grg-kit-cli 0.6.10 ā 0.6.12
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 +69 -52
- package/bin/grg.js +10 -0
- package/commands/add.js +155 -6
- package/commands/init.js +39 -8
- package/commands/list.js +29 -11
- package/commands/llm-setup.js +24 -453
- package/config/resources.js +74 -13
- package/package.json +1 -1
- package/scripts/generate-resources.js +10 -0
- package/config/catalog-fetcher.js +0 -199
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@ grg init
|
|
|
21
21
|
# Or with a specific theme
|
|
22
22
|
grg init --theme claude
|
|
23
23
|
|
|
24
|
+
# Add or switch theme
|
|
25
|
+
grg add theme claude
|
|
26
|
+
grg add theme modern-minimal
|
|
27
|
+
|
|
24
28
|
# Add blocks (all files)
|
|
25
29
|
grg add block auth
|
|
26
30
|
grg add block shell
|
|
@@ -32,10 +36,14 @@ grg add block shell sidebar
|
|
|
32
36
|
# Add all blocks
|
|
33
37
|
grg add block --all
|
|
34
38
|
|
|
39
|
+
# Add components
|
|
40
|
+
grg add component file-upload
|
|
41
|
+
|
|
35
42
|
# List available resources
|
|
36
43
|
grg list
|
|
37
44
|
grg list blocks
|
|
38
45
|
grg list themes
|
|
46
|
+
grg list components
|
|
39
47
|
```
|
|
40
48
|
|
|
41
49
|
## Commands
|
|
@@ -70,12 +78,34 @@ Examples:
|
|
|
70
78
|
- Updates `src/styles.css` with theme import
|
|
71
79
|
|
|
72
80
|
**Available themes:**
|
|
73
|
-
- `grg-theme` - Default theme with
|
|
81
|
+
- `grg-theme` - Default theme with blue accents
|
|
74
82
|
- `claude` - Claude-inspired warm tones
|
|
75
83
|
- `clean-slate` - Minimal grayscale palette
|
|
76
84
|
- `modern-minimal` - Contemporary minimal design
|
|
77
85
|
- `amber-minimal` - Warm amber accents
|
|
78
|
-
- `
|
|
86
|
+
- `chroma-clinic` - Professional blue theme for healthcare
|
|
87
|
+
- `bio-lab` - Fresh green theme for life sciences
|
|
88
|
+
- `pharma-teal` - Calming teal for pharmaceutical apps
|
|
89
|
+
- `helix-purple` - DNA-inspired purple for genomics
|
|
90
|
+
|
|
91
|
+
### `grg add theme`
|
|
92
|
+
|
|
93
|
+
Add or switch theme in an existing project.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
grg add theme <themeName>
|
|
97
|
+
|
|
98
|
+
Options:
|
|
99
|
+
-o, --output <path> Custom themes directory (default: "src/themes")
|
|
100
|
+
|
|
101
|
+
Examples:
|
|
102
|
+
grg add theme claude # Download and set claude theme
|
|
103
|
+
grg add theme modern-minimal # Download and set modern-minimal
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**What it does:**
|
|
107
|
+
- Downloads the theme CSS file to `src/themes/`
|
|
108
|
+
- Updates `src/styles.css` to import the new theme (replaces existing theme import)
|
|
79
109
|
|
|
80
110
|
### `grg add block`
|
|
81
111
|
|
|
@@ -97,6 +127,22 @@ Examples:
|
|
|
97
127
|
grg add block --all # All blocks
|
|
98
128
|
```
|
|
99
129
|
|
|
130
|
+
### `grg add component`
|
|
131
|
+
|
|
132
|
+
Add GRG Kit components to your project.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
grg add component <componentName>
|
|
136
|
+
|
|
137
|
+
Options:
|
|
138
|
+
--all Add all components
|
|
139
|
+
-o, --output <path> Custom output directory
|
|
140
|
+
|
|
141
|
+
Examples:
|
|
142
|
+
grg add component file-upload # Download file-upload component
|
|
143
|
+
grg add component --all # All components
|
|
144
|
+
```
|
|
145
|
+
|
|
100
146
|
**Available blocks and files:**
|
|
101
147
|
|
|
102
148
|
| Block | Files |
|
|
@@ -110,17 +156,23 @@ Examples:
|
|
|
110
156
|
List available blocks and themes.
|
|
111
157
|
|
|
112
158
|
```bash
|
|
113
|
-
grg list [category]
|
|
159
|
+
grg list [category] [options]
|
|
160
|
+
|
|
161
|
+
Options:
|
|
162
|
+
--json Output as JSON (for MCP server integration)
|
|
114
163
|
|
|
115
164
|
Examples:
|
|
116
165
|
grg list # Show overview
|
|
117
166
|
grg list blocks # List all blocks
|
|
118
167
|
grg list themes # List all themes
|
|
168
|
+
grg list --json # Output all resources as JSON
|
|
119
169
|
```
|
|
120
170
|
|
|
171
|
+
The `--json` flag outputs structured data used by the MCP server to get resource information.
|
|
172
|
+
|
|
121
173
|
### `grg llm-setup`
|
|
122
174
|
|
|
123
|
-
Generate
|
|
175
|
+
Generate design system rules for AI assistants (Windsurf, Cursor, Claude Code).
|
|
124
176
|
|
|
125
177
|
```bash
|
|
126
178
|
grg llm-setup [options]
|
|
@@ -129,60 +181,17 @@ Options:
|
|
|
129
181
|
-o, --output <path> Output directory for rules (default: ".windsurf/rules")
|
|
130
182
|
|
|
131
183
|
Examples:
|
|
132
|
-
grg llm-setup # Windsurf (
|
|
184
|
+
grg llm-setup # Windsurf/Cursor (design-system.md)
|
|
133
185
|
grg llm-setup --output .claude # Claude Code (single CLAUDE.md)
|
|
134
186
|
```
|
|
135
187
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
For AI assistants to automatically discover and use GRG Kit resources:
|
|
139
|
-
|
|
140
|
-
### 1. Install the MCP Server
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
npm install -g grg-kit-mcp-server
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### 2. Configure Your AI Assistant
|
|
147
|
-
|
|
148
|
-
**Windsurf** (`~/.codeium/windsurf/mcp_config.json`):
|
|
149
|
-
|
|
150
|
-
```json
|
|
151
|
-
{
|
|
152
|
-
"mcpServers": {
|
|
153
|
-
"grg-kit": {
|
|
154
|
-
"command": "grg-mcp-server"
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Claude Code** (`~/.claude/settings.json`):
|
|
161
|
-
|
|
162
|
-
```json
|
|
163
|
-
{
|
|
164
|
-
"mcpServers": {
|
|
165
|
-
"grg-kit": {
|
|
166
|
-
"command": "grg-mcp-server"
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 3. Generate AI Rules
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
cd your-angular-project
|
|
176
|
-
grg llm-setup
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### 4. Restart Your IDE
|
|
188
|
+
**What this creates:**
|
|
189
|
+
- `design-system.md` - Component usage patterns, styling rules, import patterns
|
|
180
190
|
|
|
181
191
|
**What this enables:**
|
|
182
|
-
- ā
AI automatically searches GRG Kit before writing custom code
|
|
183
|
-
- ā
AI knows about themes, components, blocks, and examples
|
|
184
192
|
- ā
AI follows GRG Kit design system patterns
|
|
185
|
-
- ā
AI
|
|
193
|
+
- ā
AI uses Spartan-NG components correctly
|
|
194
|
+
- ā
AI uses semantic colors instead of raw Tailwind colors
|
|
186
195
|
|
|
187
196
|
## Quick Reference
|
|
188
197
|
|
|
@@ -195,6 +204,10 @@ cd my-app
|
|
|
195
204
|
grg init # Default theme
|
|
196
205
|
grg init --theme claude # Custom theme
|
|
197
206
|
|
|
207
|
+
# Add/switch theme
|
|
208
|
+
grg add theme claude # Switch to claude theme
|
|
209
|
+
grg add theme modern-minimal # Switch to modern-minimal
|
|
210
|
+
|
|
198
211
|
# Add blocks (all files)
|
|
199
212
|
grg add block auth # All auth files
|
|
200
213
|
grg add block shell # All shell layouts
|
|
@@ -205,10 +218,14 @@ grg add block auth login # Just login
|
|
|
205
218
|
grg add block shell sidebar # Just sidebar shell
|
|
206
219
|
grg add block --all # All blocks
|
|
207
220
|
|
|
221
|
+
# Add components
|
|
222
|
+
grg add component file-upload # File upload component
|
|
223
|
+
|
|
208
224
|
# List resources
|
|
209
225
|
grg list # Overview
|
|
210
226
|
grg list blocks # Available blocks
|
|
211
227
|
grg list themes # Available themes
|
|
228
|
+
grg list components # Available components
|
|
212
229
|
|
|
213
230
|
# AI setup
|
|
214
231
|
grg llm-setup # Generate AI rules
|
package/bin/grg.js
CHANGED
|
@@ -41,10 +41,20 @@ addCommand
|
|
|
41
41
|
await addComponent(componentName, options);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
addCommand
|
|
45
|
+
.command('theme [themeName]')
|
|
46
|
+
.description('Add or switch theme (e.g., grg add theme claude)')
|
|
47
|
+
.option('-o, --output <path>', 'Custom themes directory', 'src/themes')
|
|
48
|
+
.action(async (themeName, options) => {
|
|
49
|
+
const { addTheme } = require('../commands/add');
|
|
50
|
+
await addTheme(themeName, options);
|
|
51
|
+
});
|
|
52
|
+
|
|
44
53
|
// List command
|
|
45
54
|
program
|
|
46
55
|
.command('list [category]')
|
|
47
56
|
.description('List available blocks and components')
|
|
57
|
+
.option('--json', 'Output as JSON (for MCP server integration)')
|
|
48
58
|
.action(list);
|
|
49
59
|
|
|
50
60
|
// LLM Setup command
|
package/commands/add.js
CHANGED
|
@@ -4,7 +4,7 @@ const ora = require('ora');
|
|
|
4
4
|
const fs = require('fs').promises;
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const https = require('https');
|
|
7
|
-
const {
|
|
7
|
+
const { RESOURCES, REPO } = require('../config/resources');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Add command - downloads blocks or specific block files
|
|
@@ -16,10 +16,6 @@ const { fetchCatalog, REPO } = require('../config/catalog-fetcher');
|
|
|
16
16
|
* grg add block --all # All blocks with all files
|
|
17
17
|
*/
|
|
18
18
|
async function add(blockName, fileIds, options) {
|
|
19
|
-
// Fetch catalog dynamically (with caching)
|
|
20
|
-
const spinner = ora('Fetching catalog...').start();
|
|
21
|
-
const RESOURCES = await fetchCatalog({ silent: true });
|
|
22
|
-
spinner.stop();
|
|
23
19
|
|
|
24
20
|
// Handle --all flag (download everything)
|
|
25
21
|
if (options.all) {
|
|
@@ -292,4 +288,157 @@ function showComponentUsage(RESOURCES) {
|
|
|
292
288
|
console.log(chalk.gray('\nRun'), chalk.cyan('grg list components'), chalk.gray('for more details'));
|
|
293
289
|
}
|
|
294
290
|
|
|
295
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Add theme command - downloads and sets up a theme
|
|
293
|
+
* Format: grg add theme <themeName>
|
|
294
|
+
* Examples:
|
|
295
|
+
* grg add theme claude # Download and set claude theme
|
|
296
|
+
* grg add theme modern-minimal # Download and set modern-minimal theme
|
|
297
|
+
*/
|
|
298
|
+
async function addTheme(themeName, options) {
|
|
299
|
+
// Fetch catalog dynamically (with caching)
|
|
300
|
+
const spinner = ora('Fetching catalog...').start();
|
|
301
|
+
const RESOURCES = await fetchCatalog({ silent: true });
|
|
302
|
+
spinner.stop();
|
|
303
|
+
|
|
304
|
+
// Validate theme name
|
|
305
|
+
if (!themeName) {
|
|
306
|
+
showThemeUsage(RESOURCES);
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const theme = RESOURCES.themes.find(t => t.name === themeName);
|
|
311
|
+
if (!theme) {
|
|
312
|
+
console.error(chalk.red(`\nError: Theme "${themeName}" not found`));
|
|
313
|
+
console.log(chalk.yellow('\nAvailable themes:'));
|
|
314
|
+
RESOURCES.themes.forEach(t => {
|
|
315
|
+
console.log(chalk.cyan(` ${t.name}`), chalk.gray(`- ${t.description}`));
|
|
316
|
+
});
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await downloadTheme(theme, options.output);
|
|
321
|
+
console.log(chalk.bold.green('⨠Done!'));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Download a theme file
|
|
326
|
+
*/
|
|
327
|
+
async function downloadTheme(theme, customOutput) {
|
|
328
|
+
const downloadSpinner = ora();
|
|
329
|
+
const themesDir = customOutput || 'src/themes';
|
|
330
|
+
const outputPath = path.join(themesDir, theme.file);
|
|
331
|
+
|
|
332
|
+
// Ensure themes directory exists
|
|
333
|
+
await fs.mkdir(themesDir, { recursive: true });
|
|
334
|
+
|
|
335
|
+
downloadSpinner.start(`Downloading ${theme.title} theme...`);
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
const themeUrl = `https://raw.githubusercontent.com/${REPO}/main/${theme.path}`;
|
|
339
|
+
await downloadFileToPath(themeUrl, outputPath);
|
|
340
|
+
|
|
341
|
+
downloadSpinner.succeed(chalk.green(`ā ${theme.title} theme downloaded`));
|
|
342
|
+
console.log(chalk.gray(` Location: ${outputPath}`));
|
|
343
|
+
|
|
344
|
+
} catch (error) {
|
|
345
|
+
downloadSpinner.fail(chalk.red(`Failed to download ${theme.title}`));
|
|
346
|
+
console.error(chalk.red(error.message));
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Update styles.css
|
|
351
|
+
downloadSpinner.start('Updating src/styles.css...');
|
|
352
|
+
try {
|
|
353
|
+
const stylesPath = 'src/styles.css';
|
|
354
|
+
let stylesContent = '';
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
stylesContent = await fs.readFile(stylesPath, 'utf-8');
|
|
358
|
+
} catch (error) {
|
|
359
|
+
// File doesn't exist, will create it
|
|
360
|
+
stylesContent = '';
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const themeImport = `@import './themes/${theme.file}';`;
|
|
364
|
+
|
|
365
|
+
// Check if any theme is already imported
|
|
366
|
+
const themeImportRegex = /@import\s+['"]\.\/themes\/[^'"]+['"];?\n?/g;
|
|
367
|
+
const existingThemeImports = stylesContent.match(themeImportRegex);
|
|
368
|
+
|
|
369
|
+
if (existingThemeImports && existingThemeImports.length > 0) {
|
|
370
|
+
// Remove ALL existing theme imports first
|
|
371
|
+
stylesContent = stylesContent.replace(themeImportRegex, '');
|
|
372
|
+
// Clean up any resulting double blank lines
|
|
373
|
+
stylesContent = stylesContent.replace(/\n{3,}/g, '\n\n');
|
|
374
|
+
// Add the new theme import after the spartan preset import
|
|
375
|
+
const spartanImport = '@import "@spartan-ng/brain/hlm-tailwind-preset.css";';
|
|
376
|
+
if (stylesContent.includes(spartanImport)) {
|
|
377
|
+
stylesContent = stylesContent.replace(spartanImport, `${spartanImport}\n\n${themeImport}`);
|
|
378
|
+
} else {
|
|
379
|
+
// Fallback: add at the beginning
|
|
380
|
+
stylesContent = themeImport + '\n' + stylesContent;
|
|
381
|
+
}
|
|
382
|
+
await fs.writeFile(stylesPath, stylesContent);
|
|
383
|
+
downloadSpinner.succeed(chalk.green(`ā Updated theme import in src/styles.css`));
|
|
384
|
+
} else if (!stylesContent.includes(themeImport)) {
|
|
385
|
+
// No theme import exists, add required imports
|
|
386
|
+
const requiredImports = [
|
|
387
|
+
'@import "@angular/cdk/overlay-prebuilt.css";',
|
|
388
|
+
'@import "tailwindcss";',
|
|
389
|
+
'@import "@spartan-ng/brain/hlm-tailwind-preset.css";',
|
|
390
|
+
'',
|
|
391
|
+
themeImport
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
const newContent = requiredImports.join('\n') + '\n';
|
|
395
|
+
await fs.writeFile(stylesPath, newContent);
|
|
396
|
+
downloadSpinner.succeed(chalk.green('ā Created src/styles.css with theme import'));
|
|
397
|
+
} else {
|
|
398
|
+
downloadSpinner.succeed(chalk.green('ā Theme already imported in src/styles.css'));
|
|
399
|
+
}
|
|
400
|
+
} catch (error) {
|
|
401
|
+
downloadSpinner.warn(chalk.yellow('Could not update src/styles.css automatically'));
|
|
402
|
+
console.log(chalk.gray('\nPlease add the following to your src/styles.css:'));
|
|
403
|
+
console.log(chalk.cyan(` @import './themes/${theme.file}';`));
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
console.log();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Download file to a specific path
|
|
411
|
+
*/
|
|
412
|
+
function downloadFileToPath(url, outputPath) {
|
|
413
|
+
return new Promise((resolve, reject) => {
|
|
414
|
+
https.get(url, (res) => {
|
|
415
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
416
|
+
// Follow redirect
|
|
417
|
+
https.get(res.headers.location, (res2) => {
|
|
418
|
+
handleResponse(res2, outputPath, resolve, reject);
|
|
419
|
+
}).on('error', reject);
|
|
420
|
+
} else {
|
|
421
|
+
handleResponse(res, outputPath, resolve, reject);
|
|
422
|
+
}
|
|
423
|
+
}).on('error', reject);
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Show theme usage help
|
|
429
|
+
*/
|
|
430
|
+
function showThemeUsage(RESOURCES) {
|
|
431
|
+
console.log(chalk.yellow('\nUsage: grg add theme <themeName>\n'));
|
|
432
|
+
console.log(chalk.bold('Examples:'));
|
|
433
|
+
console.log(chalk.cyan(' grg add theme claude'), chalk.gray(' # Download and set claude theme'));
|
|
434
|
+
console.log(chalk.cyan(' grg add theme modern-minimal'), chalk.gray(' # Download and set modern-minimal'));
|
|
435
|
+
|
|
436
|
+
console.log(chalk.bold('\nAvailable themes:'));
|
|
437
|
+
RESOURCES.themes.forEach(t => {
|
|
438
|
+
console.log(chalk.cyan(` ${t.name}`), chalk.gray(`- ${t.description}`));
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
console.log(chalk.gray('\nRun'), chalk.cyan('grg list themes'), chalk.gray('for more details'));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
module.exports = { add, addComponent, addTheme };
|
package/commands/init.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs').promises;
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { exec } = require('child_process');
|
|
4
4
|
const { promisify } = require('util');
|
|
5
|
+
const https = require('https');
|
|
5
6
|
const degit = require('degit');
|
|
6
7
|
const chalk = require('chalk');
|
|
7
8
|
const ora = require('ora');
|
|
@@ -9,6 +10,28 @@ const { RESOURCES, REPO } = require('../config/resources');
|
|
|
9
10
|
|
|
10
11
|
const execAsync = promisify(exec);
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Download a file from a URL
|
|
15
|
+
*/
|
|
16
|
+
function downloadFile(url) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
https.get(url, (res) => {
|
|
19
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
20
|
+
// Follow redirect
|
|
21
|
+
return downloadFile(res.headers.location).then(resolve).catch(reject);
|
|
22
|
+
}
|
|
23
|
+
if (res.statusCode !== 200) {
|
|
24
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let data = '';
|
|
29
|
+
res.on('data', chunk => data += chunk);
|
|
30
|
+
res.on('end', () => resolve(data));
|
|
31
|
+
}).on('error', reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
12
35
|
/**
|
|
13
36
|
* Init command - initializes GRG Kit in an existing Angular project
|
|
14
37
|
* Installs Tailwind CSS v4, runs spartan-ng ui, downloads theme
|
|
@@ -45,7 +68,18 @@ async function init(options) {
|
|
|
45
68
|
console.log(chalk.bold.cyan('\nš Initializing GRG Kit\n'));
|
|
46
69
|
console.log(chalk.gray(` Theme: ${theme.title}\n`));
|
|
47
70
|
|
|
48
|
-
// Step 1:
|
|
71
|
+
// Step 1: Fresh install of packages
|
|
72
|
+
spinner.start('Cleaning node_modules and reinstalling packages...');
|
|
73
|
+
try {
|
|
74
|
+
await execAsync('rm -rf node_modules && npm install');
|
|
75
|
+
spinner.succeed(chalk.green('ā Fresh package install complete'));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
spinner.fail(chalk.red('Failed to reinstall packages'));
|
|
78
|
+
console.error(chalk.gray(error.message));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Step 2: Install Tailwind CSS v4
|
|
49
83
|
spinner.start('Installing Tailwind CSS v4...');
|
|
50
84
|
try {
|
|
51
85
|
await execAsync('npm install tailwindcss @tailwindcss/postcss postcss --force');
|
|
@@ -227,15 +261,12 @@ async function init(options) {
|
|
|
227
261
|
spinner.warn(chalk.yellow('Themes directory may already exist'));
|
|
228
262
|
}
|
|
229
263
|
|
|
230
|
-
// Step 10: Download theme
|
|
264
|
+
// Step 10: Download theme file
|
|
231
265
|
spinner.start(`Downloading ${theme.title} theme...`);
|
|
232
266
|
try {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
verbose: false,
|
|
237
|
-
});
|
|
238
|
-
await emitter.clone(theme.defaultOutput);
|
|
267
|
+
const themeUrl = `https://raw.githubusercontent.com/${REPO}/main/${theme.path}`;
|
|
268
|
+
const themeContent = await downloadFile(themeUrl);
|
|
269
|
+
await fs.writeFile(theme.defaultOutput, themeContent);
|
|
239
270
|
spinner.succeed(chalk.green(`ā Downloaded ${theme.title} theme`));
|
|
240
271
|
} catch (error) {
|
|
241
272
|
spinner.fail(chalk.red('Failed to download theme'));
|
package/commands/list.js
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const
|
|
3
|
-
const {
|
|
2
|
+
const { RESOURCES } = require('../config/resources');
|
|
3
|
+
const { version } = require('../package.json');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* List command - displays available blocks, components, and themes
|
|
7
|
-
* Usage: grg list [category]
|
|
7
|
+
* Usage: grg list [category] [--json]
|
|
8
8
|
*/
|
|
9
|
-
async function list(category) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
async function list(category, options = {}) {
|
|
10
|
+
|
|
11
|
+
// JSON output for MCP server integration
|
|
12
|
+
if (options.json) {
|
|
13
|
+
const output = {
|
|
14
|
+
cli: {
|
|
15
|
+
name: 'grg',
|
|
16
|
+
version,
|
|
17
|
+
commands: {
|
|
18
|
+
init: { usage: 'grg init [--theme <name>]', themeFlag: '--theme' },
|
|
19
|
+
addBlock: { usage: 'grg add block <blockName> [fileIds...]', validBlocks: RESOURCES.blocks.map(b => b.name) },
|
|
20
|
+
addComponent: { usage: 'grg add component <componentName>', validComponents: RESOURCES.components.map(c => c.name) },
|
|
21
|
+
addTheme: { usage: 'grg add theme <themeName>' },
|
|
22
|
+
list: { usage: 'grg list [category] [--json]' }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
themes: RESOURCES.themes,
|
|
26
|
+
components: RESOURCES.components,
|
|
27
|
+
blocks: RESOURCES.blocks
|
|
28
|
+
};
|
|
29
|
+
console.log(JSON.stringify(output, null, 2));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
14
32
|
|
|
15
33
|
if (!category) {
|
|
16
34
|
// Show overview
|
|
@@ -25,7 +43,7 @@ async function list(category) {
|
|
|
25
43
|
console.log(chalk.gray(' Run: grg list components\n'));
|
|
26
44
|
|
|
27
45
|
console.log(chalk.bold('Themes') + chalk.gray(` (${RESOURCES.themes.length} available)`));
|
|
28
|
-
console.log(chalk.gray('
|
|
46
|
+
console.log(chalk.gray(' Add with: grg add theme <name>'));
|
|
29
47
|
console.log(chalk.gray(' Run: grg list themes\n'));
|
|
30
48
|
|
|
31
49
|
return;
|
|
@@ -67,11 +85,11 @@ async function list(category) {
|
|
|
67
85
|
|
|
68
86
|
case 'themes':
|
|
69
87
|
console.log(chalk.bold.cyan('\nšØ Available Themes\n'));
|
|
70
|
-
console.log(chalk.gray(' Use with: grg
|
|
88
|
+
console.log(chalk.gray(' Use with: grg add theme <name>\n'));
|
|
71
89
|
RESOURCES.themes.forEach(theme => {
|
|
72
90
|
console.log(chalk.bold(` ${theme.name}`));
|
|
73
91
|
console.log(chalk.gray(` ${theme.description}`));
|
|
74
|
-
console.log(chalk.yellow(` grg
|
|
92
|
+
console.log(chalk.yellow(` grg add theme ${theme.name}`));
|
|
75
93
|
if (theme.tags && theme.tags.length > 0) {
|
|
76
94
|
console.log(chalk.gray(` Tags: ${theme.tags.join(', ')}`));
|
|
77
95
|
}
|