@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/plugin.js ADDED
@@ -0,0 +1,451 @@
1
+ /**
2
+ * Bootspring Plugin Command
3
+ * Manage project plugins
4
+ *
5
+ * @package bootspring
6
+ * @command plugin
7
+ */
8
+
9
+ const path = require('path');
10
+ const config = require('../core/config');
11
+ const utils = require('../core/utils');
12
+
13
+ /**
14
+ * Plugin definitions
15
+ */
16
+ const PLUGINS = {
17
+ auth: {
18
+ name: 'Authentication',
19
+ description: 'User authentication and authorization',
20
+ providers: ['clerk', 'nextauth', 'auth0', 'supabase'],
21
+ defaultProvider: 'clerk',
22
+ features: ['social_login', 'email_password', 'magic_link', 'organizations', 'rbac'],
23
+ requiredEnv: {
24
+ clerk: ['NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY', 'CLERK_SECRET_KEY'],
25
+ nextauth: ['NEXTAUTH_SECRET', 'NEXTAUTH_URL'],
26
+ auth0: ['AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'AUTH0_ISSUER'],
27
+ supabase: ['NEXT_PUBLIC_SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY']
28
+ },
29
+ skills: ['auth/clerk', 'auth/nextauth']
30
+ },
31
+ payments: {
32
+ name: 'Payments',
33
+ description: 'Payment processing and subscriptions',
34
+ providers: ['stripe', 'paddle', 'lemonsqueezy'],
35
+ defaultProvider: 'stripe',
36
+ features: ['checkout', 'subscriptions', 'webhooks', 'invoices', 'usage_billing'],
37
+ requiredEnv: {
38
+ stripe: ['STRIPE_SECRET_KEY', 'STRIPE_WEBHOOK_SECRET'],
39
+ paddle: ['PADDLE_VENDOR_ID', 'PADDLE_API_KEY'],
40
+ lemonsqueezy: ['LEMONSQUEEZY_API_KEY', 'LEMONSQUEEZY_SIGNING_SECRET']
41
+ },
42
+ skills: ['payments/stripe', 'payments/webhooks']
43
+ },
44
+ database: {
45
+ name: 'Database',
46
+ description: 'Database ORM and migrations',
47
+ providers: ['prisma', 'drizzle', 'typeorm', 'mongoose'],
48
+ defaultProvider: 'prisma',
49
+ features: ['migrations', 'transactions', 'soft_deletes', 'seeding'],
50
+ requiredEnv: {
51
+ prisma: ['DATABASE_URL'],
52
+ drizzle: ['DATABASE_URL'],
53
+ typeorm: ['DATABASE_URL'],
54
+ mongoose: ['MONGODB_URI']
55
+ },
56
+ skills: ['database/prisma', 'database/drizzle']
57
+ },
58
+ testing: {
59
+ name: 'Testing',
60
+ description: 'Testing frameworks and utilities',
61
+ providers: ['vitest', 'jest', 'playwright'],
62
+ defaultProvider: 'vitest',
63
+ features: ['unit', 'integration', 'e2e', 'coverage', 'mocking'],
64
+ requiredEnv: {},
65
+ skills: ['testing/vitest', 'testing/playwright']
66
+ },
67
+ security: {
68
+ name: 'Security',
69
+ description: 'Security checks and protections',
70
+ providers: ['default'],
71
+ defaultProvider: 'default',
72
+ features: ['input_validation', 'rate_limiting', 'csrf', 'cors', 'owasp_checks'],
73
+ requiredEnv: {},
74
+ skills: ['security/validation', 'security/rate-limiting']
75
+ },
76
+ ai: {
77
+ name: 'AI Integration',
78
+ description: 'AI model integration and utilities',
79
+ providers: ['anthropic', 'openai', 'google'],
80
+ defaultProvider: 'anthropic',
81
+ features: ['streaming', 'tool_use', 'structured_output', 'embeddings', 'rag'],
82
+ requiredEnv: {
83
+ anthropic: ['ANTHROPIC_API_KEY'],
84
+ openai: ['OPENAI_API_KEY'],
85
+ google: ['GOOGLE_AI_API_KEY']
86
+ },
87
+ skills: ['ai/streaming', 'ai/tool-use']
88
+ }
89
+ };
90
+
91
+ /**
92
+ * List all plugins
93
+ */
94
+ function listPlugins() {
95
+ const cfg = config.load();
96
+
97
+ console.log(`
98
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Plugins${utils.COLORS.reset}
99
+ ${utils.COLORS.dim}Extensible functionality for your project${utils.COLORS.reset}
100
+ `);
101
+
102
+ for (const [id, plugin] of Object.entries(PLUGINS)) {
103
+ const userPlugin = cfg.plugins?.[id] || {};
104
+ const enabled = userPlugin.enabled !== false && (userPlugin.enabled || userPlugin.provider);
105
+ const provider = userPlugin.provider || plugin.defaultProvider;
106
+
107
+ const statusIcon = enabled
108
+ ? `${utils.COLORS.green}●${utils.COLORS.reset}`
109
+ : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
110
+
111
+ const statusText = enabled
112
+ ? `${utils.COLORS.green}enabled${utils.COLORS.reset} (${provider})`
113
+ : `${utils.COLORS.dim}disabled${utils.COLORS.reset}`;
114
+
115
+ console.log(` ${statusIcon} ${utils.COLORS.cyan}${id}${utils.COLORS.reset}`);
116
+ console.log(` ${plugin.description}`);
117
+ console.log(` Status: ${statusText}`);
118
+ console.log();
119
+ }
120
+
121
+ utils.print.dim('Use "bootspring plugin show <name>" for details');
122
+ }
123
+
124
+ /**
125
+ * Show plugin details
126
+ */
127
+ function showPlugin(pluginId) {
128
+ const plugin = PLUGINS[pluginId];
129
+
130
+ if (!plugin) {
131
+ utils.print.error(`Plugin not found: ${pluginId}`);
132
+ utils.print.dim('Use "bootspring plugin list" to see available plugins');
133
+ return;
134
+ }
135
+
136
+ const cfg = config.load();
137
+ const userPlugin = cfg.plugins?.[pluginId] || {};
138
+ const enabled = userPlugin.enabled !== false && (userPlugin.enabled || userPlugin.provider);
139
+ const currentProvider = userPlugin.provider || plugin.defaultProvider;
140
+ const enabledFeatures = userPlugin.features || [];
141
+
142
+ console.log(`
143
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ ${plugin.name} Plugin${utils.COLORS.reset}
144
+ ${utils.COLORS.dim}${plugin.description}${utils.COLORS.reset}
145
+
146
+ ${utils.COLORS.bold}Status${utils.COLORS.reset}
147
+ Enabled: ${enabled ? `${utils.COLORS.green}yes${utils.COLORS.reset}` : `${utils.COLORS.dim}no${utils.COLORS.reset}`}
148
+ Provider: ${currentProvider}
149
+
150
+ ${utils.COLORS.bold}Available Providers${utils.COLORS.reset}
151
+ ${plugin.providers.map(p => {
152
+ const isCurrent = p === currentProvider;
153
+ const icon = isCurrent ? `${utils.COLORS.green}●${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
154
+ return ` ${icon} ${p}${isCurrent ? ' (current)' : ''}`;
155
+ }).join('\n')}
156
+
157
+ ${utils.COLORS.bold}Available Features${utils.COLORS.reset}
158
+ ${plugin.features.map(f => {
159
+ const isEnabled = enabledFeatures.includes(f);
160
+ const icon = isEnabled ? `${utils.COLORS.green}✓${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
161
+ return ` ${icon} ${f}`;
162
+ }).join('\n')}
163
+ `);
164
+
165
+ // Show required environment variables
166
+ const requiredEnv = plugin.requiredEnv[currentProvider];
167
+ if (requiredEnv && requiredEnv.length > 0) {
168
+ console.log(`${utils.COLORS.bold}Required Environment Variables${utils.COLORS.reset}`);
169
+ for (const envVar of requiredEnv) {
170
+ const hasValue = !!process.env[envVar];
171
+ const icon = hasValue
172
+ ? `${utils.COLORS.green}✓${utils.COLORS.reset}`
173
+ : `${utils.COLORS.red}✗${utils.COLORS.reset}`;
174
+ console.log(` ${icon} ${envVar}`);
175
+ }
176
+ console.log();
177
+ }
178
+
179
+ // Show related skills
180
+ if (plugin.skills.length > 0) {
181
+ console.log(`${utils.COLORS.bold}Related Skills${utils.COLORS.reset}`);
182
+ for (const skill of plugin.skills) {
183
+ console.log(` ${utils.COLORS.dim}bootspring skill show ${skill}${utils.COLORS.reset}`);
184
+ }
185
+ console.log();
186
+ }
187
+
188
+ console.log(`${utils.COLORS.bold}Configuration${utils.COLORS.reset}
189
+ Edit ${utils.COLORS.cyan}bootspring.config.js${utils.COLORS.reset}:
190
+
191
+ plugins: {
192
+ ${pluginId}: {
193
+ enabled: true,
194
+ provider: '${currentProvider}',
195
+ features: ['${plugin.features.slice(0, 3).join("', '")}']
196
+ }
197
+ }
198
+ `);
199
+ }
200
+
201
+ /**
202
+ * Enable a plugin
203
+ */
204
+ function enablePlugin(pluginId, options = {}) {
205
+ const plugin = PLUGINS[pluginId];
206
+
207
+ if (!plugin) {
208
+ utils.print.error(`Plugin not found: ${pluginId}`);
209
+ return;
210
+ }
211
+
212
+ const provider = options.provider || plugin.defaultProvider;
213
+
214
+ if (!plugin.providers.includes(provider)) {
215
+ utils.print.error(`Invalid provider: ${provider}`);
216
+ utils.print.dim(`Valid providers: ${plugin.providers.join(', ')}`);
217
+ return;
218
+ }
219
+
220
+ utils.print.success(`To enable ${pluginId} plugin with ${provider}:`);
221
+ console.log(`
222
+ Edit ${utils.COLORS.cyan}bootspring.config.js${utils.COLORS.reset}:
223
+
224
+ plugins: {
225
+ ${pluginId}: {
226
+ enabled: true,
227
+ provider: '${provider}',
228
+ features: ['${plugin.features.slice(0, 3).join("', '")}']
229
+ }
230
+ }
231
+ `);
232
+
233
+ // Show required env vars
234
+ const requiredEnv = plugin.requiredEnv[provider];
235
+ if (requiredEnv && requiredEnv.length > 0) {
236
+ console.log(`${utils.COLORS.bold}Add to .env:${utils.COLORS.reset}`);
237
+ for (const envVar of requiredEnv) {
238
+ console.log(` ${envVar}=your_value_here`);
239
+ }
240
+ console.log();
241
+ }
242
+
243
+ console.log(`${utils.COLORS.dim}Then run: bootspring generate${utils.COLORS.reset}`);
244
+ }
245
+
246
+ /**
247
+ * Disable a plugin
248
+ */
249
+ function disablePlugin(pluginId) {
250
+ const plugin = PLUGINS[pluginId];
251
+
252
+ if (!plugin) {
253
+ utils.print.error(`Plugin not found: ${pluginId}`);
254
+ return;
255
+ }
256
+
257
+ utils.print.success(`To disable ${pluginId} plugin:`);
258
+ console.log(`
259
+ Edit ${utils.COLORS.cyan}bootspring.config.js${utils.COLORS.reset}:
260
+
261
+ plugins: {
262
+ ${pluginId}: {
263
+ enabled: false
264
+ }
265
+ }
266
+ `);
267
+ console.log(`${utils.COLORS.dim}Then run: bootspring generate${utils.COLORS.reset}`);
268
+ }
269
+
270
+ /**
271
+ * Validate plugins
272
+ */
273
+ function validatePlugins() {
274
+ const cfg = config.load();
275
+
276
+ console.log(`
277
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Plugin Validation${utils.COLORS.reset}
278
+ `);
279
+
280
+ let issues = 0;
281
+
282
+ for (const [id, plugin] of Object.entries(PLUGINS)) {
283
+ const userPlugin = cfg.plugins?.[id] || {};
284
+ const enabled = userPlugin.enabled !== false && (userPlugin.enabled || userPlugin.provider);
285
+
286
+ if (!enabled) continue;
287
+
288
+ const provider = userPlugin.provider || plugin.defaultProvider;
289
+ const requiredEnv = plugin.requiredEnv[provider] || [];
290
+
291
+ let pluginOk = true;
292
+ const missingEnv = [];
293
+
294
+ for (const envVar of requiredEnv) {
295
+ if (!process.env[envVar]) {
296
+ missingEnv.push(envVar);
297
+ pluginOk = false;
298
+ }
299
+ }
300
+
301
+ if (pluginOk) {
302
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${id} (${provider})`);
303
+ } else {
304
+ console.log(` ${utils.COLORS.red}✗${utils.COLORS.reset} ${id} (${provider})`);
305
+ console.log(` ${utils.COLORS.dim}Missing: ${missingEnv.join(', ')}${utils.COLORS.reset}`);
306
+ issues++;
307
+ }
308
+ }
309
+
310
+ console.log();
311
+
312
+ if (issues === 0) {
313
+ utils.print.success('All enabled plugins are properly configured');
314
+ } else {
315
+ utils.print.warning(`${issues} plugin(s) have missing configuration`);
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Show skills for a plugin
321
+ */
322
+ function showPluginSkills(pluginId) {
323
+ const plugin = PLUGINS[pluginId];
324
+
325
+ if (!plugin) {
326
+ utils.print.error(`Plugin not found: ${pluginId}`);
327
+ return;
328
+ }
329
+
330
+ console.log(`
331
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ ${plugin.name} Skills${utils.COLORS.reset}
332
+ `);
333
+
334
+ if (plugin.skills.length === 0) {
335
+ utils.print.dim('No skills available for this plugin');
336
+ return;
337
+ }
338
+
339
+ for (const skill of plugin.skills) {
340
+ console.log(` ${utils.COLORS.cyan}${skill}${utils.COLORS.reset}`);
341
+ console.log(` ${utils.COLORS.dim}bootspring skill show ${skill}${utils.COLORS.reset}`);
342
+ }
343
+
344
+ console.log();
345
+ }
346
+
347
+ /**
348
+ * Show plugin help
349
+ */
350
+ function showHelp() {
351
+ console.log(`
352
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Plugin${utils.COLORS.reset}
353
+ ${utils.COLORS.dim}Manage project plugins${utils.COLORS.reset}
354
+
355
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
356
+ bootspring plugin <command> [args]
357
+
358
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
359
+ ${utils.COLORS.cyan}list${utils.COLORS.reset} List all plugins with status
360
+ ${utils.COLORS.cyan}show${utils.COLORS.reset} <name> Show plugin details
361
+ ${utils.COLORS.cyan}enable${utils.COLORS.reset} <name> Instructions to enable plugin
362
+ ${utils.COLORS.cyan}disable${utils.COLORS.reset} <name> Instructions to disable plugin
363
+ ${utils.COLORS.cyan}validate${utils.COLORS.reset} Check plugin configuration
364
+ ${utils.COLORS.cyan}skills${utils.COLORS.reset} <name> Show skills for a plugin
365
+
366
+ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
367
+ --provider <name> Specify provider when enabling
368
+
369
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
370
+ bootspring plugin list
371
+ bootspring plugin show auth
372
+ bootspring plugin enable auth --provider clerk
373
+ bootspring plugin validate
374
+ bootspring plugin skills payments
375
+ `);
376
+ }
377
+
378
+ /**
379
+ * Run plugin command
380
+ */
381
+ async function run(args) {
382
+ const parsedArgs = utils.parseArgs(args);
383
+ const subcommand = parsedArgs._[0] || 'list';
384
+ const subargs = parsedArgs._.slice(1);
385
+
386
+ switch (subcommand) {
387
+ case 'list':
388
+ case 'ls':
389
+ listPlugins();
390
+ break;
391
+
392
+ case 'show':
393
+ case 'info':
394
+ if (!subargs[0]) {
395
+ utils.print.error('Please specify a plugin name');
396
+ utils.print.dim('Usage: bootspring plugin show <name>');
397
+ return;
398
+ }
399
+ showPlugin(subargs[0]);
400
+ break;
401
+
402
+ case 'enable':
403
+ if (!subargs[0]) {
404
+ utils.print.error('Please specify a plugin name');
405
+ utils.print.dim('Usage: bootspring plugin enable <name>');
406
+ return;
407
+ }
408
+ enablePlugin(subargs[0], { provider: parsedArgs.provider });
409
+ break;
410
+
411
+ case 'disable':
412
+ if (!subargs[0]) {
413
+ utils.print.error('Please specify a plugin name');
414
+ utils.print.dim('Usage: bootspring plugin disable <name>');
415
+ return;
416
+ }
417
+ disablePlugin(subargs[0]);
418
+ break;
419
+
420
+ case 'validate':
421
+ case 'check':
422
+ validatePlugins();
423
+ break;
424
+
425
+ case 'skills':
426
+ if (!subargs[0]) {
427
+ utils.print.error('Please specify a plugin name');
428
+ utils.print.dim('Usage: bootspring plugin skills <name>');
429
+ return;
430
+ }
431
+ showPluginSkills(subargs[0]);
432
+ break;
433
+
434
+ case 'help':
435
+ case '-h':
436
+ case '--help':
437
+ showHelp();
438
+ break;
439
+
440
+ default:
441
+ // Check if it's a plugin name (shortcut for show)
442
+ if (PLUGINS[subcommand]) {
443
+ showPlugin(subcommand);
444
+ } else {
445
+ utils.print.error(`Unknown subcommand: ${subcommand}`);
446
+ showHelp();
447
+ }
448
+ }
449
+ }
450
+
451
+ module.exports = { run, PLUGINS, listPlugins, showPlugin, enablePlugin, disablePlugin, validatePlugins };