@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/loop.js ADDED
@@ -0,0 +1,421 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Bootspring Loop CLI
5
+ *
6
+ * Autonomous task execution loop - spawns fresh AI instances
7
+ * iteratively until all PRD stories are complete.
8
+ *
9
+ * @package bootspring
10
+ * @module cli/loop
11
+ */
12
+
13
+ const { spawn, execSync } = require('child_process');
14
+ const path = require('path');
15
+ const fs = require('fs');
16
+ const prd = require('../intelligence/prd');
17
+
18
+ // Colors
19
+ const c = {
20
+ reset: '\x1b[0m',
21
+ bold: '\x1b[1m',
22
+ dim: '\x1b[2m',
23
+ green: '\x1b[32m',
24
+ blue: '\x1b[34m',
25
+ yellow: '\x1b[33m',
26
+ cyan: '\x1b[36m',
27
+ red: '\x1b[31m'
28
+ };
29
+
30
+ /**
31
+ * Check if a tool is available
32
+ */
33
+ function toolAvailable(tool) {
34
+ try {
35
+ execSync(`which ${tool}`, { stdio: 'ignore' });
36
+ return true;
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Detect available AI tool
44
+ */
45
+ function detectTool() {
46
+ if (toolAvailable('claude')) return 'claude';
47
+ if (toolAvailable('amp')) return 'amp';
48
+ return null;
49
+ }
50
+
51
+ /**
52
+ * Run the loop via shell script
53
+ */
54
+ function runLoop(options = {}) {
55
+ const scriptPath = path.join(__dirname, '..', 'scripts', 'loop.sh');
56
+
57
+ if (!fs.existsSync(scriptPath)) {
58
+ console.error(`${c.red}Loop script not found: ${scriptPath}${c.reset}`);
59
+ process.exit(1);
60
+ }
61
+
62
+ const args = [
63
+ options.iterations || '10',
64
+ '--tool', options.tool || 'claude'
65
+ ];
66
+
67
+ if (options.prd) {
68
+ args.push('--prd', options.prd);
69
+ }
70
+
71
+ console.log(`${c.cyan}Starting autonomous loop...${c.reset}`);
72
+ console.log(`${c.dim}Tool: ${options.tool || 'claude'} | Iterations: ${options.iterations || 10}${c.reset}\n`);
73
+
74
+ const child = spawn('bash', [scriptPath, ...args], {
75
+ stdio: 'inherit',
76
+ cwd: process.cwd()
77
+ });
78
+
79
+ child.on('close', (code) => {
80
+ process.exit(code);
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Create a new PRD from template or markdown
86
+ */
87
+ function createPRD(name, options = {}) {
88
+ const prdDir = prd.DEFAULT_PRD_DIR;
89
+
90
+ if (!fs.existsSync(prdDir)) {
91
+ fs.mkdirSync(prdDir, { recursive: true });
92
+ }
93
+
94
+ // Check if markdown file provided
95
+ if (options.from && fs.existsSync(options.from)) {
96
+ const markdown = fs.readFileSync(options.from, 'utf-8');
97
+ const parsed = prd.parseMarkdownPRD(markdown);
98
+ parsed.name = name || parsed.name;
99
+
100
+ const outPath = prd.savePRD(parsed);
101
+ console.log(`${c.green}Created PRD from markdown: ${outPath}${c.reset}`);
102
+ console.log(`Stories: ${parsed.stories.length}`);
103
+ return;
104
+ }
105
+
106
+ // Interactive template
107
+ const template = prd.createPRD(
108
+ name || 'new-feature',
109
+ 'Describe your feature here',
110
+ [
111
+ {
112
+ title: 'Setup and configuration',
113
+ description: 'Initial setup required for the feature',
114
+ acceptance: ['Configuration file created', 'Dependencies installed']
115
+ },
116
+ {
117
+ title: 'Core implementation',
118
+ description: 'Main functionality implementation',
119
+ acceptance: ['Feature works as specified', 'Tests pass']
120
+ },
121
+ {
122
+ title: 'Documentation and cleanup',
123
+ description: 'Final polish and documentation',
124
+ acceptance: ['README updated', 'No lint errors']
125
+ }
126
+ ]
127
+ );
128
+
129
+ const outPath = prd.savePRD(template);
130
+ console.log(`${c.green}Created PRD template: ${outPath}${c.reset}`);
131
+ console.log(`${c.dim}Edit the file to define your stories, then run: bootspring loop start${c.reset}`);
132
+ }
133
+
134
+ /**
135
+ * Show PRD status
136
+ */
137
+ function showStatus(prdPath) {
138
+ const filePath = prdPath || path.join(prd.DEFAULT_PRD_DIR, prd.DEFAULT_PRD_FILE);
139
+ const data = prd.loadPRD(filePath);
140
+
141
+ if (!data) {
142
+ console.log(`${c.yellow}No PRD found at ${filePath}${c.reset}`);
143
+ console.log(`Create one with: bootspring loop prd <name>`);
144
+ return;
145
+ }
146
+
147
+ const progress = prd.getProgress(data);
148
+
149
+ console.log(`\n${c.cyan}+--------------------------------------------------------+${c.reset}`);
150
+ console.log(`${c.cyan}|${c.reset}${c.bold} PRD: ${data.name.padEnd(47)}${c.reset}${c.cyan}|${c.reset}`);
151
+ console.log(`${c.cyan}+--------------------------------------------------------+${c.reset}\n`);
152
+
153
+ // Progress bar
154
+ const barWidth = 40;
155
+ const filled = Math.round((progress.percent / 100) * barWidth);
156
+ const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
157
+ console.log(` Progress: [${c.green}${bar}${c.reset}] ${progress.percent}%`);
158
+ console.log(` Complete: ${progress.complete}/${progress.total} | Pending: ${progress.pending} | Blocked: ${progress.blocked}\n`);
159
+
160
+ // Stories
161
+ console.log(`${c.bold}Stories:${c.reset}\n`);
162
+
163
+ for (const story of data.stories) {
164
+ let icon, color;
165
+ switch (story.status) {
166
+ case 'complete':
167
+ icon = '✓';
168
+ color = c.green;
169
+ break;
170
+ case 'blocked':
171
+ icon = '!';
172
+ color = c.red;
173
+ break;
174
+ case 'in_progress':
175
+ icon = '→';
176
+ color = c.yellow;
177
+ break;
178
+ default:
179
+ icon = ' ';
180
+ color = c.dim;
181
+ }
182
+
183
+ console.log(` ${color}[${icon}]${c.reset} ${story.title}`);
184
+ if (story.status === 'blocked') {
185
+ console.log(` ${c.red}Blocked${c.reset}`);
186
+ }
187
+ }
188
+
189
+ // Next up
190
+ const next = prd.getNextStory(data);
191
+ if (next) {
192
+ console.log(`\n${c.bold}Next:${c.reset} ${next.title}`);
193
+ } else if (progress.percent === 100) {
194
+ console.log(`\n${c.green}All stories complete!${c.reset}`);
195
+ }
196
+
197
+ console.log('');
198
+ }
199
+
200
+ /**
201
+ * Generate PRD skill for Claude Code
202
+ */
203
+ function generateSkill() {
204
+ const skillDir = path.join(__dirname, '..', '.claude-plugin', 'skills');
205
+
206
+ if (!fs.existsSync(skillDir)) {
207
+ fs.mkdirSync(skillDir, { recursive: true });
208
+ }
209
+
210
+ // PRD skill
211
+ const prdSkill = `# /prd - Generate Product Requirements Document
212
+
213
+ Generate a detailed PRD with right-sized user stories for autonomous execution.
214
+
215
+ ## Instructions
216
+
217
+ When the user invokes /prd <feature-name>:
218
+
219
+ 1. Ask clarifying questions about the feature
220
+ 2. Generate a detailed PRD with 3-7 user stories
221
+ 3. Each story should be:
222
+ - Completable in a single AI context window
223
+ - Have clear acceptance criteria
224
+ - Be independently testable
225
+
226
+ ## Output Format
227
+
228
+ Create a file at \`tasks/prd-<feature-name>.md\` with this structure:
229
+
230
+ \`\`\`markdown
231
+ # <Feature Name>
232
+
233
+ <Brief description>
234
+
235
+ ## Story 1: <Title>
236
+
237
+ <Description of what needs to be done>
238
+
239
+ ### Acceptance Criteria
240
+ - [ ] Criteria 1
241
+ - [ ] Criteria 2
242
+
243
+ ## Story 2: <Title>
244
+ ...
245
+ \`\`\`
246
+
247
+ ## Right-Sizing Guidelines
248
+
249
+ Stories should be small enough to complete in one session:
250
+ - Adding a database column + migration
251
+ - Creating a single API endpoint
252
+ - Building one UI component
253
+ - Writing tests for one module
254
+
255
+ Stories that are TOO LARGE:
256
+ - "Build the authentication system"
257
+ - "Implement payment processing"
258
+ - "Create the admin dashboard"
259
+
260
+ Break large features into multiple stories.
261
+
262
+ ## After Generation
263
+
264
+ Tell the user:
265
+ 1. Review the PRD in \`tasks/prd-<feature-name>.md\`
266
+ 2. Convert to JSON: \`bootspring loop prd --from tasks/prd-<feature-name>.md\`
267
+ 3. Start the loop: \`bootspring loop start\`
268
+ `;
269
+
270
+ fs.writeFileSync(path.join(skillDir, 'prd.md'), prdSkill);
271
+
272
+ // Loop skill
273
+ const loopSkill = `# /loop - Autonomous Task Loop
274
+
275
+ Start an autonomous execution loop that iterates through PRD stories.
276
+
277
+ ## Prerequisites
278
+
279
+ - A \`tasks/prd.json\` file with defined stories
280
+ - Either \`claude\` or \`amp\` CLI installed
281
+
282
+ ## Usage
283
+
284
+ /loop [iterations] [--tool claude|amp]
285
+
286
+ ## What Happens
287
+
288
+ 1. The loop reads the next incomplete story from \`tasks/prd.json\`
289
+ 2. A fresh AI instance works on that single story
290
+ 3. Quality gates run (tests, lint, typecheck)
291
+ 4. On success: commit + mark story complete
292
+ 5. Repeat until all stories done or max iterations reached
293
+
294
+ ## Memory Model
295
+
296
+ Context persists through:
297
+ - Git commits (what changed)
298
+ - CLAUDE.md (project knowledge)
299
+ - prd.json (task status)
300
+
301
+ Each iteration starts with fresh context to avoid degradation.
302
+
303
+ ## Commands
304
+
305
+ \`\`\`bash
306
+ bootspring loop start # Start the loop
307
+ bootspring loop status # Check PRD progress
308
+ bootspring loop prd <name> # Create new PRD
309
+ \`\`\`
310
+ `;
311
+
312
+ fs.writeFileSync(path.join(skillDir, 'loop.md'), loopSkill);
313
+
314
+ // Plugin manifest
315
+ const manifest = {
316
+ name: 'bootspring',
317
+ version: '1.0.0',
318
+ description: 'Intelligent scaffolding and autonomous task execution',
319
+ skills: ['prd', 'loop']
320
+ };
321
+
322
+ const manifestPath = path.join(__dirname, '..', '.claude-plugin', 'manifest.json');
323
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
324
+
325
+ console.log(`${c.green}Generated Claude Code plugin:${c.reset}`);
326
+ console.log(` .claude-plugin/manifest.json`);
327
+ console.log(` .claude-plugin/skills/prd.md`);
328
+ console.log(` .claude-plugin/skills/loop.md`);
329
+ console.log(`\n${c.dim}Users can install with: /plugin add bootspring${c.reset}`);
330
+ }
331
+
332
+ /**
333
+ * Show help
334
+ */
335
+ function showHelp() {
336
+ console.log(`
337
+ ${c.bold}Bootspring Autonomous Loop${c.reset}
338
+
339
+ ${c.cyan}Usage:${c.reset}
340
+ bootspring loop <command> [options]
341
+
342
+ ${c.cyan}Commands:${c.reset}
343
+ start [n] [--tool] Start loop (n iterations, default 10)
344
+ status Show PRD progress
345
+ prd <name> Create new PRD template
346
+ prd --from <file> Create PRD from markdown
347
+ skill Generate Claude Code plugin skills
348
+
349
+ ${c.cyan}Options:${c.reset}
350
+ --tool <claude|amp> AI tool to use (default: claude)
351
+ --prd <path> Path to prd.json
352
+
353
+ ${c.cyan}Examples:${c.reset}
354
+ bootspring loop prd user-auth
355
+ bootspring loop start 20 --tool claude
356
+ bootspring loop status
357
+
358
+ ${c.cyan}Workflow:${c.reset}
359
+ 1. Create PRD: bootspring loop prd my-feature
360
+ 2. Edit stories: Edit tasks/prd.json
361
+ 3. Start loop: bootspring loop start
362
+ 4. Monitor: bootspring loop status
363
+ `);
364
+ }
365
+
366
+ /**
367
+ * Main CLI handler
368
+ */
369
+ function main(args) {
370
+ const command = args[0] || 'help';
371
+
372
+ switch (command) {
373
+ case 'start': {
374
+ const tool = detectTool();
375
+ if (!tool) {
376
+ console.error(`${c.red}No AI tool found. Install claude or amp CLI.${c.reset}`);
377
+ process.exit(1);
378
+ }
379
+
380
+ const iterations = args.find(a => /^\d+$/.test(a)) || '10';
381
+ const toolArg = args.includes('--tool') ?
382
+ args[args.indexOf('--tool') + 1] : tool;
383
+ const prdArg = args.includes('--prd') ?
384
+ args[args.indexOf('--prd') + 1] : null;
385
+
386
+ runLoop({ iterations, tool: toolArg, prd: prdArg });
387
+ break;
388
+ }
389
+
390
+ case 'status':
391
+ showStatus(args[1]);
392
+ break;
393
+
394
+ case 'prd': {
395
+ // Skip the 'prd' command itself, find the feature name
396
+ const prdArgs = args.slice(1);
397
+ const name = prdArgs.find(a => !a.startsWith('--'));
398
+ const fromFile = prdArgs.includes('--from') ?
399
+ prdArgs[prdArgs.indexOf('--from') + 1] : null;
400
+
401
+ createPRD(name, { from: fromFile });
402
+ break;
403
+ }
404
+
405
+ case 'skill':
406
+ case 'skills':
407
+ generateSkill();
408
+ break;
409
+
410
+ case 'help':
411
+ default:
412
+ showHelp();
413
+ }
414
+ }
415
+
416
+ // CLI execution
417
+ if (require.main === module) {
418
+ main(process.argv.slice(2));
419
+ }
420
+
421
+ module.exports = { main, runLoop, createPRD, showStatus };
package/cli/mcp.js ADDED
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Bootspring MCP Command
3
+ * Control the MCP server
4
+ *
5
+ * @package bootspring
6
+ * @command mcp
7
+ */
8
+
9
+ const { spawn } = require('child_process');
10
+ const path = require('path');
11
+ const config = require('../core/config');
12
+ const utils = require('../core/utils');
13
+
14
+ /**
15
+ * Start MCP server (for direct invocation by Claude Code)
16
+ */
17
+ function startServer() {
18
+ // When called directly by MCP, just require the server module
19
+ // This allows Claude Code to invoke it via stdio
20
+ require('../mcp/server.js');
21
+ }
22
+
23
+ /**
24
+ * Show MCP status and configuration info
25
+ */
26
+ function showStatus() {
27
+ const cfg = config.load();
28
+
29
+ console.log(`
30
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring MCP Server${utils.COLORS.reset}
31
+ ${utils.COLORS.dim}Model Context Protocol integration${utils.COLORS.reset}
32
+
33
+ ${utils.COLORS.bold}Status${utils.COLORS.reset}
34
+ The MCP server runs on-demand when Claude Code invokes it.
35
+ It does not run as a persistent background service.
36
+
37
+ ${utils.COLORS.bold}Configuration${utils.COLORS.reset}
38
+ Project Root: ${cfg._projectRoot}
39
+ Config File: ${cfg._configPath || 'not found'}
40
+
41
+ ${utils.COLORS.bold}Available Tools${utils.COLORS.reset}
42
+ ${utils.COLORS.cyan}bootspring_context${utils.COLORS.reset} - Show/validate project context
43
+ ${utils.COLORS.cyan}bootspring_agent${utils.COLORS.reset} - Work with specialized agents
44
+ ${utils.COLORS.cyan}bootspring_todo${utils.COLORS.reset} - Manage todo items
45
+ ${utils.COLORS.cyan}bootspring_skill${utils.COLORS.reset} - Search code patterns
46
+ ${utils.COLORS.cyan}bootspring_quality${utils.COLORS.reset} - Run quality gates
47
+ ${utils.COLORS.cyan}bootspring_generate${utils.COLORS.reset} - Regenerate context
48
+ ${utils.COLORS.cyan}bootspring_plugin${utils.COLORS.reset} - Manage plugins
49
+ ${utils.COLORS.cyan}bootspring_dashboard${utils.COLORS.reset} - Dashboard info
50
+
51
+ ${utils.COLORS.bold}Resources${utils.COLORS.reset}
52
+ ${utils.COLORS.dim}bootspring://context/project${utils.COLORS.reset} - Project context JSON
53
+ ${utils.COLORS.dim}bootspring://context/claude.md${utils.COLORS.reset} - Generated AI context
54
+ ${utils.COLORS.dim}bootspring://context/todo.md${utils.COLORS.reset} - Todo list
55
+ ${utils.COLORS.dim}bootspring://agents/list${utils.COLORS.reset} - Available agents
56
+
57
+ ${utils.COLORS.bold}Setup${utils.COLORS.reset}
58
+ Ensure .mcp.json exists with:
59
+ ${utils.COLORS.dim}{
60
+ "mcpServers": {
61
+ "bootspring": {
62
+ "command": "npx",
63
+ "args": ["bootspring", "mcp"],
64
+ "env": {}
65
+ }
66
+ }
67
+ }${utils.COLORS.reset}
68
+
69
+ ${utils.COLORS.bold}Test${utils.COLORS.reset}
70
+ Run: ${utils.COLORS.cyan}bootspring mcp test${utils.COLORS.reset}
71
+ `);
72
+ }
73
+
74
+ /**
75
+ * Test MCP tools
76
+ */
77
+ async function testMcp() {
78
+ console.log(`
79
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring MCP Test${utils.COLORS.reset}
80
+ `);
81
+
82
+ const config = require('../core/config');
83
+ const context = require('../core/context');
84
+
85
+ // Test config loading
86
+ const spinner1 = utils.createSpinner('Testing config loader').start();
87
+ try {
88
+ const cfg = config.load();
89
+ if (cfg.project) {
90
+ spinner1.succeed(`Config loaded: ${cfg.project.name}`);
91
+ } else {
92
+ spinner1.warn('Config loaded but missing project info');
93
+ }
94
+ } catch (error) {
95
+ spinner1.fail(`Config error: ${error.message}`);
96
+ }
97
+
98
+ // Test context
99
+ const spinner2 = utils.createSpinner('Testing context detector').start();
100
+ try {
101
+ const cfg = config.load();
102
+ const ctx = context.get({ config: cfg });
103
+ spinner2.succeed(`Context loaded: phase=${ctx.state.phase}, health=${ctx.state.health}`);
104
+ } catch (error) {
105
+ spinner2.fail(`Context error: ${error.message}`);
106
+ }
107
+
108
+ // Test hooks
109
+ const spinner3 = utils.createSpinner('Testing context detection hooks').start();
110
+ try {
111
+ const detector = require('../hooks/context-detector');
112
+ const result = detector.detectContext('implement user authentication with Clerk');
113
+ if (result.matches.length > 0) {
114
+ spinner3.succeed(`Detection works: found ${result.matches.length} matches (${result.suggestedAgents.join(', ')})`);
115
+ } else {
116
+ spinner3.warn('Detection works but found no matches');
117
+ }
118
+ } catch (error) {
119
+ spinner3.fail(`Detection error: ${error.message}`);
120
+ }
121
+
122
+ // Test prompt enhancer
123
+ const spinner4 = utils.createSpinner('Testing prompt enhancer').start();
124
+ try {
125
+ const detector = require('../hooks/context-detector');
126
+ const enhancer = require('../hooks/prompt-enhancer');
127
+ const detection = detector.detectContext('create a database schema for users');
128
+ const enhancement = enhancer.enhance('create a database schema', detection, {});
129
+ if (enhancement) {
130
+ spinner4.succeed(`Enhancer works: category=${enhancement.category}`);
131
+ } else {
132
+ spinner4.warn('Enhancer works but produced no enhancement');
133
+ }
134
+ } catch (error) {
135
+ spinner4.fail(`Enhancer error: ${error.message}`);
136
+ }
137
+
138
+ console.log(`
139
+ ${utils.COLORS.bold}Summary${utils.COLORS.reset}
140
+ All core MCP components are functional.
141
+ The server will work when invoked by Claude Code.
142
+
143
+ ${utils.COLORS.dim}Tip: Use the tools via Claude Code for full integration testing${utils.COLORS.reset}
144
+ `);
145
+ }
146
+
147
+ /**
148
+ * Generate .mcp.json configuration
149
+ */
150
+ function generateConfig() {
151
+ const cfg = config.load();
152
+ const mcpPath = path.join(cfg._projectRoot, '.mcp.json');
153
+
154
+ const mcpConfig = {
155
+ mcpServers: {
156
+ bootspring: {
157
+ command: 'npx',
158
+ args: ['bootspring', 'mcp'],
159
+ env: {}
160
+ }
161
+ }
162
+ };
163
+
164
+ const spinner = utils.createSpinner('Generating .mcp.json').start();
165
+
166
+ if (utils.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2))) {
167
+ spinner.succeed(`Created ${mcpPath}`);
168
+ console.log(`
169
+ ${utils.COLORS.dim}Contents:${utils.COLORS.reset}
170
+ ${JSON.stringify(mcpConfig, null, 2)}
171
+ `);
172
+ } else {
173
+ spinner.fail('Failed to create .mcp.json');
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Show MCP help
179
+ */
180
+ function showHelp() {
181
+ console.log(`
182
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring MCP${utils.COLORS.reset}
183
+ ${utils.COLORS.dim}Model Context Protocol server control${utils.COLORS.reset}
184
+
185
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
186
+ bootspring mcp [command]
187
+
188
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
189
+ ${utils.COLORS.cyan}(default)${utils.COLORS.reset} Start MCP server (used by Claude Code)
190
+ ${utils.COLORS.cyan}status${utils.COLORS.reset} Show MCP configuration and tools
191
+ ${utils.COLORS.cyan}test${utils.COLORS.reset} Test MCP components
192
+ ${utils.COLORS.cyan}config${utils.COLORS.reset} Generate .mcp.json file
193
+ ${utils.COLORS.cyan}help${utils.COLORS.reset} Show this help
194
+
195
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
196
+ bootspring mcp status # Check configuration
197
+ bootspring mcp test # Test components
198
+ bootspring mcp config # Generate .mcp.json
199
+ `);
200
+ }
201
+
202
+ /**
203
+ * Run MCP command
204
+ */
205
+ async function run(args) {
206
+ const subcommand = args[0];
207
+
208
+ // Default: start the MCP server (for Claude Code invocation)
209
+ if (!subcommand) {
210
+ startServer();
211
+ return;
212
+ }
213
+
214
+ switch (subcommand) {
215
+ case 'status':
216
+ showStatus();
217
+ break;
218
+
219
+ case 'test':
220
+ await testMcp();
221
+ break;
222
+
223
+ case 'config':
224
+ case 'init':
225
+ case 'setup':
226
+ generateConfig();
227
+ break;
228
+
229
+ case 'help':
230
+ case '-h':
231
+ case '--help':
232
+ showHelp();
233
+ break;
234
+
235
+ default:
236
+ utils.print.error(`Unknown subcommand: ${subcommand}`);
237
+ showHelp();
238
+ }
239
+ }
240
+
241
+ module.exports = { run, startServer, showStatus, testMcp };