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/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "grg-kit-cli",
3
- "version": "0.1.1",
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
- "chalk": "^4.1.2",
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();