@girardmedia/bootspring 2.5.0 → 2.5.2

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.
Files changed (59) hide show
  1. package/README.md +9 -403
  2. package/bin/bootspring.js +1 -96
  3. package/dist/cli/index.js +65134 -0
  4. package/dist/cli-launcher.js +92 -0
  5. package/dist/core/index.d.ts +2110 -5582
  6. package/dist/core/index.js +2 -0
  7. package/dist/core.js +21123 -5413
  8. package/dist/mcp/index.d.ts +357 -1
  9. package/dist/mcp/index.js +2 -0
  10. package/dist/mcp-server.js +51948 -1976
  11. package/package.json +27 -63
  12. package/scripts/postinstall.cjs +144 -0
  13. package/LICENSE +0 -29
  14. package/dist/cli/index.cjs +0 -20776
  15. package/generators/api-docs.js +0 -827
  16. package/generators/decisions.js +0 -655
  17. package/generators/generate.js +0 -595
  18. package/generators/health.js +0 -942
  19. package/generators/index.ts +0 -82
  20. package/generators/presets/full.js +0 -28
  21. package/generators/presets/index.js +0 -12
  22. package/generators/presets/minimal.js +0 -29
  23. package/generators/presets/standard.js +0 -28
  24. package/generators/questionnaire.js +0 -414
  25. package/generators/sections/advanced.js +0 -136
  26. package/generators/sections/ai.js +0 -106
  27. package/generators/sections/auth.js +0 -89
  28. package/generators/sections/backend.js +0 -146
  29. package/generators/sections/business.js +0 -118
  30. package/generators/sections/content.js +0 -300
  31. package/generators/sections/deployment.js +0 -139
  32. package/generators/sections/features.js +0 -122
  33. package/generators/sections/frontend.js +0 -118
  34. package/generators/sections/identity.js +0 -76
  35. package/generators/sections/index.js +0 -40
  36. package/generators/sections/instructions.js +0 -146
  37. package/generators/sections/payments.js +0 -104
  38. package/generators/sections/plugins.js +0 -142
  39. package/generators/sections/pre-build.js +0 -130
  40. package/generators/sections/security.js +0 -127
  41. package/generators/sections/technical.js +0 -171
  42. package/generators/sections/testing.js +0 -125
  43. package/generators/sections/workflow.js +0 -104
  44. package/generators/sprint.js +0 -675
  45. package/generators/templates/agents.template.js +0 -199
  46. package/generators/templates/assistant-context.template.js +0 -83
  47. package/generators/templates/build-planning.template.js +0 -708
  48. package/generators/templates/claude.template.js +0 -379
  49. package/generators/templates/content.template.js +0 -819
  50. package/generators/templates/index.js +0 -16
  51. package/generators/templates/planning.template.js +0 -515
  52. package/generators/templates/seed.template.js +0 -109
  53. package/generators/visual-doc-generator.js +0 -910
  54. package/scripts/postinstall.js +0 -197
  55. /package/{claude-commands → assets/claude-commands}/agent.md +0 -0
  56. /package/{claude-commands → assets/claude-commands}/bs.md +0 -0
  57. /package/{claude-commands → assets/claude-commands}/build.md +0 -0
  58. /package/{claude-commands → assets/claude-commands}/skill.md +0 -0
  59. /package/{claude-commands → assets/claude-commands}/todo.md +0 -0
@@ -1,595 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Bootspring Context Generator
5
- *
6
- * Generates all context files from project configuration.
7
- * Includes MVP source code analysis for enhanced context.
8
- *
9
- * @package bootspring
10
- * @module generators/generate
11
- */
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
-
16
- // Try to load yaml package, fall back to simple parser
17
- let yaml;
18
- try {
19
- yaml = require('yaml');
20
- } catch {
21
- yaml = null;
22
- }
23
-
24
- // Colors
25
- const c = {
26
- reset: '\x1b[0m',
27
- bold: '\x1b[1m',
28
- dim: '\x1b[2m',
29
- green: '\x1b[32m',
30
- blue: '\x1b[34m',
31
- yellow: '\x1b[33m',
32
- cyan: '\x1b[36m',
33
- red: '\x1b[31m'
34
- };
35
-
36
- /**
37
- * Simple YAML parser fallback
38
- * Handles basic key: value pairs and arrays
39
- */
40
- function parseYamlSimple(content) {
41
- const result = {};
42
- const lines = content.split('\n');
43
- let currentKey = null;
44
-
45
- for (const line of lines) {
46
- // Skip comments and empty lines
47
- if (line.trim().startsWith('#') || !line.trim()) continue;
48
-
49
- const trimmed = line.trim();
50
-
51
- // Array item
52
- if (trimmed.startsWith('- ')) {
53
- const value = trimmed.substring(2).trim();
54
- if (currentKey && Array.isArray(result[currentKey])) {
55
- result[currentKey].push(value);
56
- }
57
- continue;
58
- }
59
-
60
- // Key: value pair
61
- const colonIndex = trimmed.indexOf(':');
62
- if (colonIndex > 0) {
63
- const key = trimmed.substring(0, colonIndex).trim();
64
- const value = trimmed.substring(colonIndex + 1).trim();
65
-
66
- if (value === '' || value === '|' || value === '>') {
67
- // Start of object or multiline
68
- result[key] = [];
69
- currentKey = key;
70
- } else {
71
- // Simple value
72
- let parsedValue = value;
73
- if (value === 'true') parsedValue = true;
74
- else if (value === 'false') parsedValue = false;
75
- else if (!isNaN(value) && value !== '') parsedValue = Number(value);
76
- else if (value.startsWith('"') && value.endsWith('"')) {
77
- parsedValue = value.slice(1, -1);
78
- }
79
- result[key] = parsedValue;
80
- currentKey = null;
81
- }
82
- }
83
- }
84
-
85
- return result;
86
- }
87
-
88
- /**
89
- * Analyze MVP source files
90
- * @param {string} mvpPath - Path to MVP source directory
91
- * @returns {object} MVP analysis results
92
- */
93
- function analyzeMvpSource(mvpPath) {
94
- if (!fs.existsSync(mvpPath)) {
95
- return null;
96
- }
97
-
98
- const mvpInfo = {
99
- exists: true,
100
- files: [],
101
- components: [],
102
- services: [],
103
- utilities: [],
104
- hooks: [],
105
- pages: [],
106
- patterns: [],
107
- stats: {
108
- totalFiles: 0,
109
- totalLines: 0,
110
- fileTypes: {}
111
- }
112
- };
113
-
114
- /**
115
- * Recursively scan directory
116
- */
117
- function scanDir(dir, files = []) {
118
- if (!fs.existsSync(dir)) return files;
119
-
120
- const items = fs.readdirSync(dir, { withFileTypes: true });
121
-
122
- for (const item of items) {
123
- const fullPath = path.join(dir, item.name);
124
- const relativePath = path.relative(mvpPath, fullPath);
125
-
126
- // Skip common ignore patterns
127
- if (['node_modules', '.next', 'dist', '.git', 'coverage', '.turbo'].some(p =>
128
- relativePath.includes(p)
129
- )) continue;
130
-
131
- if (item.isDirectory()) {
132
- scanDir(fullPath, files);
133
- } else {
134
- const ext = path.extname(item.name);
135
- if (['.ts', '.tsx', '.js', '.jsx', '.mjs'].includes(ext)) {
136
- files.push({
137
- name: item.name,
138
- path: relativePath,
139
- fullPath,
140
- ext
141
- });
142
- }
143
- }
144
- }
145
- return files;
146
- }
147
-
148
- mvpInfo.files = scanDir(mvpPath);
149
- mvpInfo.stats.totalFiles = mvpInfo.files.length;
150
-
151
- // Analyze each file
152
- for (const file of mvpInfo.files) {
153
- try {
154
- const content = fs.readFileSync(file.fullPath, 'utf8');
155
- const lines = content.split('\n').length;
156
- mvpInfo.stats.totalLines += lines;
157
-
158
- // Track file types
159
- mvpInfo.stats.fileTypes[file.ext] = (mvpInfo.stats.fileTypes[file.ext] || 0) + 1;
160
-
161
- // Categorize by path and content
162
- const pathLower = file.path.toLowerCase();
163
- const contentLower = content.toLowerCase();
164
-
165
- // Components
166
- if (pathLower.includes('component') ||
167
- (file.ext === '.tsx' && content.match(/^(export\s+)?(default\s+)?function\s+[A-Z]/m))) {
168
- mvpInfo.components.push(file.path);
169
- }
170
-
171
- // Services / API
172
- if (pathLower.includes('service') || pathLower.includes('api/')) {
173
- mvpInfo.services.push(file.path);
174
- }
175
-
176
- // Utilities / Lib
177
- if (pathLower.includes('util') || pathLower.includes('lib/') || pathLower.includes('helper')) {
178
- mvpInfo.utilities.push(file.path);
179
- }
180
-
181
- // Hooks
182
- if (pathLower.includes('hook') || content.match(/^export\s+(const|function)\s+use[A-Z]/m)) {
183
- mvpInfo.hooks.push(file.path);
184
- }
185
-
186
- // Pages / App routes
187
- if (pathLower.includes('/app/') || pathLower.includes('/pages/')) {
188
- mvpInfo.pages.push(file.path);
189
- }
190
-
191
- // Detect patterns used
192
- if (content.includes('async ') && content.includes('try') && content.includes('catch')) {
193
- if (!mvpInfo.patterns.includes('error-handling')) {
194
- mvpInfo.patterns.push('error-handling');
195
- }
196
- }
197
- if (content.includes('useState') || content.includes('useEffect')) {
198
- if (!mvpInfo.patterns.includes('react-hooks')) {
199
- mvpInfo.patterns.push('react-hooks');
200
- }
201
- }
202
- if (content.includes('fetch(') || content.includes('axios')) {
203
- if (!mvpInfo.patterns.includes('api-calls')) {
204
- mvpInfo.patterns.push('api-calls');
205
- }
206
- }
207
- if (contentLower.includes('prisma')) {
208
- if (!mvpInfo.patterns.includes('prisma-orm')) {
209
- mvpInfo.patterns.push('prisma-orm');
210
- }
211
- }
212
- if (content.includes('zod') || content.includes('.parse(')) {
213
- if (!mvpInfo.patterns.includes('validation')) {
214
- mvpInfo.patterns.push('validation');
215
- }
216
- }
217
- if (contentLower.includes('clerk') || contentLower.includes('auth(')) {
218
- if (!mvpInfo.patterns.includes('authentication')) {
219
- mvpInfo.patterns.push('authentication');
220
- }
221
- }
222
- if (content.includes('stripe')) {
223
- if (!mvpInfo.patterns.includes('payments')) {
224
- mvpInfo.patterns.push('payments');
225
- }
226
- }
227
- if (content.includes('Server') && (content.includes("'use server'") || content.includes('"use server"'))) {
228
- if (!mvpInfo.patterns.includes('server-actions')) {
229
- mvpInfo.patterns.push('server-actions');
230
- }
231
- }
232
-
233
- } catch {
234
- // Skip files that can't be read
235
- }
236
- }
237
-
238
- return mvpInfo;
239
- }
240
-
241
- /**
242
- * Parse bootspring.config.js or SEED.md
243
- * @param {string} projectRoot - Project root directory
244
- * @returns {object} Parsed configuration
245
- */
246
- function parseConfig(projectRoot) {
247
- // Try bootspring.config.js first
248
- const configPath = path.join(projectRoot, 'bootspring.config.js');
249
- if (fs.existsSync(configPath)) {
250
- try {
251
- delete require.cache[require.resolve(configPath)];
252
- return require(configPath);
253
- } catch {
254
- console.warn(`${c.yellow}Warning: Could not load bootspring.config.js${c.reset}`);
255
- }
256
- }
257
-
258
- // Try SEED.md (for backward compatibility)
259
- const seedPath = path.join(projectRoot, '.bootspring', 'SEED.md');
260
- if (fs.existsSync(seedPath)) {
261
- return parseSeedMd(seedPath);
262
- }
263
-
264
- // Try .girardai/SEED.md
265
- const girardaiSeedPath = path.join(projectRoot, '.girardai', 'SEED.md');
266
- if (fs.existsSync(girardaiSeedPath)) {
267
- return parseSeedMd(girardaiSeedPath);
268
- }
269
-
270
- // Return default config
271
- return {
272
- project: { name: 'My Project', description: '' },
273
- stack: { framework: 'nextjs', language: 'typescript' },
274
- plugins: {}
275
- };
276
- }
277
-
278
- /**
279
- * Parse SEED.md and extract YAML blocks
280
- * @param {string} seedPath - Path to SEED.md
281
- * @returns {object} Parsed configuration
282
- */
283
- function parseSeedMd(seedPath) {
284
- const content = fs.readFileSync(seedPath, 'utf8');
285
- const config = {};
286
-
287
- // Extract all YAML code blocks
288
- const yamlBlockRegex = /```yaml\n([\s\S]*?)```/g;
289
- let match;
290
-
291
- while ((match = yamlBlockRegex.exec(content)) !== null) {
292
- try {
293
- const parsed = yaml ? yaml.parse(match[1]) : parseYamlSimple(match[1]);
294
- Object.assign(config, parsed);
295
- } catch {
296
- // Skip invalid YAML blocks
297
- }
298
- }
299
-
300
- return config;
301
- }
302
-
303
- /**
304
- * Generate MVP section for CLAUDE.md
305
- * @param {object} mvpInfo - MVP analysis results
306
- * @returns {string} Markdown section
307
- */
308
- function generateMvpSection(mvpInfo) {
309
- if (!mvpInfo || mvpInfo.files.length === 0) {
310
- return '';
311
- }
312
-
313
- return `
314
- ---
315
-
316
- ## MVP Reference Code
317
-
318
- **IMPORTANT**: This project has MVP prototype code. Before implementing features, check the MVP for existing patterns.
319
-
320
- ### MVP Statistics
321
-
322
- | Metric | Count |
323
- |--------|-------|
324
- | Total Files | ${mvpInfo.stats.totalFiles} |
325
- | Total Lines | ${mvpInfo.stats.totalLines.toLocaleString()} |
326
- | Components | ${mvpInfo.components.length} |
327
- | Services/API | ${mvpInfo.services.length} |
328
- | Utilities | ${mvpInfo.utilities.length} |
329
- | Hooks | ${mvpInfo.hooks.length} |
330
- | Pages | ${mvpInfo.pages.length} |
331
-
332
- ### Detected Patterns
333
-
334
- ${mvpInfo.patterns.length > 0 ? mvpInfo.patterns.map(p => `- ${p}`).join('\n') : '- No specific patterns detected'}
335
-
336
- ### Key Files
337
-
338
- **Components** (${Math.min(mvpInfo.components.length, 10)} of ${mvpInfo.components.length}):
339
- ${mvpInfo.components.slice(0, 10).map(c => `- \`${c}\``).join('\n') || '- None detected'}
340
- ${mvpInfo.components.length > 10 ? `- ... and ${mvpInfo.components.length - 10} more` : ''}
341
-
342
- **Services** (${Math.min(mvpInfo.services.length, 5)} of ${mvpInfo.services.length}):
343
- ${mvpInfo.services.slice(0, 5).map(s => `- \`${s}\``).join('\n') || '- None detected'}
344
- ${mvpInfo.services.length > 5 ? `- ... and ${mvpInfo.services.length - 5} more` : ''}
345
-
346
- ### Before Implementing Features
347
-
348
- 1. **Check MVP first**: Look for existing implementations
349
- 2. **Reuse patterns**: Follow the detected patterns above
350
- 3. **Ask about MVP**: "Show me the MVP implementation of X"
351
- `;
352
- }
353
-
354
- /**
355
- * Generate full CLAUDE.md content
356
- * @param {object} config - Project configuration
357
- * @param {object} options - Generation options
358
- * @returns {string} Generated content
359
- */
360
- function generateClaudeMd(config, options = {}) {
361
- const date = new Date().toISOString().split('T')[0];
362
-
363
- const project = config.project || {};
364
- const stack = config.stack || {};
365
- const plugins = config.plugins || {};
366
-
367
- // Analyze MVP if exists
368
- let mvpInfo = null;
369
- if (options.withMvp || options.mvpPath) {
370
- const mvpPath = options.mvpPath || path.join(options.projectRoot, 'mvp', 'source');
371
- mvpInfo = analyzeMvpSource(mvpPath);
372
- }
373
-
374
- // Build enabled plugins section
375
- const enabledPlugins = Object.entries(plugins)
376
- .filter(([_name, p]) => p && p.enabled !== false);
377
-
378
- const pluginsSection = enabledPlugins.length > 0
379
- ? enabledPlugins.map(([name, plugin]) => `### ${name.charAt(0).toUpperCase() + name.slice(1)}
380
- - **Provider**: ${plugin.provider || 'default'}
381
- - **Features**: ${(plugin.features || []).join(', ') || 'default'}`).join('\n\n')
382
- : 'No plugins configured.';
383
-
384
- // Generate content
385
- const content = `# ${project.name || 'Project'} - AI Context
386
-
387
- **Generated by**: Bootspring v1.0.0
388
- **Last Updated**: ${date}
389
- **Framework**: ${stack.framework || 'unknown'}
390
-
391
- ---
392
-
393
- ## Project Overview
394
-
395
- ${project.description || 'A modern application built with Bootspring.'}
396
-
397
- ---
398
-
399
- ## Tech Stack
400
-
401
- | Component | Technology |
402
- |-----------|------------|
403
- | Framework | ${stack.framework || 'N/A'} |
404
- | Language | ${stack.language || 'typescript'} |
405
- | Database | ${stack.database || 'N/A'} |
406
- | Hosting | ${stack.hosting || 'N/A'} |
407
-
408
- ---
409
-
410
- ## Enabled Plugins
411
-
412
- ${pluginsSection}
413
-
414
- ---
415
-
416
- ## Bootspring Commands
417
-
418
- ### Quick Commands (use in AI assistant)
419
-
420
- | Command | Description |
421
- |---------|-------------|
422
- | \`bootspring todo add "task"\` | Add a todo item |
423
- | \`bootspring todo list\` | List all todos |
424
- | \`bootspring todo done <id>\` | Mark todo complete |
425
- | \`bootspring agent list\` | List available agents |
426
- | \`bootspring agent invoke <name>\` | Get specialized help |
427
- | \`bootspring skill search <query>\` | Find code patterns |
428
- | \`bootspring dashboard\` | Start real-time dashboard |
429
- | \`bootspring generate\` | Regenerate this context |
430
- | \`bootspring quality pre-commit\` | Run quality checks |
431
-
432
- ### Specialized Agents
433
-
434
- | Agent | Expertise |
435
- |-------|-----------|
436
- | database-expert | Schema design, queries, migrations |
437
- | security-expert | Security review, OWASP, auth |
438
- | frontend-expert | UI components, React, CSS |
439
- | backend-expert | API design, server logic |
440
- | api-expert | REST/GraphQL, route handlers |
441
- | testing-expert | Test strategy, coverage, TDD |
442
- | performance-expert | Optimization, profiling |
443
- | devops-expert | CI/CD, deployment |
444
- | ui-ux-expert | Design patterns, accessibility |
445
- | architecture-expert | System design, patterns |
446
- | code-review-expert | Code quality, best practices |
447
- | vercel-expert | Vercel deployment, edge functions |
448
-
449
- **Invoke**: \`bootspring agent invoke <name>\`
450
-
451
- ---
452
-
453
- ## Development Guidelines
454
-
455
- ### Code Style
456
-
457
- - Use ${stack.language === 'typescript' ? 'TypeScript' : 'JavaScript'} for all new code
458
- - Follow existing naming conventions
459
- - Keep files under 300 lines when possible
460
-
461
- ### Best Practices
462
-
463
- - Use Server Components by default (if Next.js)
464
- - Prefer Server Actions over API routes for mutations
465
- - Use Zod for input validation
466
- - Never expose API keys to client
467
- - Write tests for new features
468
-
469
- ### Git Commits
470
-
471
- - Use conventional commit format: \`feat:\`, \`fix:\`, \`docs:\`, \`refactor:\`
472
- - Keep commits focused and atomic
473
- - Never commit sensitive data
474
- - No AI/Claude references in commits
475
-
476
- ---
477
-
478
- ## Quality Gates
479
-
480
- Run before commits:
481
-
482
- \`\`\`bash
483
- bootspring quality pre-commit
484
- \`\`\`
485
- ${generateMvpSection(mvpInfo)}
486
- ---
487
-
488
- *Generated by [Bootspring](https://bootspring.com)*
489
- `;
490
-
491
- return content;
492
- }
493
-
494
- /**
495
- * Main generation function
496
- * @param {object} options - Generation options
497
- * @returns {object} Generation result
498
- */
499
- async function generate(options = {}) {
500
- const projectRoot = options.projectRoot || process.cwd();
501
- const outputPath = options.outputPath || path.join(projectRoot, 'CLAUDE.md');
502
- const dryRun = options.dryRun || false;
503
- const withMvp = options.withMvp || false;
504
-
505
- // Parse config
506
- const config = parseConfig(projectRoot);
507
-
508
- // Generate content
509
- const content = generateClaudeMd(config, {
510
- projectRoot,
511
- withMvp,
512
- mvpPath: options.mvpPath
513
- });
514
-
515
- // Write or return
516
- if (dryRun) {
517
- return {
518
- success: true,
519
- dryRun: true,
520
- content,
521
- bytes: content.length
522
- };
523
- }
524
-
525
- try {
526
- fs.writeFileSync(outputPath, content, 'utf8');
527
- return {
528
- success: true,
529
- outputPath,
530
- bytes: content.length
531
- };
532
- } catch (error) {
533
- return {
534
- success: false,
535
- error: error.message
536
- };
537
- }
538
- }
539
-
540
- // CLI execution
541
- if (require.main === module) {
542
- const args = process.argv.slice(2);
543
- const options = {
544
- dryRun: args.includes('--dry-run'),
545
- withMvp: args.includes('--with-mvp'),
546
- help: args.includes('--help') || args.includes('-h')
547
- };
548
-
549
- if (options.help) {
550
- console.log(`
551
- ${c.bold}Bootspring Context Generator${c.reset}
552
-
553
- ${c.cyan}Usage:${c.reset}
554
- node generate.js [options]
555
-
556
- ${c.cyan}Options:${c.reset}
557
- --with-mvp Include MVP source analysis
558
- --dry-run Preview without writing files
559
- --help, -h Show this help
560
-
561
- ${c.cyan}Examples:${c.reset}
562
- node generate.js
563
- node generate.js --with-mvp
564
- node generate.js --dry-run
565
- `);
566
- process.exit(0);
567
- }
568
-
569
- console.log(`
570
- ${c.cyan}${c.bold}Bootspring Context Generator${c.reset}
571
- ${c.dim}Generating AI context files...${c.reset}
572
- `);
573
-
574
- generate(options).then(result => {
575
- if (result.success) {
576
- if (result.dryRun) {
577
- console.log(`${c.yellow}[DRY RUN]${c.reset} Would write ${result.bytes.toLocaleString()} bytes`);
578
- } else {
579
- console.log(`${c.green}*${c.reset} Generated ${result.outputPath}`);
580
- console.log(`${c.dim} ${result.bytes.toLocaleString()} bytes${c.reset}`);
581
- }
582
- } else {
583
- console.log(`${c.red}Error:${c.reset} ${result.error}`);
584
- process.exit(1);
585
- }
586
- });
587
- }
588
-
589
- module.exports = {
590
- generate,
591
- generateClaudeMd,
592
- analyzeMvpSource,
593
- parseConfig,
594
- parseSeedMd
595
- };