@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/mcp/server.js ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Bootspring MCP Server
5
+ * Model Context Protocol server for AI assistant integration
6
+ *
7
+ * @package bootspring
8
+ * @module mcp
9
+ */
10
+
11
+ const { TOOLS, RESOURCES, toolHandlers, resourceHandlers, trackTelemetry } = require('./registry');
12
+
13
+ /**
14
+ * Create and start the MCP server
15
+ */
16
+ async function main() {
17
+ const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
18
+ const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
19
+ const {
20
+ CallToolRequestSchema,
21
+ ListToolsRequestSchema,
22
+ ListResourcesRequestSchema,
23
+ ReadResourceRequestSchema
24
+ } = require('@modelcontextprotocol/sdk/types.js');
25
+
26
+ const server = new Server(
27
+ {
28
+ name: 'bootspring',
29
+ version: '1.1.0'
30
+ },
31
+ {
32
+ capabilities: {
33
+ tools: {},
34
+ resources: {}
35
+ }
36
+ }
37
+ );
38
+
39
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
40
+ return { tools: TOOLS };
41
+ });
42
+
43
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
44
+ const { name, arguments: args } = request.params;
45
+
46
+ const handler = toolHandlers[name];
47
+ if (!handler) {
48
+ throw new Error(`Unknown tool: ${name}`);
49
+ }
50
+
51
+ try {
52
+ return await handler(args || {});
53
+ } catch (error) {
54
+ return {
55
+ content: [{
56
+ type: 'text',
57
+ text: `Error: ${error.message}`
58
+ }],
59
+ isError: true
60
+ };
61
+ }
62
+ });
63
+
64
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
65
+ return { resources: RESOURCES };
66
+ });
67
+
68
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
69
+ const { uri } = request.params;
70
+
71
+ const handler = resourceHandlers[uri];
72
+ if (!handler) {
73
+ throw new Error(`Unknown resource: ${uri}`);
74
+ }
75
+
76
+ return await handler();
77
+ });
78
+
79
+ const transport = new StdioServerTransport();
80
+ await server.connect(transport);
81
+
82
+ console.error('Bootspring MCP server started');
83
+ }
84
+
85
+ if (require.main === module) {
86
+ main().catch((error) => {
87
+ console.error('Failed to start MCP server:', error);
88
+ process.exit(1);
89
+ });
90
+ }
91
+
92
+ module.exports = {
93
+ TOOLS,
94
+ RESOURCES,
95
+ toolHandlers,
96
+ resourceHandlers,
97
+ trackTelemetry,
98
+ main
99
+ };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * MCP agent tool module
3
+ */
4
+
5
+ function getToolDefinition() {
6
+ return {
7
+ name: 'bootspring_agent',
8
+ description: 'Work with specialized AI agents. List available agents, show details, or invoke for specialized expertise.',
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ action: {
13
+ type: 'string',
14
+ enum: ['list', 'show', 'invoke', 'search'],
15
+ description: 'Action: list agents, show details, invoke agent, or search'
16
+ },
17
+ name: {
18
+ type: 'string',
19
+ description: 'Agent name (e.g., database-expert, security-expert)'
20
+ },
21
+ topic: {
22
+ type: 'string',
23
+ description: 'Topic or question for the agent (when invoking)'
24
+ },
25
+ query: {
26
+ type: 'string',
27
+ description: 'Search query (when searching)'
28
+ },
29
+ includeExternal: {
30
+ type: 'boolean',
31
+ description: 'Include external skills catalog (skills/external) in list/search/show'
32
+ },
33
+ limit: {
34
+ type: 'number',
35
+ description: 'Max number of results for list/search when includeExternal is true'
36
+ }
37
+ },
38
+ required: ['action']
39
+ }
40
+ };
41
+ }
42
+
43
+ function createHandler({ agentModule, format }) {
44
+ return async (args) => {
45
+ const { action, name, topic, query } = args;
46
+
47
+ switch (action) {
48
+ case 'list': {
49
+ const agents = Object.entries(agentModule.AGENTS).map(([id, agent]) => ({
50
+ id,
51
+ name: agent.name,
52
+ category: agent.category,
53
+ description: agent.description
54
+ }));
55
+ return format.list({
56
+ title: 'Available Agents',
57
+ items: agents,
58
+ formatter: (a) => ` 🤖 ${a.id}\n ${a.name} - ${a.description.slice(0, 60)}...`,
59
+ hints: [
60
+ 'Use action=show name="agent-id" to see full details',
61
+ 'Use action=invoke name="agent-id" topic="your question"'
62
+ ]
63
+ });
64
+ }
65
+ case 'show': {
66
+ if (!name) return format.error('Agent name required', ['Provide name="agent-id"']);
67
+ const agent = agentModule.AGENTS[name];
68
+ if (!agent) return format.error(`Agent not found: ${name}`, [
69
+ 'Use action=list to see available agents'
70
+ ]);
71
+ return format.agentDetails(name, agent);
72
+ }
73
+ case 'invoke': {
74
+ if (!name) throw new Error('Agent name required');
75
+ const agent = agentModule.AGENTS[name];
76
+ if (!agent) throw new Error(`Agent not found: ${name}`);
77
+
78
+ const contextText = `
79
+ ## Agent: ${agent.name}
80
+
81
+ You are now acting as the **${agent.name}**, a specialized expert in:
82
+ ${agent.expertise.map(e => `- ${e}`).join('\n')}
83
+
84
+ ### Your Role
85
+ ${agent.description}
86
+
87
+ ### Guidelines
88
+ 1. Focus on your areas of expertise listed above
89
+ 2. Provide specific, actionable advice
90
+ 3. Include code examples when relevant
91
+ 4. Consider security and best practices
92
+ 5. Reference official documentation when helpful
93
+
94
+ ### Topic
95
+ ${topic || 'The user will provide context for your assistance.'}
96
+
97
+ ---
98
+
99
+ Please provide your expert analysis and recommendations.
100
+ `;
101
+ return {
102
+ content: [{
103
+ type: 'text',
104
+ text: contextText
105
+ }]
106
+ };
107
+ }
108
+ case 'search': {
109
+ if (!query) throw new Error('Search query required');
110
+ const queryLower = query.toLowerCase();
111
+ const matches = Object.entries(agentModule.AGENTS)
112
+ .filter(([id, agent]) => {
113
+ return id.includes(queryLower) ||
114
+ agent.name.toLowerCase().includes(queryLower) ||
115
+ agent.description.toLowerCase().includes(queryLower) ||
116
+ agent.expertise.some(e => e.toLowerCase().includes(queryLower)) ||
117
+ agent.triggers.some(t => t.includes(queryLower));
118
+ })
119
+ .map(([id, agent]) => ({ id, name: agent.name, description: agent.description }));
120
+
121
+ return {
122
+ content: [{
123
+ type: 'text',
124
+ text: JSON.stringify(matches, null, 2)
125
+ }]
126
+ };
127
+ }
128
+ default:
129
+ throw new Error(`Unknown action: ${action}`);
130
+ }
131
+ };
132
+ }
133
+
134
+ module.exports = {
135
+ getToolDefinition,
136
+ createHandler
137
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * MCP capabilities tool module
3
+ */
4
+
5
+ function getToolDefinition() {
6
+ return {
7
+ name: 'bootspring_capabilities',
8
+ description: 'Return capability manifest for assistant clients (tools, premium access, workflow packs, telemetry events).',
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ mode: {
13
+ type: 'string',
14
+ enum: ['local', 'server'],
15
+ description: 'Optional access mode override'
16
+ },
17
+ tier: {
18
+ type: 'string',
19
+ description: 'Optional tier override: free, pro, team, enterprise'
20
+ },
21
+ entitled: {
22
+ type: 'boolean',
23
+ description: 'Optional entitlement override'
24
+ },
25
+ client: {
26
+ type: 'string',
27
+ description: 'Optional client label (e.g., claude-code, codex)'
28
+ }
29
+ },
30
+ required: []
31
+ }
32
+ };
33
+ }
34
+
35
+ function createHandler({ capabilities }) {
36
+ return async (args) => {
37
+ const { mode, tier, entitled, client } = args;
38
+ const manifest = capabilities.buildCapabilities({ mode, tier, entitled });
39
+ return {
40
+ content: [{
41
+ type: 'text',
42
+ text: JSON.stringify({
43
+ client: client || 'unspecified',
44
+ ...manifest
45
+ }, null, 2)
46
+ }]
47
+ };
48
+ };
49
+ }
50
+
51
+ module.exports = {
52
+ getToolDefinition,
53
+ createHandler
54
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * MCP context tool module
3
+ */
4
+
5
+ function getToolDefinition() {
6
+ return {
7
+ name: 'bootspring_context',
8
+ description: 'Show or validate the current project context. Use "show" to see project summary, "validate" to check project health.',
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ action: {
13
+ type: 'string',
14
+ enum: ['show', 'validate', 'summary'],
15
+ description: 'Action to perform: show (default), validate, or summary'
16
+ }
17
+ },
18
+ required: []
19
+ }
20
+ };
21
+ }
22
+
23
+ function createHandler({ config, context, format }) {
24
+ return async (args) => {
25
+ const action = args.action || 'show';
26
+ const cfg = config.load();
27
+
28
+ switch (action) {
29
+ case 'show':
30
+ case 'summary': {
31
+ const ctx = context.get({ config: cfg });
32
+ return format.contextSummary(ctx);
33
+ }
34
+ case 'validate': {
35
+ const validation = context.validate({ config: cfg });
36
+ return format.contextValidation(validation);
37
+ }
38
+ default:
39
+ return format.error(`Unknown action: ${action}`, [
40
+ 'Valid actions: show, summary, validate'
41
+ ]);
42
+ }
43
+ };
44
+ }
45
+
46
+ module.exports = {
47
+ getToolDefinition,
48
+ createHandler
49
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * MCP dashboard tool module
3
+ */
4
+
5
+ function getToolDefinition() {
6
+ return {
7
+ name: 'bootspring_dashboard',
8
+ description: 'Get dashboard status or start URL.',
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ action: {
13
+ type: 'string',
14
+ enum: ['status', 'url'],
15
+ description: 'Action: status or url'
16
+ }
17
+ },
18
+ required: []
19
+ }
20
+ };
21
+ }
22
+
23
+ function createHandler({ config }) {
24
+ return async (args) => {
25
+ const action = args.action || 'status';
26
+ const cfg = config.load();
27
+ const port = cfg.dashboard?.port || 3456;
28
+
29
+ switch (action) {
30
+ case 'status':
31
+ return {
32
+ content: [{
33
+ type: 'text',
34
+ text: JSON.stringify({
35
+ status: 'available',
36
+ port,
37
+ url: `http://localhost:${port}`,
38
+ command: 'bootspring dashboard'
39
+ }, null, 2)
40
+ }]
41
+ };
42
+ case 'url':
43
+ return {
44
+ content: [{
45
+ type: 'text',
46
+ text: `http://localhost:${port}`
47
+ }]
48
+ };
49
+ default:
50
+ throw new Error(`Unknown action: ${action}`);
51
+ }
52
+ };
53
+ }
54
+
55
+ module.exports = {
56
+ getToolDefinition,
57
+ createHandler
58
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * MCP generate tool module
3
+ */
4
+
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+
8
+ function getToolDefinition() {
9
+ return {
10
+ name: 'bootspring_generate',
11
+ description: 'Regenerate the CLAUDE.md context file with current project state.',
12
+ inputSchema: {
13
+ type: 'object',
14
+ properties: {
15
+ full: {
16
+ type: 'boolean',
17
+ description: 'Full regeneration including .mcp.json and todo.md'
18
+ }
19
+ },
20
+ required: []
21
+ }
22
+ };
23
+ }
24
+
25
+ function createHandler({ config, context, generateModule }) {
26
+ return async (_args) => {
27
+ const cfg = config.load();
28
+ const ctx = context.get({ config: cfg });
29
+ const claudePath = path.join(cfg._projectRoot, cfg.paths?.context || 'CLAUDE.md');
30
+
31
+ const content = generateModule.generateClaudeMd(cfg, ctx);
32
+ fs.writeFileSync(claudePath, content);
33
+
34
+ return {
35
+ content: [{
36
+ type: 'text',
37
+ text: `Generated CLAUDE.md at ${claudePath}`
38
+ }]
39
+ };
40
+ };
41
+ }
42
+
43
+ module.exports = {
44
+ getToolDefinition,
45
+ createHandler
46
+ };
@@ -0,0 +1,134 @@
1
+ /**
2
+ * MCP loop tool module
3
+ */
4
+
5
+ const path = require('path');
6
+
7
+ function getToolDefinition() {
8
+ return {
9
+ name: 'bootspring_loop',
10
+ description: 'Autonomous task loop management. Create PRDs, check status, manage iterative task execution.',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ action: {
15
+ type: 'string',
16
+ enum: ['status', 'next', 'complete', 'create', 'progress'],
17
+ description: 'Action: status (PRD overview), next (get next story), complete (mark done), create (new PRD), progress (summary)'
18
+ },
19
+ name: {
20
+ type: 'string',
21
+ description: 'PRD or story name (for create/complete actions)'
22
+ },
23
+ storyId: {
24
+ type: 'string',
25
+ description: 'Story ID to mark complete'
26
+ },
27
+ prdPath: {
28
+ type: 'string',
29
+ description: 'Path to prd.json (default: tasks/prd.json)'
30
+ }
31
+ },
32
+ required: ['action']
33
+ }
34
+ };
35
+ }
36
+
37
+ function createHandler({ prdModule, format }) {
38
+ return async (args) => {
39
+ const { action, name, storyId, prdPath } = args;
40
+ const filePath = prdPath || path.join(prdModule.DEFAULT_PRD_DIR, prdModule.DEFAULT_PRD_FILE);
41
+
42
+ switch (action) {
43
+ case 'status':
44
+ case 'progress': {
45
+ const prd = prdModule.loadPRD(filePath);
46
+ if (!prd) {
47
+ return format.success({
48
+ summary: 'No PRD found',
49
+ data: { exists: false },
50
+ hints: [
51
+ 'Create a PRD with action=create name="feature-name"',
52
+ 'PRDs help you track iterative development progress'
53
+ ]
54
+ });
55
+ }
56
+ const progress = prdModule.getProgress(prd);
57
+ return format.loopStatus(prd, progress);
58
+ }
59
+
60
+ case 'next': {
61
+ const prd = prdModule.loadPRD(filePath);
62
+ if (!prd) {
63
+ return format.error('No PRD found', [
64
+ 'Create a PRD first with action=create'
65
+ ]);
66
+ }
67
+ const next = prdModule.getNextStory(prd);
68
+ if (!next) {
69
+ return format.success({
70
+ summary: 'All stories complete! 🎉',
71
+ data: { complete: true },
72
+ hints: ['Create a new PRD for your next feature']
73
+ });
74
+ }
75
+ return format.success({
76
+ summary: `Next Story: ${next.title}`,
77
+ data: next,
78
+ hints: [
79
+ `Mark complete with action=complete storyId="${next.id}"`
80
+ ]
81
+ });
82
+ }
83
+
84
+ case 'complete': {
85
+ if (!storyId) throw new Error('storyId required');
86
+ const prd = prdModule.loadPRD(filePath);
87
+ if (!prd) throw new Error('No PRD found');
88
+
89
+ prdModule.updateStoryStatus(prd, storyId, 'complete');
90
+ prdModule.savePRD(prd, filePath);
91
+
92
+ const progress = prdModule.getProgress(prd);
93
+ return {
94
+ content: [{
95
+ type: 'text',
96
+ text: JSON.stringify({
97
+ completed: storyId,
98
+ progress,
99
+ allComplete: prdModule.isComplete(prd)
100
+ }, null, 2)
101
+ }]
102
+ };
103
+ }
104
+
105
+ case 'create': {
106
+ const prdName = name || 'new-feature';
107
+ const newPrd = prdModule.createPRD(prdName, 'Created via MCP', [
108
+ { title: 'Setup', description: 'Initial setup' },
109
+ { title: 'Implementation', description: 'Core implementation' },
110
+ { title: 'Testing', description: 'Add tests' }
111
+ ]);
112
+ const savedPath = prdModule.savePRD(newPrd, filePath);
113
+ return {
114
+ content: [{
115
+ type: 'text',
116
+ text: JSON.stringify({
117
+ created: savedPath,
118
+ stories: newPrd.stories.length,
119
+ message: 'Edit the PRD to define your stories'
120
+ }, null, 2)
121
+ }]
122
+ };
123
+ }
124
+
125
+ default:
126
+ throw new Error(`Unknown action: ${action}`);
127
+ }
128
+ };
129
+ }
130
+
131
+ module.exports = {
132
+ getToolDefinition,
133
+ createHandler
134
+ };