@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/init.js ADDED
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Bootspring Init Command
3
+ * Initialize Bootspring in a new or existing project
4
+ *
5
+ * @package bootspring
6
+ * @command init
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const readline = require('readline');
12
+ const config = require('../core/config');
13
+ const utils = require('../core/utils');
14
+
15
+ // Available options
16
+ const FRAMEWORKS = ['nextjs', 'remix', 'nuxt', 'sveltekit', 'express', 'fastify', 'other'];
17
+ const LANGUAGES = ['typescript', 'javascript'];
18
+ const DATABASES = ['postgresql', 'mysql', 'mongodb', 'sqlite', 'none'];
19
+ const HOSTINGS = ['vercel', 'netlify', 'railway', 'fly', 'aws', 'self-hosted'];
20
+
21
+ /**
22
+ * Create readline interface for interactive prompts
23
+ */
24
+ function createPrompt() {
25
+ return readline.createInterface({
26
+ input: process.stdin,
27
+ output: process.stdout
28
+ });
29
+ }
30
+
31
+ /**
32
+ * Ask a question and return the answer
33
+ */
34
+ function ask(rl, question, defaultValue = '') {
35
+ const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
36
+ return new Promise((resolve) => {
37
+ rl.question(prompt, (answer) => {
38
+ resolve(answer.trim() || defaultValue);
39
+ });
40
+ });
41
+ }
42
+
43
+ /**
44
+ * Ask a multiple choice question
45
+ */
46
+ function askChoice(rl, question, options, defaultIndex = 0) {
47
+ return new Promise((resolve) => {
48
+ console.log(`\n${question}`);
49
+ options.forEach((opt, i) => {
50
+ const marker = i === defaultIndex ? `${utils.COLORS.cyan}→${utils.COLORS.reset}` : ' ';
51
+ console.log(` ${marker} ${i + 1}. ${opt}`);
52
+ });
53
+ rl.question(`\nSelect [1-${options.length}] (default: ${defaultIndex + 1}): `, (answer) => {
54
+ const index = parseInt(answer, 10) - 1;
55
+ if (index >= 0 && index < options.length) {
56
+ resolve(options[index]);
57
+ } else {
58
+ resolve(options[defaultIndex]);
59
+ }
60
+ });
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Ask yes/no question
66
+ */
67
+ function askYesNo(rl, question, defaultYes = true) {
68
+ const hint = defaultYes ? '[Y/n]' : '[y/N]';
69
+ return new Promise((resolve) => {
70
+ rl.question(`${question} ${hint}: `, (answer) => {
71
+ const a = answer.trim().toLowerCase();
72
+ if (a === '') {
73
+ resolve(defaultYes);
74
+ } else {
75
+ resolve(a === 'y' || a === 'yes');
76
+ }
77
+ });
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Detect project info from existing files
83
+ */
84
+ function detectProject(projectRoot) {
85
+ const detected = {
86
+ name: path.basename(projectRoot),
87
+ framework: 'nextjs',
88
+ language: 'typescript',
89
+ database: 'postgresql',
90
+ hosting: 'vercel'
91
+ };
92
+
93
+ // Check package.json
94
+ const pkg = utils.getPackageJson(projectRoot);
95
+ if (pkg) {
96
+ detected.name = pkg.name || detected.name;
97
+
98
+ // Detect framework
99
+ if (pkg.dependencies?.next || pkg.devDependencies?.next) {
100
+ detected.framework = 'nextjs';
101
+ } else if (pkg.dependencies?.remix || pkg.devDependencies?.remix) {
102
+ detected.framework = 'remix';
103
+ } else if (pkg.dependencies?.nuxt || pkg.devDependencies?.nuxt) {
104
+ detected.framework = 'nuxt';
105
+ } else if (pkg.dependencies?.['@sveltejs/kit']) {
106
+ detected.framework = 'sveltekit';
107
+ } else if (pkg.dependencies?.express) {
108
+ detected.framework = 'express';
109
+ } else if (pkg.dependencies?.fastify) {
110
+ detected.framework = 'fastify';
111
+ }
112
+
113
+ // Detect database
114
+ if (pkg.dependencies?.['@prisma/client']) {
115
+ detected.database = 'postgresql';
116
+ } else if (pkg.dependencies?.mongoose) {
117
+ detected.database = 'mongodb';
118
+ } else if (pkg.dependencies?.mysql2) {
119
+ detected.database = 'mysql';
120
+ }
121
+ }
122
+
123
+ // Detect TypeScript
124
+ if (utils.fileExists(path.join(projectRoot, 'tsconfig.json'))) {
125
+ detected.language = 'typescript';
126
+ } else {
127
+ detected.language = 'javascript';
128
+ }
129
+
130
+ // Detect Vercel
131
+ if (utils.fileExists(path.join(projectRoot, 'vercel.json'))) {
132
+ detected.hosting = 'vercel';
133
+ } else if (utils.fileExists(path.join(projectRoot, 'netlify.toml'))) {
134
+ detected.hosting = 'netlify';
135
+ } else if (utils.fileExists(path.join(projectRoot, 'fly.toml'))) {
136
+ detected.hosting = 'fly';
137
+ }
138
+
139
+ return detected;
140
+ }
141
+
142
+ /**
143
+ * Generate CLAUDE.md content
144
+ */
145
+ function generateClaudeMd(projectConfig) {
146
+ const date = utils.formatDate();
147
+
148
+ return `# ${projectConfig.project.name} - AI Context
149
+
150
+ **Generated by**: Bootspring v1.0.0
151
+ **Last Updated**: ${date}
152
+ **Documentation**: https://bootspring.com/docs
153
+
154
+ ---
155
+
156
+ ## Project Overview
157
+
158
+ ${projectConfig.project.description || 'A project scaffolded with Bootspring.'}
159
+
160
+ ---
161
+
162
+ ## Tech Stack
163
+
164
+ - **Framework**: ${projectConfig.stack.framework}
165
+ - **Language**: ${projectConfig.stack.language}
166
+ - **Database**: ${projectConfig.stack.database}
167
+ - **Hosting**: ${projectConfig.stack.hosting}
168
+
169
+ ---
170
+
171
+ ## Bootspring Commands
172
+
173
+ Use these commands with your AI assistant:
174
+
175
+ | Command | Description |
176
+ |---------|-------------|
177
+ | \`bootspring todo add "task"\` | Add a new todo item |
178
+ | \`bootspring todo list\` | List all todos |
179
+ | \`bootspring todo done <id>\` | Mark todo as complete |
180
+ | \`bootspring agent list\` | List available agents |
181
+ | \`bootspring agent invoke <name>\` | Get specialized help |
182
+ | \`bootspring skill search <query>\` | Find code patterns |
183
+ | \`bootspring dashboard\` | Start real-time dashboard |
184
+ | \`bootspring quality pre-commit\` | Run quality checks |
185
+
186
+ ---
187
+
188
+ ## Enabled Plugins
189
+
190
+ ${Object.entries(projectConfig.plugins)
191
+ .filter(([_, p]) => p.enabled !== false)
192
+ .map(([name, plugin]) => `### ${name.charAt(0).toUpperCase() + name.slice(1)}
193
+ - Provider: ${plugin.provider || 'default'}
194
+ - Features: ${(plugin.features || []).join(', ') || 'default'}`)
195
+ .join('\n\n')}
196
+
197
+ ---
198
+
199
+ ## Development Workflow
200
+
201
+ 1. **Start dashboard**: \`bootspring dashboard\` for real-time visibility
202
+ 2. **Track work**: Use \`bootspring todo\` to manage tasks
203
+ 3. **Get help**: Invoke agents for specialized expertise
204
+ 4. **Quality**: Run \`bootspring quality pre-commit\` before committing
205
+
206
+ ---
207
+
208
+ ## Custom Instructions
209
+
210
+ - Use Server Components by default (Next.js)
211
+ - Prefer Server Actions over API routes for mutations
212
+ - Use Zod for all input validation
213
+ - Follow existing file naming conventions
214
+ - Keep components small and focused
215
+ - Write tests for new features
216
+ - Never expose API keys to client-side code
217
+
218
+ ---
219
+
220
+ *Generated by [Bootspring](https://bootspring.com) - Development scaffolding with intelligence*
221
+ `;
222
+ }
223
+
224
+ /**
225
+ * Generate todo.md content
226
+ */
227
+ function generateTodoMd(projectName) {
228
+ const date = utils.formatDate();
229
+
230
+ return `# ${projectName} - Todo List
231
+
232
+ > Last updated: ${date}
233
+
234
+ ## In Progress
235
+
236
+ - [ ] Complete project setup
237
+
238
+ ## Pending
239
+
240
+ - [ ] Configure environment variables
241
+ - [ ] Set up database schema
242
+ - [ ] Implement core features
243
+
244
+ ## Completed
245
+
246
+ `;
247
+ }
248
+
249
+ /**
250
+ * Run init command
251
+ */
252
+ async function run(args) {
253
+ const parsedArgs = utils.parseArgs(args);
254
+ const force = parsedArgs.force || parsedArgs.f;
255
+ const quick = parsedArgs.quick || parsedArgs.q;
256
+ const projectRoot = config.findProjectRoot();
257
+
258
+ console.log(`
259
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Init${utils.COLORS.reset}
260
+ ${utils.COLORS.dim}Development scaffolding with intelligence${utils.COLORS.reset}
261
+ `);
262
+
263
+ // Check if already initialized
264
+ const existingConfig = config.findConfigFile(projectRoot);
265
+ if (existingConfig && !force) {
266
+ utils.print.warning(`Project already initialized at ${projectRoot}`);
267
+ utils.print.dim(`Use --force to reinitialize`);
268
+ return;
269
+ }
270
+
271
+ // Detect existing project settings
272
+ const detected = detectProject(projectRoot);
273
+ utils.print.info(`Detected project: ${detected.name}`);
274
+ utils.print.dim(`Root: ${projectRoot}`);
275
+
276
+ let projectConfig;
277
+
278
+ if (quick) {
279
+ // Quick mode - use detected values
280
+ utils.print.info('Using detected settings (quick mode)');
281
+ projectConfig = {
282
+ project: {
283
+ name: detected.name,
284
+ description: '',
285
+ version: '1.0.0'
286
+ },
287
+ stack: {
288
+ framework: detected.framework,
289
+ language: detected.language,
290
+ database: detected.database,
291
+ hosting: detected.hosting
292
+ },
293
+ plugins: {
294
+ auth: { enabled: false, provider: 'clerk' },
295
+ payments: { enabled: false, provider: 'stripe' },
296
+ database: { enabled: detected.database !== 'none', provider: 'prisma' },
297
+ testing: { enabled: true, provider: 'vitest' },
298
+ security: { enabled: true },
299
+ ai: { enabled: false, provider: 'anthropic' }
300
+ },
301
+ dashboard: { port: 3456, autoOpen: false },
302
+ quality: { preCommit: true, prePush: false, strictMode: false },
303
+ paths: { context: 'CLAUDE.md', config: 'bootspring.config.js', todo: 'todo.md' }
304
+ };
305
+ } else {
306
+ // Interactive mode
307
+ const rl = createPrompt();
308
+
309
+ console.log(`\n${utils.COLORS.bold}Project Configuration${utils.COLORS.reset}`);
310
+
311
+ const name = await ask(rl, 'Project name', detected.name);
312
+ const description = await ask(rl, 'Description', '');
313
+ const framework = await askChoice(rl, 'Framework:', FRAMEWORKS, FRAMEWORKS.indexOf(detected.framework));
314
+ const language = await askChoice(rl, 'Language:', LANGUAGES, LANGUAGES.indexOf(detected.language));
315
+ const database = await askChoice(rl, 'Database:', DATABASES, DATABASES.indexOf(detected.database));
316
+ const hosting = await askChoice(rl, 'Hosting:', HOSTINGS, HOSTINGS.indexOf(detected.hosting));
317
+
318
+ console.log(`\n${utils.COLORS.bold}Plugins${utils.COLORS.reset}`);
319
+
320
+ const enableAuth = await askYesNo(rl, 'Enable auth plugin?', false);
321
+ const enablePayments = await askYesNo(rl, 'Enable payments plugin?', false);
322
+ const enableTesting = await askYesNo(rl, 'Enable testing plugin?', true);
323
+ const enableAI = await askYesNo(rl, 'Enable AI plugin?', false);
324
+
325
+ rl.close();
326
+
327
+ projectConfig = {
328
+ project: { name, description, version: '1.0.0' },
329
+ stack: { framework, language, database, hosting },
330
+ plugins: {
331
+ auth: { enabled: enableAuth, provider: 'clerk' },
332
+ payments: { enabled: enablePayments, provider: 'stripe' },
333
+ database: { enabled: database !== 'none', provider: 'prisma' },
334
+ testing: { enabled: enableTesting, provider: 'vitest' },
335
+ security: { enabled: true },
336
+ ai: { enabled: enableAI, provider: 'anthropic' }
337
+ },
338
+ dashboard: { port: 3456, autoOpen: false },
339
+ quality: { preCommit: true, prePush: false, strictMode: false },
340
+ paths: { context: 'CLAUDE.md', config: 'bootspring.config.js', todo: 'todo.md' }
341
+ };
342
+ }
343
+
344
+ // Create files
345
+ console.log(`\n${utils.COLORS.bold}Creating files...${utils.COLORS.reset}\n`);
346
+
347
+ // 1. bootspring.config.js
348
+ const configPath = path.join(projectRoot, 'bootspring.config.js');
349
+ const configSpinner = utils.createSpinner('Creating bootspring.config.js').start();
350
+ if (config.save(projectConfig, configPath)) {
351
+ configSpinner.succeed('Created bootspring.config.js');
352
+ } else {
353
+ configSpinner.fail('Failed to create bootspring.config.js');
354
+ }
355
+
356
+ // 2. CLAUDE.md
357
+ const claudePath = path.join(projectRoot, 'CLAUDE.md');
358
+ const claudeSpinner = utils.createSpinner('Creating CLAUDE.md').start();
359
+ if (utils.writeFile(claudePath, generateClaudeMd(projectConfig))) {
360
+ claudeSpinner.succeed('Created CLAUDE.md');
361
+ } else {
362
+ claudeSpinner.fail('Failed to create CLAUDE.md');
363
+ }
364
+
365
+ // 3. todo.md (if not exists)
366
+ const todoPath = path.join(projectRoot, 'todo.md');
367
+ if (!utils.fileExists(todoPath)) {
368
+ const todoSpinner = utils.createSpinner('Creating todo.md').start();
369
+ if (utils.writeFile(todoPath, generateTodoMd(projectConfig.project.name))) {
370
+ todoSpinner.succeed('Created todo.md');
371
+ } else {
372
+ todoSpinner.fail('Failed to create todo.md');
373
+ }
374
+ }
375
+
376
+ // 4. .mcp.json for Claude Code
377
+ const mcpPath = path.join(projectRoot, '.mcp.json');
378
+ if (!utils.fileExists(mcpPath)) {
379
+ const mcpSpinner = utils.createSpinner('Creating .mcp.json').start();
380
+ const mcpConfig = {
381
+ mcpServers: {
382
+ bootspring: {
383
+ command: 'npx',
384
+ args: ['bootspring', 'mcp'],
385
+ env: {}
386
+ }
387
+ }
388
+ };
389
+ if (utils.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2))) {
390
+ mcpSpinner.succeed('Created .mcp.json (MCP server config)');
391
+ } else {
392
+ mcpSpinner.fail('Failed to create .mcp.json');
393
+ }
394
+ }
395
+
396
+ // Success message
397
+ console.log(`
398
+ ${utils.COLORS.green}${utils.COLORS.bold}✓ Bootspring initialized successfully!${utils.COLORS.reset}
399
+
400
+ ${utils.COLORS.bold}Next steps:${utils.COLORS.reset}
401
+
402
+ 1. Review ${utils.COLORS.cyan}bootspring.config.js${utils.COLORS.reset} and customize as needed
403
+ 2. Start the dashboard: ${utils.COLORS.cyan}bootspring dashboard${utils.COLORS.reset}
404
+ 3. Add your first todo: ${utils.COLORS.cyan}bootspring todo add "Your first task"${utils.COLORS.reset}
405
+
406
+ ${utils.COLORS.dim}Documentation: https://bootspring.com/docs${utils.COLORS.reset}
407
+ `);
408
+ }
409
+
410
+ module.exports = { run };