@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.
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/agents/README.md +93 -0
- package/agents/api-expert/context.md +416 -0
- package/agents/architecture-expert/context.md +454 -0
- package/agents/backend-expert/context.md +483 -0
- package/agents/code-review-expert/context.md +365 -0
- package/agents/database-expert/context.md +250 -0
- package/agents/devops-expert/context.md +446 -0
- package/agents/frontend-expert/context.md +364 -0
- package/agents/index.js +140 -0
- package/agents/performance-expert/context.md +377 -0
- package/agents/security-expert/context.md +343 -0
- package/agents/testing-expert/context.md +414 -0
- package/agents/ui-ux-expert/context.md +448 -0
- package/agents/vercel-expert/context.md +426 -0
- package/bin/bootspring.js +310 -0
- package/cli/agent.js +337 -0
- package/cli/context.js +194 -0
- package/cli/dashboard.js +150 -0
- package/cli/generate.js +294 -0
- package/cli/init.js +410 -0
- package/cli/loop.js +421 -0
- package/cli/mcp.js +241 -0
- package/cli/memory.js +303 -0
- package/cli/orchestrator.js +400 -0
- package/cli/plugin.js +451 -0
- package/cli/quality.js +332 -0
- package/cli/skill.js +369 -0
- package/cli/task.js +628 -0
- package/cli/telemetry.js +114 -0
- package/cli/todo.js +614 -0
- package/cli/update.js +312 -0
- package/core/config.js +245 -0
- package/core/context.js +329 -0
- package/core/entitlements.js +209 -0
- package/core/index.js +43 -0
- package/core/policies.js +68 -0
- package/core/telemetry.js +247 -0
- package/core/utils.js +380 -0
- package/dashboard/server.js +818 -0
- package/docs/integrations/claude-code.md +42 -0
- package/docs/integrations/codex.md +42 -0
- package/docs/mcp-api-platform.md +102 -0
- package/generators/generate.js +598 -0
- package/generators/index.js +18 -0
- package/hooks/context-detector.js +177 -0
- package/hooks/index.js +35 -0
- package/hooks/prompt-enhancer.js +289 -0
- package/intelligence/git-memory.js +551 -0
- package/intelligence/index.js +59 -0
- package/intelligence/orchestrator.js +964 -0
- package/intelligence/prd.js +447 -0
- package/intelligence/recommendation-weights.json +18 -0
- package/intelligence/recommendations.js +234 -0
- package/mcp/capabilities.js +71 -0
- package/mcp/contracts/mcp-contract.v1.json +497 -0
- package/mcp/registry.js +213 -0
- package/mcp/response-formatter.js +462 -0
- package/mcp/server.js +99 -0
- package/mcp/tools/agent-tool.js +137 -0
- package/mcp/tools/capabilities-tool.js +54 -0
- package/mcp/tools/context-tool.js +49 -0
- package/mcp/tools/dashboard-tool.js +58 -0
- package/mcp/tools/generate-tool.js +46 -0
- package/mcp/tools/loop-tool.js +134 -0
- package/mcp/tools/memory-tool.js +180 -0
- package/mcp/tools/orchestrator-tool.js +232 -0
- package/mcp/tools/plugin-tool.js +76 -0
- package/mcp/tools/quality-tool.js +47 -0
- package/mcp/tools/skill-tool.js +233 -0
- package/mcp/tools/telemetry-tool.js +95 -0
- package/mcp/tools/todo-tool.js +133 -0
- package/package.json +98 -0
- package/plugins/index.js +141 -0
- package/quality/index.js +380 -0
- package/quality/lint-budgets.json +19 -0
- package/skills/index.js +787 -0
- package/skills/patterns/README.md +163 -0
- package/skills/patterns/api/route-handler.md +217 -0
- package/skills/patterns/api/server-action.md +249 -0
- package/skills/patterns/auth/clerk.md +132 -0
- package/skills/patterns/database/prisma.md +180 -0
- package/skills/patterns/payments/stripe.md +272 -0
- package/skills/patterns/security/validation.md +268 -0
- package/skills/patterns/testing/vitest.md +307 -0
- package/templates/bootspring.config.js +83 -0
- package/templates/mcp.json +9 -0
package/quality/index.js
ADDED
|
@@ -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
|
+
};
|