create-qa-architect 5.3.1 → 5.4.3
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/.github/workflows/quality.yml +11 -11
- package/.github/workflows/shell-ci.yml.example +82 -0
- package/.github/workflows/shell-quality.yml.example +148 -0
- package/README.md +120 -12
- package/config/shell-ci.yml +82 -0
- package/config/shell-quality.yml +148 -0
- package/docs/CI-COST-ANALYSIS.md +323 -0
- package/eslint.config.cjs +2 -0
- package/lib/commands/analyze-ci.js +616 -0
- package/lib/commands/deps.js +70 -22
- package/lib/commands/index.js +4 -0
- package/lib/config-validator.js +28 -45
- package/lib/error-reporter.js +1 -1
- package/lib/github-api.js +34 -4
- package/lib/license-signing.js +15 -0
- package/lib/licensing.js +116 -22
- package/lib/package-utils.js +9 -9
- package/lib/project-maturity.js +58 -6
- package/lib/smart-strategy-generator.js +20 -3
- package/lib/telemetry.js +1 -1
- package/lib/ui-helpers.js +1 -1
- package/lib/validation/config-security.js +22 -18
- package/lib/validation/index.js +68 -97
- package/package.json +3 -3
- package/scripts/validate-claude-md.js +80 -0
- package/setup.js +607 -51
package/lib/project-maturity.js
CHANGED
|
@@ -157,6 +157,9 @@ class ProjectMaturityDetector {
|
|
|
157
157
|
hasTests: this.hasTests(),
|
|
158
158
|
hasDependencies: this.hasDependencies(),
|
|
159
159
|
hasCssFiles: this.hasCssFiles(),
|
|
160
|
+
hasShellScripts: this.hasShellScripts(),
|
|
161
|
+
shellScriptCount: this.countShellScripts(),
|
|
162
|
+
isShellProject: this.isShellProject(),
|
|
160
163
|
packageJsonExists: this.packageJsonExists(),
|
|
161
164
|
}
|
|
162
165
|
}
|
|
@@ -266,7 +269,7 @@ class ProjectMaturityDetector {
|
|
|
266
269
|
const deps = packageJson.dependencies || {}
|
|
267
270
|
const devDeps = packageJson.devDependencies || {}
|
|
268
271
|
return Object.keys(deps).length > 0 || Object.keys(devDeps).length > 0
|
|
269
|
-
} catch {
|
|
272
|
+
} catch (_error) {
|
|
270
273
|
return false
|
|
271
274
|
}
|
|
272
275
|
}
|
|
@@ -287,6 +290,36 @@ class ProjectMaturityDetector {
|
|
|
287
290
|
)
|
|
288
291
|
}
|
|
289
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Check if project has shell scripts
|
|
295
|
+
* @returns {boolean} True if shell scripts exist
|
|
296
|
+
*/
|
|
297
|
+
hasShellScripts() {
|
|
298
|
+
return this.countShellScripts() > 0
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Count shell script files
|
|
303
|
+
* @returns {number} Number of shell script files
|
|
304
|
+
*/
|
|
305
|
+
countShellScripts() {
|
|
306
|
+
const extensions = ['.sh', '.bash']
|
|
307
|
+
|
|
308
|
+
return this.countFilesRecursive(this.projectPath, {
|
|
309
|
+
extensions,
|
|
310
|
+
excludeDirs: EXCLUDE_DIRECTORIES.PROJECT_MATURITY,
|
|
311
|
+
maxDepth: 4,
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Check if this is primarily a shell script project
|
|
317
|
+
* @returns {boolean} True if shell project (has .sh files, no package.json)
|
|
318
|
+
*/
|
|
319
|
+
isShellProject() {
|
|
320
|
+
return this.hasShellScripts() && !this.packageJsonExists()
|
|
321
|
+
}
|
|
322
|
+
|
|
290
323
|
/**
|
|
291
324
|
* Check if package.json exists
|
|
292
325
|
* @returns {boolean} True if package.json exists
|
|
@@ -405,9 +438,17 @@ class ProjectMaturityDetector {
|
|
|
405
438
|
}
|
|
406
439
|
}
|
|
407
440
|
} catch (error) {
|
|
408
|
-
//
|
|
409
|
-
if (
|
|
410
|
-
console.warn(
|
|
441
|
+
// Always log permission errors (affects maturity detection accuracy)
|
|
442
|
+
if (error.code === 'EACCES') {
|
|
443
|
+
console.warn(`⚠️ Permission denied: ${dir} (excluded from analysis)`)
|
|
444
|
+
} else if (error.code !== 'ENOENT') {
|
|
445
|
+
console.warn(
|
|
446
|
+
`⚠️ Could not read ${dir}: ${error.message} (${error.code})`
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (this.verbose && error.stack) {
|
|
451
|
+
console.warn(` Stack: ${error.stack}`)
|
|
411
452
|
}
|
|
412
453
|
}
|
|
413
454
|
|
|
@@ -435,7 +476,7 @@ class ProjectMaturityDetector {
|
|
|
435
476
|
|
|
436
477
|
/**
|
|
437
478
|
* Generate GitHub Actions outputs for maturity detection
|
|
438
|
-
* @returns {{maturity: string, sourceCount: number, testCount: number, hasDeps: boolean, hasDocs: boolean, hasCss: boolean, requiredChecks: string, optionalChecks: string, disabledChecks: string}} GitHub Actions output format
|
|
479
|
+
* @returns {{maturity: string, sourceCount: number, testCount: number, hasDeps: boolean, hasDocs: boolean, hasCss: boolean, hasShell: boolean, shellCount: number, isShellProject: boolean, requiredChecks: string, optionalChecks: string, disabledChecks: string}} GitHub Actions output format
|
|
439
480
|
*/
|
|
440
481
|
generateGitHubActionsOutput() {
|
|
441
482
|
const maturity = this.detect()
|
|
@@ -449,6 +490,9 @@ class ProjectMaturityDetector {
|
|
|
449
490
|
hasDeps: stats.hasDependencies,
|
|
450
491
|
hasDocs: stats.hasDocumentation,
|
|
451
492
|
hasCss: stats.hasCssFiles,
|
|
493
|
+
hasShell: stats.hasShellScripts,
|
|
494
|
+
shellCount: stats.shellScriptCount,
|
|
495
|
+
isShellProject: stats.isShellProject,
|
|
452
496
|
requiredChecks: checks.required.join(','),
|
|
453
497
|
optionalChecks: checks.optional.join(','),
|
|
454
498
|
disabledChecks: checks.disabled.join(','),
|
|
@@ -472,7 +516,12 @@ class ProjectMaturityDetector {
|
|
|
472
516
|
console.log(` • Test files: ${stats.testFiles}`)
|
|
473
517
|
console.log(` • Documentation: ${stats.hasDocumentation ? 'Yes' : 'No'}`)
|
|
474
518
|
console.log(` • Dependencies: ${stats.hasDependencies ? 'Yes' : 'No'}`)
|
|
475
|
-
console.log(` • CSS files: ${stats.hasCssFiles ? 'Yes' : 'No'}
|
|
519
|
+
console.log(` • CSS files: ${stats.hasCssFiles ? 'Yes' : 'No'}`)
|
|
520
|
+
console.log(` • Shell scripts: ${stats.shellScriptCount}`)
|
|
521
|
+
if (stats.isShellProject) {
|
|
522
|
+
console.log(` • Project type: Shell script project`)
|
|
523
|
+
}
|
|
524
|
+
console.log()
|
|
476
525
|
|
|
477
526
|
console.log('Quality Checks:')
|
|
478
527
|
console.log(` ✅ Required: ${level.checks.required.join(', ')}`)
|
|
@@ -504,6 +553,9 @@ if (require.main === module) {
|
|
|
504
553
|
console.log(`has-deps=${output.hasDeps}`)
|
|
505
554
|
console.log(`has-docs=${output.hasDocs}`)
|
|
506
555
|
console.log(`has-css=${output.hasCss}`)
|
|
556
|
+
console.log(`has-shell=${output.hasShell}`)
|
|
557
|
+
console.log(`shell-count=${output.shellCount}`)
|
|
558
|
+
console.log(`is-shell-project=${output.isShellProject}`)
|
|
507
559
|
console.log(`required-checks=${output.requiredChecks}`)
|
|
508
560
|
console.log(`optional-checks=${output.optionalChecks}`)
|
|
509
561
|
console.log(`disabled-checks=${output.disabledChecks}`)
|
|
@@ -170,9 +170,19 @@ function readPackageJson(projectPath) {
|
|
|
170
170
|
} catch (error) {
|
|
171
171
|
// DR22 fix: Provide specific error messages for different failure types
|
|
172
172
|
if (error instanceof SyntaxError) {
|
|
173
|
-
|
|
173
|
+
const errorId = 'PKG_JSON_INVALID_SYNTAX'
|
|
174
|
+
console.error(`❌ [${errorId}] package.json has invalid JSON syntax:`)
|
|
174
175
|
console.error(` File: ${pkgPath}`)
|
|
175
|
-
console.error(
|
|
176
|
+
console.error(` Error: ${error.message}`)
|
|
177
|
+
console.error(`\n Recovery steps:`)
|
|
178
|
+
console.error(` 1. Validate JSON: cat ${pkgPath} | jq .`)
|
|
179
|
+
console.error(
|
|
180
|
+
` 2. Common issues: trailing commas, missing quotes, unclosed brackets`
|
|
181
|
+
)
|
|
182
|
+
console.error(` 3. Use a JSON validator: https://jsonlint.com`)
|
|
183
|
+
console.error(
|
|
184
|
+
`\n ⚠️ Smart Test Strategy will use generic fallback until this is fixed\n`
|
|
185
|
+
)
|
|
176
186
|
} else if (error.code === 'EACCES') {
|
|
177
187
|
console.error(`❌ Permission denied reading package.json: ${pkgPath}`)
|
|
178
188
|
console.error(' Check file permissions and try again')
|
|
@@ -235,7 +245,14 @@ function generateSmartStrategy(options = {}) {
|
|
|
235
245
|
)
|
|
236
246
|
|
|
237
247
|
if (!fs.existsSync(templatePath)) {
|
|
238
|
-
throw new Error(
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Smart strategy template not found at ${templatePath}\n` +
|
|
250
|
+
`This indicates a package installation issue.\n\n` +
|
|
251
|
+
`Troubleshooting steps:\n` +
|
|
252
|
+
`1. Reinstall the package: npm install -g create-qa-architect@latest\n` +
|
|
253
|
+
`2. Check file permissions: ls -la ${path.dirname(templatePath)}\n` +
|
|
254
|
+
`3. Report issue if problem persists: https://github.com/vibebuildlab/qa-architect/issues/new`
|
|
255
|
+
)
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
let template = fs.readFileSync(templatePath, 'utf8')
|
package/lib/telemetry.js
CHANGED
package/lib/ui-helpers.js
CHANGED
|
@@ -58,7 +58,7 @@ function showProgress(message) {
|
|
|
58
58
|
const oraImport = require('ora')
|
|
59
59
|
const ora = /** @type {any} */ (oraImport.default || oraImport)
|
|
60
60
|
return ora(message).start()
|
|
61
|
-
} catch {
|
|
61
|
+
} catch (_error) {
|
|
62
62
|
// Fallback if ora not installed (graceful degradation)
|
|
63
63
|
console.log(formatMessage('working', message))
|
|
64
64
|
return {
|
|
@@ -37,11 +37,19 @@ class ConfigSecurityScanner {
|
|
|
37
37
|
// checksumMap dependency injection - FOR TESTING ONLY
|
|
38
38
|
// WARNING: Do not use in production CLI - this bypasses security verification!
|
|
39
39
|
if (options.checksumMap) {
|
|
40
|
-
|
|
40
|
+
// Security fix: Block checksumMap override in production
|
|
41
|
+
// Only allow in explicit test/development mode
|
|
42
|
+
const isTestMode = process.env.NODE_ENV === 'test'
|
|
43
|
+
const isDeveloperMode = process.env.QAA_DEVELOPER === 'true'
|
|
44
|
+
const isProduction = process.env.NODE_ENV === 'production'
|
|
45
|
+
|
|
46
|
+
if (isProduction || (!isTestMode && !isDeveloperMode)) {
|
|
41
47
|
throw new Error(
|
|
42
|
-
'checksumMap override not allowed in production
|
|
48
|
+
'checksumMap override not allowed in production. ' +
|
|
49
|
+
'Only permitted when NODE_ENV=test or QAA_DEVELOPER=true'
|
|
43
50
|
)
|
|
44
51
|
}
|
|
52
|
+
|
|
45
53
|
if (!options.quiet) {
|
|
46
54
|
console.warn(
|
|
47
55
|
'⚠️ WARNING: Using custom checksum map - FOR TESTING ONLY!'
|
|
@@ -118,23 +126,14 @@ class ConfigSecurityScanner {
|
|
|
118
126
|
)
|
|
119
127
|
}
|
|
120
128
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
console.warn(
|
|
124
|
-
'🚨 WARNING: Using npx gitleaks (supply chain risk - downloads latest version)'
|
|
125
|
-
)
|
|
126
|
-
console.warn(
|
|
127
|
-
'📌 Consider: brew install gitleaks (macOS) or choco install gitleaks (Windows)'
|
|
128
|
-
)
|
|
129
|
-
return 'npx gitleaks'
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Security-first: fail hard instead of silent fallback
|
|
129
|
+
// Security-first: fail hard instead of any fallback
|
|
130
|
+
// SECURITY: Removed npx gitleaks fallback to prevent command injection
|
|
133
131
|
throw new Error(
|
|
134
132
|
`Cannot resolve secure gitleaks binary. Options:\n` +
|
|
135
133
|
`1. Install globally: brew install gitleaks (macOS) or choco install gitleaks (Windows)\n` +
|
|
136
134
|
`2. Set GITLEAKS_PATH to your preferred binary\n` +
|
|
137
|
-
`
|
|
135
|
+
`Note: --allow-latest-gitleaks flag is deprecated and no longer supported.\n` +
|
|
136
|
+
`npx gitleaks has been intentionally removed due to supply chain security risk.`
|
|
138
137
|
)
|
|
139
138
|
}
|
|
140
139
|
}
|
|
@@ -404,11 +403,16 @@ class ConfigSecurityScanner {
|
|
|
404
403
|
spinner.succeed('npm audit completed')
|
|
405
404
|
}
|
|
406
405
|
} catch {
|
|
407
|
-
spinner.
|
|
408
|
-
|
|
406
|
+
spinner.fail(`Could not parse ${packageManager} audit output`)
|
|
407
|
+
this.issues.push(
|
|
408
|
+
`${packageManager} audit: Unable to parse audit output. Run '${packageManager} audit --json' manually to inspect vulnerabilities.`
|
|
409
|
+
)
|
|
409
410
|
}
|
|
410
411
|
} else {
|
|
411
|
-
spinner.
|
|
412
|
+
spinner.fail('npm audit returned an error with no output')
|
|
413
|
+
this.issues.push(
|
|
414
|
+
`${packageManager} audit: Failed with no output. Run '${packageManager} audit --json' manually to inspect vulnerabilities.`
|
|
415
|
+
)
|
|
412
416
|
}
|
|
413
417
|
}
|
|
414
418
|
}
|
package/lib/validation/index.js
CHANGED
|
@@ -4,6 +4,27 @@ const { ConfigSecurityScanner } = require('./config-security')
|
|
|
4
4
|
const { DocumentationValidator } = require('./documentation')
|
|
5
5
|
const { WorkflowValidator } = require('./workflow-validation')
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Validation check configuration
|
|
9
|
+
*/
|
|
10
|
+
const VALIDATION_CHECKS = [
|
|
11
|
+
{
|
|
12
|
+
name: 'configSecurity',
|
|
13
|
+
label: 'Configuration security',
|
|
14
|
+
method: 'runConfigSecurity',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'documentation',
|
|
18
|
+
label: 'Documentation validation',
|
|
19
|
+
method: 'runDocumentationValidation',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'workflows',
|
|
23
|
+
label: 'Workflow validation',
|
|
24
|
+
method: 'runWorkflowValidation',
|
|
25
|
+
},
|
|
26
|
+
]
|
|
27
|
+
|
|
7
28
|
/**
|
|
8
29
|
* Enhanced Validation Runner
|
|
9
30
|
* Coordinates all validation checks
|
|
@@ -43,63 +64,31 @@ class ValidationRunner {
|
|
|
43
64
|
async runComprehensiveCheck() {
|
|
44
65
|
console.log('🔍 Running comprehensive validation...\n')
|
|
45
66
|
|
|
46
|
-
const results =
|
|
47
|
-
|
|
48
|
-
documentation: null,
|
|
49
|
-
workflows: null,
|
|
50
|
-
overall: { passed: true, issues: [] },
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
console.log('⏳ [1/3] Running configuration security scan...')
|
|
55
|
-
results.configSecurity = await this.runConfigSecurity()
|
|
56
|
-
console.log('✅ [1/3] Configuration security complete')
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.log('❌ [1/3] Configuration security failed')
|
|
59
|
-
results.configSecurity = { passed: false, error: error.message }
|
|
60
|
-
results.overall.passed = false
|
|
61
|
-
results.overall.issues.push(`Configuration Security: ${error.message}`)
|
|
62
|
-
}
|
|
67
|
+
const results = this._initResults()
|
|
68
|
+
const total = VALIDATION_CHECKS.length
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.log('⏳ [2/3] Running documentation validation...')
|
|
68
|
-
results.documentation = await this.runDocumentationValidation()
|
|
69
|
-
console.log('✅ [2/3] Documentation validation complete')
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.log('❌ [2/3] Documentation validation failed')
|
|
72
|
-
results.documentation = { passed: false, error: error.message }
|
|
73
|
-
results.overall.passed = false
|
|
74
|
-
results.overall.issues.push(`Documentation: ${error.message}`)
|
|
75
|
-
}
|
|
70
|
+
for (let i = 0; i < VALIDATION_CHECKS.length; i++) {
|
|
71
|
+
const check = VALIDATION_CHECKS[i]
|
|
72
|
+
const stepNum = i + 1
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.log('⏳ [3/3] Running workflow validation...')
|
|
81
|
-
results.workflows = await this.runWorkflowValidation()
|
|
82
|
-
console.log('✅ [3/3] Workflow validation complete')
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.log('❌ [3/3] Workflow validation failed')
|
|
85
|
-
results.workflows = { passed: false, error: error.message }
|
|
86
|
-
results.overall.passed = false
|
|
87
|
-
results.overall.issues.push(`Workflows: ${error.message}`)
|
|
88
|
-
}
|
|
74
|
+
console.log(
|
|
75
|
+
`⏳ [${stepNum}/${total}] Running ${check.label.toLowerCase()}...`
|
|
76
|
+
)
|
|
89
77
|
|
|
90
|
-
|
|
78
|
+
try {
|
|
79
|
+
results[check.name] = await this[check.method]()
|
|
80
|
+
console.log(`✅ [${stepNum}/${total}] ${check.label} complete`)
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.log(`❌ [${stepNum}/${total}] ${check.label} failed`)
|
|
83
|
+
results[check.name] = { passed: false, error: error.message }
|
|
84
|
+
results.overall.passed = false
|
|
85
|
+
results.overall.issues.push(`${check.label}: ${error.message}`)
|
|
86
|
+
}
|
|
91
87
|
|
|
92
|
-
|
|
93
|
-
console.log('✅ All validation checks passed!')
|
|
94
|
-
} else {
|
|
95
|
-
// Detect test scenario and use appropriate prefix
|
|
96
|
-
const isTest = process.argv.join(' ').includes('test')
|
|
97
|
-
const prefix = isTest ? '📋 TEST SCENARIO:' : '❌'
|
|
98
|
-
console.error(`${prefix} Validation failed with issues:`)
|
|
99
|
-
results.overall.issues.forEach(issue => console.error(` - ${issue}`))
|
|
100
|
-
throw new Error('Comprehensive validation failed')
|
|
88
|
+
console.log('')
|
|
101
89
|
}
|
|
102
90
|
|
|
91
|
+
this._reportResults(results)
|
|
103
92
|
return results
|
|
104
93
|
}
|
|
105
94
|
|
|
@@ -110,71 +99,53 @@ class ValidationRunner {
|
|
|
110
99
|
async runComprehensiveCheckParallel() {
|
|
111
100
|
console.log('🔍 Running comprehensive validation (parallel)...\n')
|
|
112
101
|
|
|
113
|
-
const results =
|
|
114
|
-
configSecurity: null,
|
|
115
|
-
documentation: null,
|
|
116
|
-
workflows: null,
|
|
117
|
-
overall: { passed: true, issues: [] },
|
|
118
|
-
}
|
|
102
|
+
const results = this._initResults()
|
|
119
103
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.runConfigSecurity()
|
|
104
|
+
const validationPromises = VALIDATION_CHECKS.map(check =>
|
|
105
|
+
this[check.method]()
|
|
123
106
|
.then(result => {
|
|
124
|
-
results.
|
|
125
|
-
console.log(
|
|
107
|
+
results[check.name] = result
|
|
108
|
+
console.log(`✅ ${check.label} complete`)
|
|
126
109
|
})
|
|
127
110
|
.catch(error => {
|
|
128
|
-
console.log(
|
|
129
|
-
results.
|
|
111
|
+
console.log(`❌ ${check.label} failed`)
|
|
112
|
+
results[check.name] = { passed: false, error: error.message }
|
|
130
113
|
results.overall.passed = false
|
|
131
|
-
results.overall.issues.push(
|
|
132
|
-
`Configuration Security: ${error.message}`
|
|
133
|
-
)
|
|
134
|
-
}),
|
|
135
|
-
|
|
136
|
-
this.runDocumentationValidation()
|
|
137
|
-
.then(result => {
|
|
138
|
-
results.documentation = result
|
|
139
|
-
console.log('✅ Documentation validation complete')
|
|
114
|
+
results.overall.issues.push(`${check.label}: ${error.message}`)
|
|
140
115
|
})
|
|
141
|
-
|
|
142
|
-
console.log('❌ Documentation validation failed')
|
|
143
|
-
results.documentation = { passed: false, error: error.message }
|
|
144
|
-
results.overall.passed = false
|
|
145
|
-
results.overall.issues.push(`Documentation: ${error.message}`)
|
|
146
|
-
}),
|
|
116
|
+
)
|
|
147
117
|
|
|
148
|
-
this.runWorkflowValidation()
|
|
149
|
-
.then(result => {
|
|
150
|
-
results.workflows = result
|
|
151
|
-
console.log('✅ Workflow validation complete')
|
|
152
|
-
})
|
|
153
|
-
.catch(error => {
|
|
154
|
-
console.log('❌ Workflow validation failed')
|
|
155
|
-
results.workflows = { passed: false, error: error.message }
|
|
156
|
-
results.overall.passed = false
|
|
157
|
-
results.overall.issues.push(`Workflows: ${error.message}`)
|
|
158
|
-
}),
|
|
159
|
-
]
|
|
160
|
-
|
|
161
|
-
// Wait for all validations to complete
|
|
162
118
|
await Promise.all(validationPromises)
|
|
119
|
+
console.log('')
|
|
120
|
+
|
|
121
|
+
this._reportResults(results)
|
|
122
|
+
return results
|
|
123
|
+
}
|
|
163
124
|
|
|
164
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Initialize results object
|
|
127
|
+
*/
|
|
128
|
+
_initResults() {
|
|
129
|
+
const results = { overall: { passed: true, issues: [] } }
|
|
130
|
+
VALIDATION_CHECKS.forEach(check => {
|
|
131
|
+
results[check.name] = null
|
|
132
|
+
})
|
|
133
|
+
return results
|
|
134
|
+
}
|
|
165
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Report validation results
|
|
138
|
+
*/
|
|
139
|
+
_reportResults(results) {
|
|
166
140
|
if (results.overall.passed) {
|
|
167
141
|
console.log('✅ All validation checks passed!')
|
|
168
142
|
} else {
|
|
169
|
-
// Detect test scenario and use appropriate prefix
|
|
170
143
|
const isTest = process.argv.join(' ').includes('test')
|
|
171
144
|
const prefix = isTest ? '📋 TEST SCENARIO:' : '❌'
|
|
172
145
|
console.error(`${prefix} Validation failed with issues:`)
|
|
173
146
|
results.overall.issues.forEach(issue => console.error(` - ${issue}`))
|
|
174
147
|
throw new Error('Comprehensive validation failed')
|
|
175
148
|
}
|
|
176
|
-
|
|
177
|
-
return results
|
|
178
149
|
}
|
|
179
150
|
}
|
|
180
151
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-qa-architect",
|
|
3
|
-
"version": "5.3
|
|
3
|
+
"version": "5.4.3",
|
|
4
4
|
"description": "QA Architect - Bootstrap quality automation for JavaScript/TypeScript and Python projects with GitHub Actions, pre-commit hooks, linting, formatting, and smart test strategy",
|
|
5
5
|
"main": "setup.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"validate:comprehensive": "node setup.js --comprehensive --no-markdownlint",
|
|
21
21
|
"validate:all": "npm run validate:comprehensive && npm run security:audit",
|
|
22
22
|
"validate:pre-push": "npm run test:patterns --if-present && npm run lint && npm run format:check && npm run test:commands --if-present && npm test --if-present",
|
|
23
|
-
"test": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/integration.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/parallel-validation.test.js && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/template-loader.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/real-world-packages.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/real-purchase-flow.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/project-maturity-cli.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js && node tests/gitleaks-real-binary-test.js && node tests/tier-enforcement.test.js",
|
|
24
|
-
"test:unit": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/template-loader.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js",
|
|
23
|
+
"test": "export QAA_DEVELOPER=true && node tests/result-types.test.js && node tests/setup.test.js && node tests/integration.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/parallel-validation.test.js && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/template-loader.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/deps-edge-cases.test.js && node tests/real-world-packages.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/real-purchase-flow.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/workflow-tiers.test.js && node tests/analyze-ci.test.js && node tests/analyze-ci-integration.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/project-maturity-cli.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js && node tests/gitleaks-real-binary-test.js && node tests/tier-enforcement.test.js",
|
|
24
|
+
"test:unit": "export QAA_DEVELOPER=true && node tests/result-types.test.js && node tests/setup.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/template-loader.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/workflow-tiers.test.js && node tests/analyze-ci.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js",
|
|
25
25
|
"test:fast": "npm run test:unit",
|
|
26
26
|
"test:medium": "npm run test:fast && npm run test:patterns && npm run test:commands",
|
|
27
27
|
"test:slow": "export QAA_DEVELOPER=true && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/real-world-packages.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/real-purchase-flow.test.js && node tests/project-maturity-cli.test.js && node tests/gitleaks-real-binary-test.js && npm run test:e2e",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validates CLAUDE.md consistency with package.json
|
|
6
|
+
* Checks that package name and version are correctly referenced
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
|
|
12
|
+
function validateClaudeMd() {
|
|
13
|
+
console.log('🔍 Validating CLAUDE.md...\n')
|
|
14
|
+
|
|
15
|
+
// Read package.json
|
|
16
|
+
const packagePath = path.join(__dirname, '..', 'package.json')
|
|
17
|
+
if (!fs.existsSync(packagePath)) {
|
|
18
|
+
console.error('❌ package.json not found')
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'))
|
|
23
|
+
const packageName = pkg.name
|
|
24
|
+
const packageVersion = pkg.version
|
|
25
|
+
|
|
26
|
+
// Read CLAUDE.md
|
|
27
|
+
const claudeMdPath = path.join(__dirname, '..', 'CLAUDE.md')
|
|
28
|
+
if (!fs.existsSync(claudeMdPath)) {
|
|
29
|
+
console.error('❌ CLAUDE.md not found')
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const claudeMd = fs.readFileSync(claudeMdPath, 'utf8')
|
|
34
|
+
|
|
35
|
+
let errors = 0
|
|
36
|
+
|
|
37
|
+
// Check for package name reference
|
|
38
|
+
if (!claudeMd.includes(packageName)) {
|
|
39
|
+
console.error(
|
|
40
|
+
`❌ CLAUDE.md does not reference package name: ${packageName}`
|
|
41
|
+
)
|
|
42
|
+
errors++
|
|
43
|
+
} else {
|
|
44
|
+
console.log(`✅ Package name referenced: ${packageName}`)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check for version reference (optional - just warn)
|
|
48
|
+
if (!claudeMd.includes(packageVersion)) {
|
|
49
|
+
console.warn(
|
|
50
|
+
`⚠️ CLAUDE.md does not reference current version: ${packageVersion}`
|
|
51
|
+
)
|
|
52
|
+
console.warn(' This is not a critical error, but consider updating.')
|
|
53
|
+
} else {
|
|
54
|
+
console.log(`✅ Version referenced: ${packageVersion}`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Basic content checks
|
|
58
|
+
const requiredSections = ['Project Overview', 'Commands', 'Architecture']
|
|
59
|
+
|
|
60
|
+
requiredSections.forEach(section => {
|
|
61
|
+
if (!claudeMd.includes(section)) {
|
|
62
|
+
console.error(`❌ Missing required section: ${section}`)
|
|
63
|
+
errors++
|
|
64
|
+
} else {
|
|
65
|
+
console.log(`✅ Section found: ${section}`)
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
console.log()
|
|
70
|
+
|
|
71
|
+
if (errors > 0) {
|
|
72
|
+
console.error(`❌ CLAUDE.md validation failed with ${errors} error(s)`)
|
|
73
|
+
process.exit(1)
|
|
74
|
+
} else {
|
|
75
|
+
console.log('✅ CLAUDE.md validation passed!')
|
|
76
|
+
process.exit(0)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
validateClaudeMd()
|