@girardmedia/bootspring 1.1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +255 -0
  3. package/agents/README.md +93 -0
  4. package/agents/api-expert/context.md +416 -0
  5. package/agents/architecture-expert/context.md +454 -0
  6. package/agents/backend-expert/context.md +483 -0
  7. package/agents/code-review-expert/context.md +365 -0
  8. package/agents/database-expert/context.md +250 -0
  9. package/agents/devops-expert/context.md +446 -0
  10. package/agents/frontend-expert/context.md +364 -0
  11. package/agents/index.js +140 -0
  12. package/agents/performance-expert/context.md +377 -0
  13. package/agents/security-expert/context.md +343 -0
  14. package/agents/testing-expert/context.md +414 -0
  15. package/agents/ui-ux-expert/context.md +448 -0
  16. package/agents/vercel-expert/context.md +426 -0
  17. package/bin/bootspring.js +310 -0
  18. package/cli/agent.js +337 -0
  19. package/cli/context.js +194 -0
  20. package/cli/dashboard.js +150 -0
  21. package/cli/generate.js +294 -0
  22. package/cli/init.js +410 -0
  23. package/cli/loop.js +421 -0
  24. package/cli/mcp.js +241 -0
  25. package/cli/memory.js +303 -0
  26. package/cli/orchestrator.js +400 -0
  27. package/cli/plugin.js +451 -0
  28. package/cli/quality.js +332 -0
  29. package/cli/skill.js +369 -0
  30. package/cli/task.js +628 -0
  31. package/cli/telemetry.js +114 -0
  32. package/cli/todo.js +614 -0
  33. package/cli/update.js +312 -0
  34. package/core/config.js +245 -0
  35. package/core/context.js +329 -0
  36. package/core/entitlements.js +209 -0
  37. package/core/index.js +43 -0
  38. package/core/policies.js +68 -0
  39. package/core/telemetry.js +247 -0
  40. package/core/utils.js +380 -0
  41. package/dashboard/server.js +818 -0
  42. package/docs/integrations/claude-code.md +42 -0
  43. package/docs/integrations/codex.md +42 -0
  44. package/docs/mcp-api-platform.md +102 -0
  45. package/generators/generate.js +598 -0
  46. package/generators/index.js +18 -0
  47. package/hooks/context-detector.js +177 -0
  48. package/hooks/index.js +35 -0
  49. package/hooks/prompt-enhancer.js +289 -0
  50. package/intelligence/git-memory.js +551 -0
  51. package/intelligence/index.js +59 -0
  52. package/intelligence/orchestrator.js +964 -0
  53. package/intelligence/prd.js +447 -0
  54. package/intelligence/recommendation-weights.json +18 -0
  55. package/intelligence/recommendations.js +234 -0
  56. package/mcp/capabilities.js +71 -0
  57. package/mcp/contracts/mcp-contract.v1.json +497 -0
  58. package/mcp/registry.js +213 -0
  59. package/mcp/response-formatter.js +462 -0
  60. package/mcp/server.js +99 -0
  61. package/mcp/tools/agent-tool.js +137 -0
  62. package/mcp/tools/capabilities-tool.js +54 -0
  63. package/mcp/tools/context-tool.js +49 -0
  64. package/mcp/tools/dashboard-tool.js +58 -0
  65. package/mcp/tools/generate-tool.js +46 -0
  66. package/mcp/tools/loop-tool.js +134 -0
  67. package/mcp/tools/memory-tool.js +180 -0
  68. package/mcp/tools/orchestrator-tool.js +232 -0
  69. package/mcp/tools/plugin-tool.js +76 -0
  70. package/mcp/tools/quality-tool.js +47 -0
  71. package/mcp/tools/skill-tool.js +233 -0
  72. package/mcp/tools/telemetry-tool.js +95 -0
  73. package/mcp/tools/todo-tool.js +133 -0
  74. package/package.json +98 -0
  75. package/plugins/index.js +141 -0
  76. package/quality/index.js +380 -0
  77. package/quality/lint-budgets.json +19 -0
  78. package/skills/index.js +787 -0
  79. package/skills/patterns/README.md +163 -0
  80. package/skills/patterns/api/route-handler.md +217 -0
  81. package/skills/patterns/api/server-action.md +249 -0
  82. package/skills/patterns/auth/clerk.md +132 -0
  83. package/skills/patterns/database/prisma.md +180 -0
  84. package/skills/patterns/payments/stripe.md +272 -0
  85. package/skills/patterns/security/validation.md +268 -0
  86. package/skills/patterns/testing/vitest.md +307 -0
  87. package/templates/bootspring.config.js +83 -0
  88. package/templates/mcp.json +9 -0
package/cli/update.js ADDED
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Bootspring Update Command
3
+ * Check for updates and manage versions
4
+ *
5
+ * @package bootspring
6
+ * @command update
7
+ */
8
+
9
+ const { execSync } = require('child_process');
10
+ const path = require('path');
11
+ const fs = require('fs');
12
+ const config = require('../core/config');
13
+ const utils = require('../core/utils');
14
+
15
+ /**
16
+ * Get current installed version
17
+ */
18
+ function getCurrentVersion() {
19
+ const packagePath = path.join(__dirname, '..', 'package.json');
20
+
21
+ try {
22
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
23
+ return pkg.version || '0.0.0';
24
+ } catch (error) {
25
+ return '0.0.0';
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Get latest version from npm
31
+ */
32
+ async function getLatestVersion() {
33
+ try {
34
+ const result = execSync('npm view bootspring version 2>/dev/null', {
35
+ encoding: 'utf-8',
36
+ timeout: 10000
37
+ }).trim();
38
+ return result || null;
39
+ } catch (error) {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Compare semantic versions
46
+ * Returns: -1 if a < b, 0 if a === b, 1 if a > b
47
+ */
48
+ function compareVersions(a, b) {
49
+ const partsA = a.split('.').map(Number);
50
+ const partsB = b.split('.').map(Number);
51
+
52
+ for (let i = 0; i < 3; i++) {
53
+ const partA = partsA[i] || 0;
54
+ const partB = partsB[i] || 0;
55
+
56
+ if (partA < partB) return -1;
57
+ if (partA > partB) return 1;
58
+ }
59
+
60
+ return 0;
61
+ }
62
+
63
+ /**
64
+ * Check for updates
65
+ */
66
+ async function checkForUpdates(options = {}) {
67
+ console.log(`
68
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Update Check${utils.COLORS.reset}
69
+ `);
70
+
71
+ const spinner = utils.createSpinner('Checking for updates...').start();
72
+
73
+ const currentVersion = getCurrentVersion();
74
+ const latestVersion = await getLatestVersion();
75
+
76
+ if (!latestVersion) {
77
+ spinner.warn('Could not fetch latest version from npm');
78
+ console.log(`${utils.COLORS.dim}Current version: ${currentVersion}${utils.COLORS.reset}`);
79
+ console.log(`${utils.COLORS.dim}Package may not be published yet${utils.COLORS.reset}`);
80
+ return { current: currentVersion, latest: null, updateAvailable: false };
81
+ }
82
+
83
+ const comparison = compareVersions(currentVersion, latestVersion);
84
+
85
+ if (comparison < 0) {
86
+ spinner.succeed(`Update available: ${currentVersion} → ${latestVersion}`);
87
+ console.log(`
88
+ ${utils.COLORS.bold}To update:${utils.COLORS.reset}
89
+ ${utils.COLORS.cyan}npm update -g bootspring${utils.COLORS.reset}
90
+
91
+ ${utils.COLORS.bold}Or for local projects:${utils.COLORS.reset}
92
+ ${utils.COLORS.cyan}npm update bootspring${utils.COLORS.reset}
93
+ `);
94
+ return { current: currentVersion, latest: latestVersion, updateAvailable: true };
95
+ } else if (comparison === 0) {
96
+ spinner.succeed(`You're on the latest version (${currentVersion})`);
97
+ return { current: currentVersion, latest: latestVersion, updateAvailable: false };
98
+ } else {
99
+ spinner.info(`You're ahead of npm (${currentVersion} > ${latestVersion})`);
100
+ console.log(`${utils.COLORS.dim}You may be running a development version${utils.COLORS.reset}`);
101
+ return { current: currentVersion, latest: latestVersion, updateAvailable: false };
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Apply update via npm
107
+ */
108
+ async function applyUpdate(options = {}) {
109
+ console.log(`
110
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Update${utils.COLORS.reset}
111
+ `);
112
+
113
+ const checkResult = await checkForUpdates();
114
+
115
+ if (!checkResult.updateAvailable) {
116
+ return;
117
+ }
118
+
119
+ console.log(`${utils.COLORS.bold}Starting update...${utils.COLORS.reset}`);
120
+
121
+ const spinner = utils.createSpinner('Updating bootspring...').start();
122
+
123
+ try {
124
+ // Detect if installed globally or locally
125
+ const isGlobal = options.global || process.argv[1].includes('node_modules/.bin');
126
+
127
+ const command = isGlobal
128
+ ? 'npm update -g bootspring'
129
+ : 'npm update bootspring';
130
+
131
+ execSync(command, {
132
+ stdio: 'pipe',
133
+ encoding: 'utf-8',
134
+ timeout: 120000 // 2 minutes
135
+ });
136
+
137
+ spinner.succeed(`Updated to ${checkResult.latest}`);
138
+
139
+ console.log(`
140
+ ${utils.COLORS.green}Update complete!${utils.COLORS.reset}
141
+ ${utils.COLORS.dim}Run "bootspring --version" to verify${utils.COLORS.reset}
142
+ `);
143
+ } catch (error) {
144
+ spinner.fail('Update failed');
145
+ console.log(`${utils.COLORS.red}${error.message}${utils.COLORS.reset}`);
146
+ console.log(`
147
+ ${utils.COLORS.dim}Try updating manually:${utils.COLORS.reset}
148
+ npm update -g bootspring
149
+ `);
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Show version information
155
+ */
156
+ function showVersion() {
157
+ const currentVersion = getCurrentVersion();
158
+ const packagePath = path.join(__dirname, '..', 'package.json');
159
+
160
+ let packageInfo = {};
161
+ try {
162
+ packageInfo = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
163
+ } catch (error) {
164
+ // Ignore
165
+ }
166
+
167
+ console.log(`
168
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring${utils.COLORS.reset}
169
+ ${utils.COLORS.dim}Development scaffolding with intelligence${utils.COLORS.reset}
170
+
171
+ ${utils.COLORS.bold}Version Information${utils.COLORS.reset}
172
+ Version: ${utils.COLORS.cyan}${currentVersion}${utils.COLORS.reset}
173
+ ${packageInfo.description ? `Description: ${packageInfo.description}` : ''}
174
+ ${packageInfo.homepage ? `Homepage: ${packageInfo.homepage}` : ''}
175
+ ${packageInfo.repository?.url ? `Repository: ${packageInfo.repository.url}` : ''}
176
+
177
+ ${utils.COLORS.bold}Environment${utils.COLORS.reset}
178
+ Node.js: ${process.version}
179
+ Platform: ${process.platform}
180
+ Arch: ${process.arch}
181
+
182
+ ${utils.COLORS.dim}Run "bootspring update check" to check for updates${utils.COLORS.reset}
183
+ `);
184
+ }
185
+
186
+ /**
187
+ * Show changelog/release notes
188
+ */
189
+ async function showChangelog() {
190
+ console.log(`
191
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Changelog${utils.COLORS.reset}
192
+ `);
193
+
194
+ const spinner = utils.createSpinner('Fetching changelog...').start();
195
+
196
+ try {
197
+ // Try to fetch from npm
198
+ const result = execSync('npm view bootspring --json 2>/dev/null', {
199
+ encoding: 'utf-8',
200
+ timeout: 10000
201
+ });
202
+
203
+ const npmInfo = JSON.parse(result);
204
+
205
+ spinner.succeed('Latest release info');
206
+
207
+ console.log(`
208
+ ${utils.COLORS.bold}Latest Version${utils.COLORS.reset}
209
+ Version: ${npmInfo.version}
210
+ Published: ${npmInfo.time?.[npmInfo.version] || 'unknown'}
211
+
212
+ ${utils.COLORS.bold}Recent Versions${utils.COLORS.reset}`);
213
+
214
+ const versions = Object.keys(npmInfo.time || {})
215
+ .filter(v => v !== 'created' && v !== 'modified')
216
+ .slice(-5)
217
+ .reverse();
218
+
219
+ for (const version of versions) {
220
+ const date = new Date(npmInfo.time[version]);
221
+ console.log(` ${utils.COLORS.cyan}${version}${utils.COLORS.reset} - ${utils.formatDate(date)}`);
222
+ }
223
+
224
+ console.log(`
225
+ ${utils.COLORS.dim}For full changelog, visit: ${npmInfo.homepage || 'https://github.com/bootspring/bootspring'}${utils.COLORS.reset}
226
+ `);
227
+ } catch (error) {
228
+ spinner.warn('Could not fetch changelog');
229
+ console.log(`
230
+ ${utils.COLORS.dim}Package may not be published yet.
231
+ Check the repository for changelog information.${utils.COLORS.reset}
232
+ `);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Show help
238
+ */
239
+ function showHelp() {
240
+ console.log(`
241
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Update${utils.COLORS.reset}
242
+ ${utils.COLORS.dim}Check for updates and manage versions${utils.COLORS.reset}
243
+
244
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
245
+ bootspring update [command]
246
+
247
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
248
+ ${utils.COLORS.cyan}check${utils.COLORS.reset} Check for available updates
249
+ ${utils.COLORS.cyan}apply${utils.COLORS.reset} Download and apply updates
250
+ ${utils.COLORS.cyan}version${utils.COLORS.reset} Show version information
251
+ ${utils.COLORS.cyan}changelog${utils.COLORS.reset} Show recent changes
252
+
253
+ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
254
+ --global Update global installation
255
+
256
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
257
+ bootspring update check
258
+ bootspring update apply
259
+ bootspring update version
260
+ `);
261
+ }
262
+
263
+ /**
264
+ * Run update command
265
+ */
266
+ async function run(args) {
267
+ const parsedArgs = utils.parseArgs(args);
268
+ const subcommand = parsedArgs._[0] || 'check';
269
+
270
+ switch (subcommand) {
271
+ case 'check':
272
+ await checkForUpdates();
273
+ break;
274
+
275
+ case 'apply':
276
+ case 'upgrade':
277
+ case 'install':
278
+ await applyUpdate({ global: parsedArgs.global });
279
+ break;
280
+
281
+ case 'version':
282
+ case '-v':
283
+ case '--version':
284
+ showVersion();
285
+ break;
286
+
287
+ case 'changelog':
288
+ case 'changes':
289
+ case 'releases':
290
+ await showChangelog();
291
+ break;
292
+
293
+ case 'help':
294
+ case '-h':
295
+ case '--help':
296
+ showHelp();
297
+ break;
298
+
299
+ default:
300
+ utils.print.error(`Unknown subcommand: ${subcommand}`);
301
+ showHelp();
302
+ }
303
+ }
304
+
305
+ module.exports = {
306
+ run,
307
+ checkForUpdates,
308
+ applyUpdate,
309
+ getCurrentVersion,
310
+ getLatestVersion,
311
+ compareVersions
312
+ };
package/core/config.js ADDED
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Bootspring Configuration
3
+ * Handles loading and validating bootspring.config.js
4
+ *
5
+ * @package bootspring
6
+ * @module core/config
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ // Default configuration
13
+ const DEFAULT_CONFIG = {
14
+ project: {
15
+ name: 'My Project',
16
+ description: '',
17
+ version: '1.0.0'
18
+ },
19
+
20
+ stack: {
21
+ framework: 'nextjs',
22
+ language: 'typescript',
23
+ database: 'postgresql',
24
+ hosting: 'vercel'
25
+ },
26
+
27
+ plugins: {
28
+ auth: { enabled: false, provider: 'clerk' },
29
+ payments: { enabled: false, provider: 'stripe' },
30
+ database: { enabled: true, provider: 'prisma' },
31
+ testing: { enabled: true, provider: 'vitest' },
32
+ security: { enabled: true },
33
+ ai: { enabled: false, provider: 'anthropic' }
34
+ },
35
+
36
+ dashboard: {
37
+ port: 3456,
38
+ autoOpen: false
39
+ },
40
+
41
+ quality: {
42
+ preCommit: true,
43
+ prePush: false,
44
+ strictMode: false
45
+ },
46
+
47
+ paths: {
48
+ context: 'CLAUDE.md',
49
+ config: 'bootspring.config.js',
50
+ todo: 'todo.md'
51
+ }
52
+ };
53
+
54
+ // Config file names to search for
55
+ const CONFIG_FILES = [
56
+ 'bootspring.config.js',
57
+ 'bootspring.config.mjs',
58
+ 'bootspring.config.json',
59
+ '.bootspringrc',
60
+ '.bootspringrc.js',
61
+ '.bootspringrc.json'
62
+ ];
63
+
64
+ /**
65
+ * Find the project root directory
66
+ * @returns {string|null} Project root path or null
67
+ */
68
+ function findProjectRoot() {
69
+ let dir = process.cwd();
70
+ const root = path.parse(dir).root;
71
+
72
+ while (dir !== root) {
73
+ // Check for common project indicators
74
+ if (
75
+ fs.existsSync(path.join(dir, 'package.json')) ||
76
+ fs.existsSync(path.join(dir, 'bootspring.config.js')) ||
77
+ fs.existsSync(path.join(dir, '.git'))
78
+ ) {
79
+ return dir;
80
+ }
81
+ dir = path.dirname(dir);
82
+ }
83
+
84
+ return process.cwd();
85
+ }
86
+
87
+ /**
88
+ * Find config file in project
89
+ * @param {string} projectRoot - Project root directory
90
+ * @returns {string|null} Config file path or null
91
+ */
92
+ function findConfigFile(projectRoot) {
93
+ for (const filename of CONFIG_FILES) {
94
+ const filepath = path.join(projectRoot, filename);
95
+ if (fs.existsSync(filepath)) {
96
+ return filepath;
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ /**
103
+ * Deep merge two objects
104
+ * @param {object} target - Target object
105
+ * @param {object} source - Source object
106
+ * @returns {object} Merged object
107
+ */
108
+ function deepMerge(target, source) {
109
+ const result = { ...target };
110
+
111
+ for (const key of Object.keys(source)) {
112
+ if (source[key] instanceof Object && key in target && target[key] instanceof Object) {
113
+ result[key] = deepMerge(target[key], source[key]);
114
+ } else {
115
+ result[key] = source[key];
116
+ }
117
+ }
118
+
119
+ return result;
120
+ }
121
+
122
+ /**
123
+ * Load configuration from file
124
+ * @param {string} [projectRoot] - Optional project root path
125
+ * @returns {object} Configuration object
126
+ */
127
+ function load(projectRoot = null) {
128
+ const root = projectRoot || findProjectRoot();
129
+ const configPath = findConfigFile(root);
130
+
131
+ let userConfig = {};
132
+
133
+ if (configPath) {
134
+ try {
135
+ if (configPath.endsWith('.json') || configPath.endsWith('.bootspringrc')) {
136
+ const content = fs.readFileSync(configPath, 'utf-8');
137
+ userConfig = JSON.parse(content);
138
+ } else {
139
+ // Clear require cache to get fresh config
140
+ delete require.cache[require.resolve(configPath)];
141
+ userConfig = require(configPath);
142
+ }
143
+ } catch (error) {
144
+ console.warn(`Warning: Could not load config from ${configPath}: ${error.message}`);
145
+ }
146
+ }
147
+
148
+ // Merge with defaults
149
+ const config = deepMerge(DEFAULT_CONFIG, userConfig);
150
+
151
+ // Add computed paths
152
+ config._projectRoot = root;
153
+ config._configPath = configPath;
154
+ config._bootspringDir = path.join(root, '.bootspring');
155
+
156
+ return config;
157
+ }
158
+
159
+ /**
160
+ * Save configuration to file
161
+ * @param {object} config - Configuration object
162
+ * @param {string} [filepath] - Optional file path
163
+ * @returns {boolean} Success status
164
+ */
165
+ function save(config, filepath = null) {
166
+ const root = config._projectRoot || findProjectRoot();
167
+ const targetPath = filepath || path.join(root, 'bootspring.config.js');
168
+
169
+ // Remove internal properties
170
+ const cleanConfig = { ...config };
171
+ delete cleanConfig._projectRoot;
172
+ delete cleanConfig._configPath;
173
+ delete cleanConfig._bootspringDir;
174
+
175
+ const content = `/**
176
+ * Bootspring Configuration
177
+ * https://bootspring.com/docs/configuration
178
+ */
179
+
180
+ module.exports = ${JSON.stringify(cleanConfig, null, 2)};
181
+ `;
182
+
183
+ try {
184
+ fs.writeFileSync(targetPath, content, 'utf-8');
185
+ return true;
186
+ } catch (error) {
187
+ console.error(`Error saving config: ${error.message}`);
188
+ return false;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Validate configuration
194
+ * @param {object} config - Configuration object
195
+ * @returns {object} Validation result { valid, errors }
196
+ */
197
+ function validate(config) {
198
+ const errors = [];
199
+
200
+ // Required fields
201
+ if (!config.project?.name) {
202
+ errors.push('project.name is required');
203
+ }
204
+
205
+ // Valid framework
206
+ const validFrameworks = ['nextjs', 'remix', 'nuxt', 'sveltekit', 'express', 'fastify'];
207
+ if (config.stack?.framework && !validFrameworks.includes(config.stack.framework)) {
208
+ errors.push(`Invalid framework: ${config.stack.framework}. Valid: ${validFrameworks.join(', ')}`);
209
+ }
210
+
211
+ // Valid language
212
+ const validLanguages = ['typescript', 'javascript'];
213
+ if (config.stack?.language && !validLanguages.includes(config.stack.language)) {
214
+ errors.push(`Invalid language: ${config.stack.language}. Valid: ${validLanguages.join(', ')}`);
215
+ }
216
+
217
+ // Port range
218
+ if (config.dashboard?.port && (config.dashboard.port < 1024 || config.dashboard.port > 65535)) {
219
+ errors.push('dashboard.port must be between 1024 and 65535');
220
+ }
221
+
222
+ return {
223
+ valid: errors.length === 0,
224
+ errors
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Get default configuration
230
+ * @returns {object} Default configuration
231
+ */
232
+ function getDefaults() {
233
+ return { ...DEFAULT_CONFIG };
234
+ }
235
+
236
+ module.exports = {
237
+ load,
238
+ save,
239
+ validate,
240
+ getDefaults,
241
+ findProjectRoot,
242
+ findConfigFile,
243
+ DEFAULT_CONFIG,
244
+ CONFIG_FILES
245
+ };