@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
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Bootspring Quality Module
3
+ * Configurable quality gate system
4
+ *
5
+ * @package bootspring
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ /**
13
+ * Default quality gate definitions
14
+ */
15
+ const DEFAULT_GATES = {
16
+ 'pre-commit': {
17
+ name: 'Pre-Commit',
18
+ description: 'Quick checks before committing code',
19
+ checks: ['typecheck', 'lint', 'format']
20
+ },
21
+ 'pre-push': {
22
+ name: 'Pre-Push',
23
+ description: 'Thorough checks before pushing to remote',
24
+ checks: ['typecheck', 'lint', 'test', 'build']
25
+ },
26
+ 'pre-deploy': {
27
+ name: 'Pre-Deploy',
28
+ description: 'Full audit before deployment',
29
+ checks: ['typecheck', 'lint', 'test', 'build', 'security']
30
+ }
31
+ };
32
+
33
+ /**
34
+ * Check definitions - can detect available tools
35
+ */
36
+ const CHECK_DEFINITIONS = {
37
+ typecheck: {
38
+ name: 'TypeScript',
39
+ description: 'Type checking',
40
+ commands: [
41
+ { tool: 'tsc', command: 'npx tsc --noEmit', detect: 'tsconfig.json' },
42
+ { tool: 'typescript', command: 'npx tsc --noEmit', detect: 'package.json:typescript' }
43
+ ],
44
+ fallback: null // Skip if not available
45
+ },
46
+ lint: {
47
+ name: 'Linting',
48
+ description: 'Code linting',
49
+ commands: [
50
+ { tool: 'eslint', command: 'npx eslint .', detect: 'eslint.config.js' },
51
+ { tool: 'eslint', command: 'npx eslint .', detect: '.eslintrc.js' },
52
+ { tool: 'eslint', command: 'npx eslint .', detect: '.eslintrc.json' },
53
+ { tool: 'biome', command: 'npx biome check .', detect: 'biome.json' }
54
+ ],
55
+ fallback: null
56
+ },
57
+ format: {
58
+ name: 'Formatting',
59
+ description: 'Code formatting check',
60
+ commands: [
61
+ { tool: 'prettier', command: 'npx prettier --check .', detect: '.prettierrc' },
62
+ { tool: 'prettier', command: 'npx prettier --check .', detect: '.prettierrc.json' },
63
+ { tool: 'prettier', command: 'npx prettier --check .', detect: 'prettier.config.js' },
64
+ { tool: 'biome', command: 'npx biome format --check .', detect: 'biome.json' }
65
+ ],
66
+ fallback: null
67
+ },
68
+ test: {
69
+ name: 'Tests',
70
+ description: 'Running tests',
71
+ commands: [
72
+ { tool: 'jest', command: 'npm test', detect: 'jest.config.js' },
73
+ { tool: 'vitest', command: 'npm test', detect: 'vitest.config.ts' },
74
+ { tool: 'mocha', command: 'npm test', detect: 'package.json:mocha' },
75
+ { tool: 'npm', command: 'npm test', detect: 'package.json:scripts.test' }
76
+ ],
77
+ fallback: 'npm test'
78
+ },
79
+ build: {
80
+ name: 'Build',
81
+ description: 'Production build',
82
+ commands: [
83
+ { tool: 'next', command: 'npm run build', detect: 'next.config.js' },
84
+ { tool: 'vite', command: 'npm run build', detect: 'vite.config.ts' },
85
+ { tool: 'npm', command: 'npm run build', detect: 'package.json:scripts.build' }
86
+ ],
87
+ fallback: null
88
+ },
89
+ security: {
90
+ name: 'Security',
91
+ description: 'Security audit',
92
+ commands: [
93
+ { tool: 'npm-audit', command: 'npm audit --audit-level=high', detect: 'package-lock.json' },
94
+ { tool: 'yarn-audit', command: 'yarn audit --level high', detect: 'yarn.lock' },
95
+ { tool: 'pnpm-audit', command: 'pnpm audit --audit-level high', detect: 'pnpm-lock.yaml' }
96
+ ],
97
+ fallback: null
98
+ }
99
+ };
100
+
101
+ /**
102
+ * Detect if a check's tool is available in the project
103
+ * @param {string} projectRoot - Project root directory
104
+ * @param {string} detect - Detection pattern
105
+ * @returns {boolean}
106
+ */
107
+ function detectTool(projectRoot, detect) {
108
+ if (!detect) return false;
109
+
110
+ // Check for file existence
111
+ if (!detect.includes(':')) {
112
+ const filePath = path.join(projectRoot, detect);
113
+ return fs.existsSync(filePath);
114
+ }
115
+
116
+ // Check for package.json property
117
+ const [file, prop] = detect.split(':');
118
+ if (file === 'package.json') {
119
+ try {
120
+ const pkgPath = path.join(projectRoot, 'package.json');
121
+ if (!fs.existsSync(pkgPath)) return false;
122
+
123
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
124
+ const parts = prop.split('.');
125
+ let value = pkg;
126
+ for (const part of parts) {
127
+ value = value?.[part];
128
+ }
129
+ return value !== undefined && value !== null;
130
+ } catch {
131
+ return false;
132
+ }
133
+ }
134
+
135
+ return false;
136
+ }
137
+
138
+ /**
139
+ * Get the command for a check based on project configuration
140
+ * @param {string} checkId - Check identifier
141
+ * @param {string} projectRoot - Project root directory
142
+ * @returns {object|null} Check configuration
143
+ */
144
+ function resolveCheck(checkId, projectRoot) {
145
+ const definition = CHECK_DEFINITIONS[checkId];
146
+ if (!definition) {
147
+ return null;
148
+ }
149
+
150
+ // Find first available command
151
+ for (const cmd of definition.commands) {
152
+ if (detectTool(projectRoot, cmd.detect)) {
153
+ return {
154
+ id: checkId,
155
+ name: definition.name,
156
+ description: definition.description,
157
+ command: cmd.command,
158
+ tool: cmd.tool
159
+ };
160
+ }
161
+ }
162
+
163
+ // Use fallback if available
164
+ if (definition.fallback) {
165
+ return {
166
+ id: checkId,
167
+ name: definition.name,
168
+ description: definition.description,
169
+ command: definition.fallback,
170
+ tool: 'fallback'
171
+ };
172
+ }
173
+
174
+ return null;
175
+ }
176
+
177
+ /**
178
+ * Execute a check
179
+ * @param {object} check - Check configuration
180
+ * @param {string} projectRoot - Project root directory
181
+ * @param {object} options - Execution options
182
+ * @returns {object} Result
183
+ */
184
+ function executeCheck(check, projectRoot, options = {}) {
185
+ const { timeout = 300000, verbose = false } = options;
186
+
187
+ try {
188
+ const output = execSync(check.command, {
189
+ cwd: projectRoot,
190
+ stdio: 'pipe',
191
+ encoding: 'utf-8',
192
+ timeout
193
+ });
194
+
195
+ return {
196
+ id: check.id,
197
+ name: check.name,
198
+ status: 'pass',
199
+ message: 'Passed',
200
+ output: verbose ? output : null,
201
+ duration: null // Could add timing
202
+ };
203
+ } catch (error) {
204
+ const output = error.stdout || error.stderr || error.message;
205
+ return {
206
+ id: check.id,
207
+ name: check.name,
208
+ status: 'fail',
209
+ message: output.slice(0, 500),
210
+ output: verbose ? output : null,
211
+ exitCode: error.status || 1
212
+ };
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Get a gate definition
218
+ * @param {string} gateId - Gate identifier
219
+ * @param {object} customGates - Custom gate definitions
220
+ * @returns {object|null}
221
+ */
222
+ function getGate(gateId, customGates = {}) {
223
+ return customGates[gateId] || DEFAULT_GATES[gateId] || null;
224
+ }
225
+
226
+ /**
227
+ * List available gates
228
+ * @param {object} customGates - Custom gate definitions
229
+ * @returns {string[]}
230
+ */
231
+ function listGates(customGates = {}) {
232
+ return [...new Set([
233
+ ...Object.keys(DEFAULT_GATES),
234
+ ...Object.keys(customGates)
235
+ ])];
236
+ }
237
+
238
+ /**
239
+ * Run a quality gate
240
+ * @param {string} gateId - Gate identifier
241
+ * @param {string} projectRoot - Project root directory
242
+ * @param {object} options - Execution options
243
+ * @returns {object} Gate results
244
+ */
245
+ function runGate(gateId, projectRoot, options = {}) {
246
+ const { customGates = {}, skip = [], strict = false, verbose = false } = options;
247
+
248
+ const gate = getGate(gateId, customGates);
249
+ if (!gate) {
250
+ return {
251
+ gate: gateId,
252
+ status: 'error',
253
+ message: `Unknown gate: ${gateId}`,
254
+ results: []
255
+ };
256
+ }
257
+
258
+ const results = [];
259
+ let passed = 0;
260
+ let failed = 0;
261
+ let skipped = 0;
262
+
263
+ for (const checkId of gate.checks) {
264
+ // Skip if requested
265
+ if (skip.includes(checkId)) {
266
+ results.push({
267
+ id: checkId,
268
+ name: CHECK_DEFINITIONS[checkId]?.name || checkId,
269
+ status: 'skip',
270
+ message: 'Skipped by user'
271
+ });
272
+ skipped++;
273
+ continue;
274
+ }
275
+
276
+ // Resolve check
277
+ const check = resolveCheck(checkId, projectRoot);
278
+ if (!check) {
279
+ results.push({
280
+ id: checkId,
281
+ name: CHECK_DEFINITIONS[checkId]?.name || checkId,
282
+ status: 'skip',
283
+ message: 'Tool not available'
284
+ });
285
+ skipped++;
286
+ continue;
287
+ }
288
+
289
+ // Execute
290
+ const result = executeCheck(check, projectRoot, { verbose });
291
+ results.push(result);
292
+
293
+ if (result.status === 'pass') {
294
+ passed++;
295
+ } else {
296
+ failed++;
297
+ if (strict) {
298
+ break;
299
+ }
300
+ }
301
+ }
302
+
303
+ return {
304
+ gate: gateId,
305
+ name: gate.name,
306
+ description: gate.description,
307
+ status: failed === 0 ? 'pass' : 'fail',
308
+ passed,
309
+ failed,
310
+ skipped,
311
+ total: results.length,
312
+ results
313
+ };
314
+ }
315
+
316
+ /**
317
+ * Get available checks for a project
318
+ * @param {string} projectRoot - Project root directory
319
+ * @returns {object[]}
320
+ */
321
+ function getAvailableChecks(projectRoot) {
322
+ const available = [];
323
+
324
+ for (const [checkId, definition] of Object.entries(CHECK_DEFINITIONS)) {
325
+ const check = resolveCheck(checkId, projectRoot);
326
+ if (check) {
327
+ available.push({
328
+ id: checkId,
329
+ name: definition.name,
330
+ description: definition.description,
331
+ tool: check.tool,
332
+ command: check.command
333
+ });
334
+ }
335
+ }
336
+
337
+ return available;
338
+ }
339
+
340
+ /**
341
+ * Generate git hook script
342
+ * @param {string} gateId - Gate to run
343
+ * @param {object} options - Hook options
344
+ * @returns {string}
345
+ */
346
+ function generateHookScript(gateId, options = {}) {
347
+ const { strict = true, skip = [] } = options;
348
+
349
+ let script = '#!/bin/sh\n';
350
+ script += '# Bootspring Quality Gate Hook\n\n';
351
+
352
+ let cmd = `npx bootspring quality ${gateId}`;
353
+ if (strict) cmd += ' --strict';
354
+ if (skip.length > 0) {
355
+ for (const s of skip) {
356
+ cmd += ` --skip ${s}`;
357
+ }
358
+ }
359
+
360
+ script += `${cmd}\n`;
361
+ return script;
362
+ }
363
+
364
+ module.exports = {
365
+ // Core API
366
+ runGate,
367
+ executeCheck,
368
+ resolveCheck,
369
+ getGate,
370
+ listGates,
371
+ getAvailableChecks,
372
+
373
+ // Utilities
374
+ detectTool,
375
+ generateHookScript,
376
+
377
+ // Constants
378
+ DEFAULT_GATES,
379
+ CHECK_DEFINITIONS
380
+ };
@@ -0,0 +1,19 @@
1
+ {
2
+ "scopes": [
3
+ {
4
+ "name": "mcp",
5
+ "path": "mcp",
6
+ "maxWarnings": 0
7
+ },
8
+ {
9
+ "name": "core",
10
+ "path": "core",
11
+ "maxWarnings": 18
12
+ },
13
+ {
14
+ "name": "cli",
15
+ "path": "cli",
16
+ "maxWarnings": 55
17
+ }
18
+ ]
19
+ }