grg-kit-cli 0.1.1 ā 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -11
- package/bin/grg.js +15 -2
- package/commands/interactive.js +223 -0
- package/config/resources.js +857 -173
- package/package.json +5 -2
- package/scripts/README.md +101 -0
- package/scripts/generate-resources.js +287 -0
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grg-kit-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI tool for pulling GRG Kit resources into your Angular project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"grg": "./bin/grg.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
+
"generate": "node scripts/generate-resources.js",
|
|
11
|
+
"prepublishOnly": "npm run generate",
|
|
10
12
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
13
|
},
|
|
12
14
|
"keywords": [
|
|
@@ -25,9 +27,10 @@
|
|
|
25
27
|
"directory": "cli"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
30
|
+
"chalk": "^4.1.2",
|
|
28
31
|
"commander": "^11.1.0",
|
|
29
32
|
"degit": "^2.8.4",
|
|
30
|
-
"
|
|
33
|
+
"inquirer": "^8.2.7",
|
|
31
34
|
"ora": "^5.4.1"
|
|
32
35
|
},
|
|
33
36
|
"engines": {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# CLI Scripts
|
|
2
|
+
|
|
3
|
+
## generate-resources.js
|
|
4
|
+
|
|
5
|
+
Automatically generates `config/resources.js` by scanning the `templates/` directory.
|
|
6
|
+
|
|
7
|
+
### Purpose
|
|
8
|
+
|
|
9
|
+
Ensures the CLI always has up-to-date resource definitions based on what's actually available in the templates, preventing:
|
|
10
|
+
- Outdated resource lists
|
|
11
|
+
- Manual maintenance errors
|
|
12
|
+
- Mismatched paths
|
|
13
|
+
- Missing new resources
|
|
14
|
+
|
|
15
|
+
### Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Run manually
|
|
19
|
+
npm run generate
|
|
20
|
+
|
|
21
|
+
# Or directly
|
|
22
|
+
node scripts/generate-resources.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Auto-Generation
|
|
26
|
+
|
|
27
|
+
The script runs automatically before publishing:
|
|
28
|
+
```bash
|
|
29
|
+
npm publish # Runs prepublishOnly hook ā npm run generate
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### What It Does
|
|
33
|
+
|
|
34
|
+
1. **Scans templates directory** for:
|
|
35
|
+
- Themes (`templates/ui/themes/*.css`)
|
|
36
|
+
- Components (`templates/ui/components/*/`)
|
|
37
|
+
- Layouts (`templates/ui/layouts/*/`)
|
|
38
|
+
- Examples (`templates/spartan-examples/components/(*)`)
|
|
39
|
+
|
|
40
|
+
2. **Generates metadata** for each resource:
|
|
41
|
+
- Name, title, description
|
|
42
|
+
- Path and default output location
|
|
43
|
+
- Tags for searchability
|
|
44
|
+
- Dependencies (if applicable)
|
|
45
|
+
|
|
46
|
+
3. **Writes `config/resources.js`** with structured data
|
|
47
|
+
|
|
48
|
+
### Output
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
š Scanning templates directory...
|
|
52
|
+
ā Found 6 themes
|
|
53
|
+
ā Found 2 components
|
|
54
|
+
ā Found 3 layouts
|
|
55
|
+
ā Found 56 example components
|
|
56
|
+
|
|
57
|
+
ā
Generated /path/to/config/resources.js
|
|
58
|
+
|
|
59
|
+
š¦ Resource Summary:
|
|
60
|
+
Themes: 6
|
|
61
|
+
Components: 2
|
|
62
|
+
Layouts: 3
|
|
63
|
+
Examples: 56
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Customizing Metadata
|
|
67
|
+
|
|
68
|
+
Edit the metadata constants in `generate-resources.js`:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const THEME_METADATA = {
|
|
72
|
+
'grg-theme.css': {
|
|
73
|
+
description: 'Default theme with purple/orange accents',
|
|
74
|
+
tags: ['default', 'purple', 'orange', 'colorful']
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const COMPONENT_METADATA = {
|
|
79
|
+
'stepper': {
|
|
80
|
+
description: 'Multi-step form component',
|
|
81
|
+
tags: ['form', 'wizard'],
|
|
82
|
+
dependencies: ['@spartan-ng/helm/button']
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Benefits
|
|
88
|
+
|
|
89
|
+
ā
**Always accurate** - Resources match what's in templates
|
|
90
|
+
ā
**No manual updates** - Add files to templates, run script
|
|
91
|
+
ā
**Type-safe** - Consistent structure for all resources
|
|
92
|
+
ā
**MCP-ready** - Structured metadata for LLM consumption
|
|
93
|
+
ā
**Auto-discovery** - New resources automatically included
|
|
94
|
+
|
|
95
|
+
### Development Workflow
|
|
96
|
+
|
|
97
|
+
1. Add new resource to `templates/` directory
|
|
98
|
+
2. (Optional) Add metadata to script constants
|
|
99
|
+
3. Run `npm run generate`
|
|
100
|
+
4. Test with `grg list` or `grg add`
|
|
101
|
+
5. Publish with `npm publish` (auto-generates)
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate resources.js from actual template files
|
|
5
|
+
* This ensures CLI always has up-to-date resource definitions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const TEMPLATES_DIR = path.join(__dirname, '../../templates');
|
|
12
|
+
const OUTPUT_FILE = path.join(__dirname, '../config/resources.js');
|
|
13
|
+
|
|
14
|
+
// Theme metadata (can be enhanced by reading CSS files)
|
|
15
|
+
const THEME_METADATA = {
|
|
16
|
+
'grg-theme.css': {
|
|
17
|
+
description: 'Default theme with purple/orange accents',
|
|
18
|
+
tags: ['default', 'purple', 'orange', 'colorful']
|
|
19
|
+
},
|
|
20
|
+
'claude.css': {
|
|
21
|
+
description: 'Claude-inspired warm tones',
|
|
22
|
+
tags: ['warm', 'orange', 'brown', 'claude']
|
|
23
|
+
},
|
|
24
|
+
'clean-slate.css': {
|
|
25
|
+
description: 'Minimal grayscale palette',
|
|
26
|
+
tags: ['minimal', 'grayscale', 'neutral', 'clean']
|
|
27
|
+
},
|
|
28
|
+
'modern-minimal.css': {
|
|
29
|
+
description: 'Contemporary minimal design',
|
|
30
|
+
tags: ['minimal', 'modern', 'contemporary', 'clean']
|
|
31
|
+
},
|
|
32
|
+
'amber-minimal.css': {
|
|
33
|
+
description: 'Warm amber accents',
|
|
34
|
+
tags: ['minimal', 'warm', 'amber', 'orange']
|
|
35
|
+
},
|
|
36
|
+
'mocks.css': {
|
|
37
|
+
description: 'Theme for mockups and prototypes',
|
|
38
|
+
tags: ['mockup', 'prototype', 'design']
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Component metadata
|
|
43
|
+
const COMPONENT_METADATA = {
|
|
44
|
+
'stepper': {
|
|
45
|
+
description: 'Multi-step form component with progress indicator',
|
|
46
|
+
tags: ['form', 'wizard', 'multi-step', 'progress'],
|
|
47
|
+
dependencies: ['@spartan-ng/helm/button', '@spartan-ng/helm/card'],
|
|
48
|
+
type: 'grg-component',
|
|
49
|
+
prefix: 'grg'
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Layout metadata
|
|
54
|
+
const LAYOUT_METADATA = {
|
|
55
|
+
'dashboard': {
|
|
56
|
+
description: 'Full dashboard layout with sidebar and header',
|
|
57
|
+
tags: ['dashboard', 'admin', 'sidebar', 'navigation'],
|
|
58
|
+
dependencies: ['@spartan-ng/helm/button', '@spartan-ng/helm/card', '@spartan-ng/helm/navigation-menu']
|
|
59
|
+
},
|
|
60
|
+
'auth': {
|
|
61
|
+
description: 'Authentication pages layout (login, signup, forgot password)',
|
|
62
|
+
tags: ['auth', 'login', 'signup', 'authentication'],
|
|
63
|
+
dependencies: ['@spartan-ng/helm/button', '@spartan-ng/helm/card', '@spartan-ng/helm/form-field']
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Example component descriptions
|
|
68
|
+
const EXAMPLE_DESCRIPTIONS = {
|
|
69
|
+
'accordion': 'Collapsible content sections examples',
|
|
70
|
+
'alert': 'Status messages and notifications examples',
|
|
71
|
+
'alert-dialog': 'Confirmation and alert dialogs examples',
|
|
72
|
+
'aspect-ratio': 'Responsive containers with fixed aspect ratios examples',
|
|
73
|
+
'autocomplete': 'Search-enabled input controls examples',
|
|
74
|
+
'avatar': 'User profile images with fallbacks examples',
|
|
75
|
+
'badge': 'Status indicators and tags examples',
|
|
76
|
+
'breadcrumb': 'Hierarchical navigation indicators examples',
|
|
77
|
+
'button': 'Interactive buttons with multiple variants examples',
|
|
78
|
+
'button-group': 'Grouped button controls examples',
|
|
79
|
+
'calendar': 'Date selection interfaces examples',
|
|
80
|
+
'card': 'Content containers with header, content, and footer examples',
|
|
81
|
+
'carousel': 'Image and content carousels examples',
|
|
82
|
+
'checkbox': 'Boolean input controls examples',
|
|
83
|
+
'collapsible': 'Expandable/collapsible content examples',
|
|
84
|
+
'combobox': 'Searchable select controls examples',
|
|
85
|
+
'command': 'Command palette and search interfaces examples',
|
|
86
|
+
'context-menu': 'Right-click context menus examples',
|
|
87
|
+
'data-table': 'Advanced data tables with sorting and filtering examples',
|
|
88
|
+
'date-picker': 'Date input controls examples',
|
|
89
|
+
'dialog': 'Modal dialogs and popups examples',
|
|
90
|
+
'dropdown-menu': 'Dropdown menu controls examples',
|
|
91
|
+
'empty': 'Empty state components examples',
|
|
92
|
+
'field': 'Form field components examples',
|
|
93
|
+
'form-field': 'Complete form fields with validation examples',
|
|
94
|
+
'hover-card': 'Content previews on hover examples',
|
|
95
|
+
'icon': 'Icon components examples',
|
|
96
|
+
'input': 'Form input fields examples',
|
|
97
|
+
'input-group': 'Grouped input controls examples',
|
|
98
|
+
'input-otp': 'One-time password inputs examples',
|
|
99
|
+
'item': 'List item components examples',
|
|
100
|
+
'kbd': 'Keyboard shortcut displays examples',
|
|
101
|
+
'label': 'Form labels examples',
|
|
102
|
+
'menubar': 'Application menu bars examples',
|
|
103
|
+
'navigation-menu': 'Primary navigation menus examples',
|
|
104
|
+
'pagination': 'Data pagination controls examples',
|
|
105
|
+
'popover': 'Contextual content overlays examples',
|
|
106
|
+
'progress': 'Progress indicators examples',
|
|
107
|
+
'radio-group': 'Single-choice selection controls examples',
|
|
108
|
+
'resizable': 'Resizable panels examples',
|
|
109
|
+
'scroll-area': 'Custom scrollable containers examples',
|
|
110
|
+
'select': 'Dropdown selection controls examples',
|
|
111
|
+
'separator': 'Visual dividers examples',
|
|
112
|
+
'sheet': 'Slide-out panels examples',
|
|
113
|
+
'sidebar': 'Application sidebars examples',
|
|
114
|
+
'skeleton': 'Loading state placeholders examples',
|
|
115
|
+
'slider': 'Range input controls examples',
|
|
116
|
+
'sonner': 'Toast notifications examples',
|
|
117
|
+
'spinner': 'Loading spinners examples',
|
|
118
|
+
'switch': 'Toggle switches examples',
|
|
119
|
+
'table': 'Data tables examples',
|
|
120
|
+
'tabs': 'Tabbed interfaces examples',
|
|
121
|
+
'textarea': 'Multi-line text inputs examples',
|
|
122
|
+
'toast': 'Toast notifications examples',
|
|
123
|
+
'toggle': 'Toggle buttons examples',
|
|
124
|
+
'toggle-group': 'Grouped toggle controls examples',
|
|
125
|
+
'tooltip': 'Contextual tooltips examples'
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
function scanDirectory(dir) {
|
|
129
|
+
try {
|
|
130
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.warn(`Warning: Could not read directory ${dir}`);
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function generateThemes() {
|
|
138
|
+
const themesDir = path.join(TEMPLATES_DIR, 'ui/themes');
|
|
139
|
+
const files = scanDirectory(themesDir);
|
|
140
|
+
|
|
141
|
+
return files
|
|
142
|
+
.filter(file => file.isFile() && file.name.endsWith('.css'))
|
|
143
|
+
.map(file => {
|
|
144
|
+
const name = file.name.replace('.css', '');
|
|
145
|
+
const metadata = THEME_METADATA[file.name] || {
|
|
146
|
+
description: `${name} theme`,
|
|
147
|
+
tags: []
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
name,
|
|
152
|
+
title: name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
|
|
153
|
+
description: metadata.description,
|
|
154
|
+
file: file.name,
|
|
155
|
+
path: `templates/ui/themes/${file.name}`,
|
|
156
|
+
defaultOutput: `src/themes/${file.name}`,
|
|
157
|
+
tags: metadata.tags,
|
|
158
|
+
features: ['dark-mode', 'tailwind-v4', 'spartan-ng', 'oklch']
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function generateComponents() {
|
|
164
|
+
const componentsDir = path.join(TEMPLATES_DIR, 'ui/components');
|
|
165
|
+
const dirs = scanDirectory(componentsDir);
|
|
166
|
+
|
|
167
|
+
return dirs
|
|
168
|
+
.filter(dir => dir.isDirectory())
|
|
169
|
+
.map(dir => {
|
|
170
|
+
const metadata = COMPONENT_METADATA[dir.name] || {
|
|
171
|
+
description: `${dir.name} component`,
|
|
172
|
+
tags: [],
|
|
173
|
+
dependencies: []
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
name: dir.name,
|
|
178
|
+
title: dir.name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') + ' Component',
|
|
179
|
+
description: metadata.description,
|
|
180
|
+
path: `templates/ui/components/${dir.name}`,
|
|
181
|
+
defaultOutput: `src/app/components/${dir.name}`,
|
|
182
|
+
tags: metadata.tags,
|
|
183
|
+
dependencies: metadata.dependencies,
|
|
184
|
+
...(metadata.type && { type: metadata.type }),
|
|
185
|
+
...(metadata.prefix && { prefix: metadata.prefix })
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function generateLayouts() {
|
|
191
|
+
const layoutsDir = path.join(TEMPLATES_DIR, 'ui/layouts');
|
|
192
|
+
const dirs = scanDirectory(layoutsDir);
|
|
193
|
+
|
|
194
|
+
return dirs
|
|
195
|
+
.filter(dir => dir.isDirectory())
|
|
196
|
+
.map(dir => {
|
|
197
|
+
const metadata = LAYOUT_METADATA[dir.name] || {
|
|
198
|
+
description: `${dir.name} layout`,
|
|
199
|
+
tags: [],
|
|
200
|
+
dependencies: []
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
name: dir.name,
|
|
205
|
+
title: dir.name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') + ' Layout',
|
|
206
|
+
description: metadata.description,
|
|
207
|
+
path: `templates/ui/layouts/${dir.name}`,
|
|
208
|
+
defaultOutput: `src/app/layouts/${dir.name}`,
|
|
209
|
+
tags: metadata.tags,
|
|
210
|
+
dependencies: metadata.dependencies
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function generateExamples() {
|
|
216
|
+
const examplesDir = path.join(TEMPLATES_DIR, 'spartan-examples/components');
|
|
217
|
+
const dirs = scanDirectory(examplesDir);
|
|
218
|
+
|
|
219
|
+
const components = dirs
|
|
220
|
+
.filter(dir => dir.isDirectory() && dir.name.startsWith('('))
|
|
221
|
+
.map(dir => {
|
|
222
|
+
const name = dir.name.replace(/[()]/g, '');
|
|
223
|
+
const description = EXAMPLE_DESCRIPTIONS[name] || `${name} examples`;
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
name,
|
|
227
|
+
title: name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') + ' Examples',
|
|
228
|
+
description,
|
|
229
|
+
path: `templates/spartan-examples/components/${dir.name}`,
|
|
230
|
+
defaultOutput: `src/app/examples/${name}`,
|
|
231
|
+
tags: [name, 'example', 'spartan-ng']
|
|
232
|
+
};
|
|
233
|
+
})
|
|
234
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
all: {
|
|
238
|
+
name: 'all',
|
|
239
|
+
title: 'All Spartan-NG Examples',
|
|
240
|
+
description: `Complete collection of ${components.length}+ Spartan-NG component examples with usage patterns and variants`,
|
|
241
|
+
path: 'templates/spartan-examples',
|
|
242
|
+
defaultOutput: 'src/app/spartan-examples',
|
|
243
|
+
tags: ['examples', 'spartan-ng', 'all', 'reference'],
|
|
244
|
+
count: `${components.length}+`,
|
|
245
|
+
purpose: 'Learning and reference for developers and LLMs'
|
|
246
|
+
},
|
|
247
|
+
components
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function generateResourcesFile() {
|
|
252
|
+
console.log('š Scanning templates directory...');
|
|
253
|
+
|
|
254
|
+
const themes = generateThemes();
|
|
255
|
+
const components = generateComponents();
|
|
256
|
+
const layouts = generateLayouts();
|
|
257
|
+
const examples = generateExamples();
|
|
258
|
+
|
|
259
|
+
console.log(`ā Found ${themes.length} themes`);
|
|
260
|
+
console.log(`ā Found ${components.length} components`);
|
|
261
|
+
console.log(`ā Found ${layouts.length} layouts`);
|
|
262
|
+
console.log(`ā Found ${examples.components.length} example components`);
|
|
263
|
+
|
|
264
|
+
const output = `/**
|
|
265
|
+
* Resource definitions for GRG Kit
|
|
266
|
+
* This file is auto-generated from templates directory
|
|
267
|
+
* Run: node scripts/generate-resources.js to update
|
|
268
|
+
*/
|
|
269
|
+
|
|
270
|
+
const RESOURCES = ${JSON.stringify({ themes, components, layouts, examples }, null, 2)};
|
|
271
|
+
|
|
272
|
+
const REPO = 'Genesis-Research/grg-kit';
|
|
273
|
+
|
|
274
|
+
module.exports = { RESOURCES, REPO };
|
|
275
|
+
`;
|
|
276
|
+
|
|
277
|
+
fs.writeFileSync(OUTPUT_FILE, output);
|
|
278
|
+
console.log(`\nā
Generated ${OUTPUT_FILE}`);
|
|
279
|
+
console.log('\nš¦ Resource Summary:');
|
|
280
|
+
console.log(` Themes: ${themes.length}`);
|
|
281
|
+
console.log(` Components: ${components.length}`);
|
|
282
|
+
console.log(` Layouts: ${layouts.length}`);
|
|
283
|
+
console.log(` Examples: ${examples.components.length}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Run the generator
|
|
287
|
+
generateResourcesFile();
|