create-qa-architect 5.0.0 → 5.0.6

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 (56) hide show
  1. package/.github/RELEASE_CHECKLIST.md +2 -4
  2. package/.github/workflows/daily-deploy-check.yml +136 -0
  3. package/.github/workflows/nightly-gitleaks-verification.yml +1 -1
  4. package/.github/workflows/quality.yml +3 -0
  5. package/.github/workflows/release.yml +12 -10
  6. package/.github/workflows/weekly-audit.yml +173 -0
  7. package/LICENSE +66 -0
  8. package/README.md +44 -30
  9. package/config/defaults.js +22 -1
  10. package/config/quality-config.schema.json +1 -1
  11. package/create-saas-monetization.js +75 -27
  12. package/docs/ARCHITECTURE.md +53 -0
  13. package/docs/DEPLOYMENT.md +62 -0
  14. package/docs/PREFLIGHT_REPORT.md +108 -0
  15. package/docs/SLA_GATES.md +28 -0
  16. package/docs/TESTING.md +61 -0
  17. package/docs/security/SOC2_STARTER.md +29 -0
  18. package/lib/config-validator.js +8 -2
  19. package/lib/dependency-monitoring-basic.js +73 -26
  20. package/lib/dependency-monitoring-premium.js +21 -19
  21. package/lib/github-api.js +249 -0
  22. package/lib/interactive/questions.js +4 -0
  23. package/lib/license-validator.js +1 -1
  24. package/lib/licensing.js +11 -10
  25. package/lib/package-utils.js +224 -8
  26. package/lib/project-maturity.js +1 -1
  27. package/lib/setup-enhancements.js +33 -0
  28. package/lib/template-loader.js +2 -0
  29. package/lib/ui-helpers.js +2 -1
  30. package/lib/validation/base-validator.js +5 -1
  31. package/lib/validation/cache-manager.js +1 -0
  32. package/lib/validation/config-security.js +5 -4
  33. package/lib/validation/validation-factory.js +1 -1
  34. package/lib/yaml-utils.js +15 -10
  35. package/package.json +18 -13
  36. package/scripts/check-docs.sh +63 -0
  37. package/scripts/smart-test-strategy.sh +98 -0
  38. package/scripts/test-e2e-package.sh +283 -0
  39. package/scripts/validate-command-patterns.js +112 -0
  40. package/setup.js +161 -44
  41. package/templates/QUALITY_TROUBLESHOOTING.md +403 -0
  42. package/templates/ci/circleci-config.yml +35 -0
  43. package/templates/ci/gitlab-ci.yml +47 -0
  44. package/templates/integration-tests/api-service.test.js +244 -0
  45. package/templates/integration-tests/frontend-app.test.js +267 -0
  46. package/templates/scripts/smart-test-strategy.sh +109 -0
  47. package/templates/test-stubs/e2e.smoke.test.js +12 -0
  48. package/templates/test-stubs/unit.test.js +7 -0
  49. package/legal/README.md +0 -106
  50. package/legal/copyright.md +0 -76
  51. package/legal/disclaimer.md +0 -146
  52. package/legal/privacy-policy.html +0 -324
  53. package/legal/privacy-policy.md +0 -196
  54. package/legal/terms-of-service.md +0 -224
  55. package/marketing/beta-user-email-campaign.md +0 -372
  56. package/marketing/landing-page.html +0 -721
@@ -50,17 +50,17 @@ function mergeDevDependencies(initialDevDeps = {}, defaultDevDeps) {
50
50
 
51
51
  /**
52
52
  * Merge lint-staged configuration, preserving existing patterns
53
- * @param {Object} existing - Existing lint-staged config
54
- * @param {Object} defaults - Default lint-staged config
55
- * @param {Object} options - Merge options
56
- * @param {Function} patternChecker - Function to check if a pattern matches certain criteria
57
- * @returns {Object} Merged lint-staged config
53
+ * @param {Record<string, string|string[]>} [existing] - Existing lint-staged config
54
+ * @param {Record<string, string|string[]>} defaults - Default lint-staged config
55
+ * @param {{stylelintTargets?: string[]}} [options] - Merge options
56
+ * @param {(pattern: string) => boolean} [patternChecker] - Function to check if a pattern matches certain criteria
57
+ * @returns {Record<string, string|string[]>} Merged lint-staged config
58
58
  */
59
59
  function mergeLintStaged(
60
+ defaults = {},
60
61
  existing = {},
61
- defaults,
62
62
  options = {},
63
- patternChecker = null
63
+ patternChecker = _pattern => false
64
64
  ) {
65
65
  const merged = { ...existing }
66
66
  const stylelintTargets = options.stylelintTargets || []
@@ -88,7 +88,8 @@ function mergeLintStaged(
88
88
  : [merged[pattern]]
89
89
 
90
90
  const newCommands = [...existingCommands]
91
- commands.forEach(command => {
91
+ const commandList = Array.isArray(commands) ? commands : [commands]
92
+ commandList.forEach(command => {
92
93
  if (!newCommands.includes(command)) {
93
94
  newCommands.push(command)
94
95
  }
@@ -177,6 +178,219 @@ function getAuditCommand(packageManager) {
177
178
  return commands[packageManager] || 'npm audit'
178
179
  }
179
180
 
181
+ /**
182
+ * Detect monorepo type and configuration
183
+ * @param {string} projectPath - Path to the project directory
184
+ * @returns {Object} Monorepo info: { type, isMonorepo, packages, tool }
185
+ */
186
+ function detectMonorepoType(projectPath = process.cwd()) {
187
+ const fs = require('fs')
188
+ const path = require('path')
189
+
190
+ const result = {
191
+ isMonorepo: false,
192
+ type: null, // 'workspaces' | 'lerna' | 'nx' | 'turborepo' | 'rush'
193
+ tool: null, // Specific tool name
194
+ packages: [], // List of workspace package paths
195
+ packageManager: detectPackageManager(projectPath),
196
+ }
197
+
198
+ // Check for Nx (nx.json)
199
+ const nxJsonPath = path.join(projectPath, 'nx.json')
200
+ if (fs.existsSync(nxJsonPath)) {
201
+ result.isMonorepo = true
202
+ result.type = 'nx'
203
+ result.tool = 'nx'
204
+ try {
205
+ const nxJson = JSON.parse(fs.readFileSync(nxJsonPath, 'utf8'))
206
+ result.config = nxJson
207
+ } catch {
208
+ // Ignore parse errors
209
+ }
210
+ }
211
+
212
+ // Check for Turborepo (turbo.json)
213
+ const turboJsonPath = path.join(projectPath, 'turbo.json')
214
+ if (fs.existsSync(turboJsonPath)) {
215
+ result.isMonorepo = true
216
+ result.type = 'turborepo'
217
+ result.tool = 'turborepo'
218
+ try {
219
+ const turboJson = JSON.parse(fs.readFileSync(turboJsonPath, 'utf8'))
220
+ result.config = turboJson
221
+ } catch {
222
+ // Ignore parse errors
223
+ }
224
+ }
225
+
226
+ // Check for Rush (rush.json)
227
+ const rushJsonPath = path.join(projectPath, 'rush.json')
228
+ if (fs.existsSync(rushJsonPath)) {
229
+ result.isMonorepo = true
230
+ result.type = 'rush'
231
+ result.tool = 'rush'
232
+ }
233
+
234
+ // Check for Lerna (lerna.json)
235
+ const lernaJsonPath = path.join(projectPath, 'lerna.json')
236
+ if (fs.existsSync(lernaJsonPath)) {
237
+ result.isMonorepo = true
238
+ result.type = 'lerna'
239
+ result.tool = 'lerna'
240
+ try {
241
+ const lernaJson = JSON.parse(fs.readFileSync(lernaJsonPath, 'utf8'))
242
+ result.packages = lernaJson.packages || ['packages/*']
243
+ } catch {
244
+ result.packages = ['packages/*']
245
+ }
246
+ }
247
+
248
+ // Check for pnpm workspaces (pnpm-workspace.yaml)
249
+ const pnpmWorkspacePath = path.join(projectPath, 'pnpm-workspace.yaml')
250
+ if (fs.existsSync(pnpmWorkspacePath)) {
251
+ result.isMonorepo = true
252
+ result.type = result.type || 'workspaces'
253
+ result.tool = result.tool || 'pnpm'
254
+ try {
255
+ const yaml = fs.readFileSync(pnpmWorkspacePath, 'utf8')
256
+ // Simple line-by-line YAML parsing (safer than regex)
257
+ const lines = yaml.split('\n')
258
+ let inPackages = false
259
+ const packages = []
260
+ for (const line of lines) {
261
+ if (line.trim() === 'packages:') {
262
+ inPackages = true
263
+ continue
264
+ }
265
+ if (inPackages) {
266
+ // Check if line is a list item (starts with -)
267
+ const match = line.match(/^\s*-\s*['"]?([^'"]+)['"]?\s*$/)
268
+ if (match) {
269
+ packages.push(match[1])
270
+ } else if (
271
+ line.trim() &&
272
+ !line.startsWith(' ') &&
273
+ !line.startsWith('\t')
274
+ ) {
275
+ // New top-level key, stop parsing packages
276
+ break
277
+ }
278
+ }
279
+ }
280
+ if (packages.length > 0) {
281
+ result.packages = packages
282
+ }
283
+ } catch {
284
+ // Ignore parse errors
285
+ }
286
+ }
287
+
288
+ // Check for npm/yarn workspaces in package.json
289
+ const packageJsonPath = path.join(projectPath, 'package.json')
290
+ if (fs.existsSync(packageJsonPath)) {
291
+ try {
292
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
293
+ if (packageJson.workspaces) {
294
+ result.isMonorepo = true
295
+ result.type = result.type || 'workspaces'
296
+ // workspaces can be array or object with packages key
297
+ const workspaces = Array.isArray(packageJson.workspaces)
298
+ ? packageJson.workspaces
299
+ : packageJson.workspaces.packages || []
300
+ result.packages = result.packages.length ? result.packages : workspaces
301
+ if (!result.tool) {
302
+ result.tool =
303
+ result.packageManager === 'yarn' ? 'yarn' : result.packageManager
304
+ }
305
+ }
306
+ } catch {
307
+ // Ignore parse errors
308
+ }
309
+ }
310
+
311
+ // Resolve workspace package paths to actual directories
312
+ if (result.isMonorepo && result.packages.length > 0) {
313
+ result.resolvedPackages = resolveWorkspacePackages(
314
+ projectPath,
315
+ result.packages
316
+ )
317
+ }
318
+
319
+ return result
320
+ }
321
+
322
+ /**
323
+ * Resolve workspace glob patterns to actual package directories
324
+ * @param {string} projectPath - Root project path
325
+ * @param {Array<string>} patterns - Workspace patterns (e.g., ['packages/*', 'apps/*'])
326
+ * @returns {Array<Object>} Resolved packages with name and path
327
+ */
328
+ function resolveWorkspacePackages(projectPath, patterns) {
329
+ const fs = require('fs')
330
+ const path = require('path')
331
+ const packages = []
332
+
333
+ for (const pattern of patterns) {
334
+ // Handle simple glob patterns like 'packages/*'
335
+ if (pattern.endsWith('/*')) {
336
+ const baseDir = path.join(projectPath, pattern.slice(0, -2))
337
+ if (fs.existsSync(baseDir)) {
338
+ try {
339
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true })
340
+ for (const entry of entries) {
341
+ if (entry.isDirectory()) {
342
+ const pkgPath = path.join(baseDir, entry.name)
343
+ const pkgJsonPath = path.join(pkgPath, 'package.json')
344
+ if (fs.existsSync(pkgJsonPath)) {
345
+ try {
346
+ const pkgJson = JSON.parse(
347
+ fs.readFileSync(pkgJsonPath, 'utf8')
348
+ )
349
+ packages.push({
350
+ name: pkgJson.name || entry.name,
351
+ path: pkgPath,
352
+ relativePath: path.relative(projectPath, pkgPath),
353
+ })
354
+ } catch {
355
+ packages.push({
356
+ name: entry.name,
357
+ path: pkgPath,
358
+ relativePath: path.relative(projectPath, pkgPath),
359
+ })
360
+ }
361
+ }
362
+ }
363
+ }
364
+ } catch {
365
+ // Ignore read errors
366
+ }
367
+ }
368
+ } else if (!pattern.includes('*')) {
369
+ // Direct path without glob
370
+ const pkgPath = path.join(projectPath, pattern)
371
+ const pkgJsonPath = path.join(pkgPath, 'package.json')
372
+ if (fs.existsSync(pkgJsonPath)) {
373
+ try {
374
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'))
375
+ packages.push({
376
+ name: pkgJson.name || path.basename(pkgPath),
377
+ path: pkgPath,
378
+ relativePath: pattern,
379
+ })
380
+ } catch {
381
+ packages.push({
382
+ name: path.basename(pkgPath),
383
+ path: pkgPath,
384
+ relativePath: pattern,
385
+ })
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ return packages
392
+ }
393
+
180
394
  module.exports = {
181
395
  mergeScripts,
182
396
  mergeDevDependencies,
@@ -184,4 +398,6 @@ module.exports = {
184
398
  detectPackageManager,
185
399
  getInstallCommand,
186
400
  getAuditCommand,
401
+ detectMonorepoType,
402
+ resolveWorkspacePackages,
187
403
  }
@@ -435,7 +435,7 @@ class ProjectMaturityDetector {
435
435
 
436
436
  /**
437
437
  * Generate GitHub Actions outputs for maturity detection
438
- * @returns {string} GitHub Actions output format
438
+ * @returns {{maturity: string, sourceCount: number, testCount: number, hasDeps: boolean, hasDocs: boolean, hasCss: boolean, requiredChecks: string, optionalChecks: string, disabledChecks: string}} GitHub Actions output format
439
439
  */
440
440
  generateGitHubActionsOutput() {
441
441
  const maturity = this.detect()
@@ -80,6 +80,10 @@ function applyProductionQualityFixes(projectPath = '.', options = {}) {
80
80
  copyIntegrationTestTemplates(projectPath, projectType)
81
81
  fixes.push(`✅ Added ${projectType} integration test templates`)
82
82
 
83
+ // Fix 6b: Add starter unit and e2e smoke test stubs
84
+ copyTestStubs(projectPath)
85
+ fixes.push('✅ Added unit and e2e smoke test stubs')
86
+
83
87
  // Fix 7: Apply security-first configuration
84
88
  const securityFixes = applySecurityFirstConfiguration(projectPath)
85
89
  fixes.push('✅ Applied security-first configuration:')
@@ -201,6 +205,35 @@ function getTestTypesDocumentation(projectType) {
201
205
  )
202
206
  }
203
207
 
208
+ function copyTestStubs(projectPath) {
209
+ const stubDir = path.join(__dirname, '../templates/test-stubs')
210
+ if (!fs.existsSync(stubDir)) return
211
+
212
+ const targets = [
213
+ {
214
+ source: path.join(stubDir, 'unit.test.js'),
215
+ dest: path.join(projectPath, 'tests', 'unit', 'sample.test.js'),
216
+ },
217
+ {
218
+ source: path.join(stubDir, 'e2e.smoke.test.js'),
219
+ dest: path.join(projectPath, 'tests', 'e2e', 'smoke.test.js'),
220
+ },
221
+ ]
222
+
223
+ targets.forEach(({ source, dest }) => {
224
+ if (!fs.existsSync(source)) return
225
+
226
+ const destDir = path.dirname(dest)
227
+ if (!fs.existsSync(destDir)) {
228
+ fs.mkdirSync(destDir, { recursive: true })
229
+ }
230
+
231
+ if (!fs.existsSync(dest)) {
232
+ fs.copyFileSync(source, dest)
233
+ }
234
+ })
235
+ }
236
+
204
237
  /**
205
238
  * Generate comprehensive pre-commit hook
206
239
  * This replaces the narrow CLAUDE.md-only validation
@@ -126,6 +126,7 @@ class TemplateLoader {
126
126
  * // Only loads from whitelisted dirs: config/, .github/, lib/
127
127
  */
128
128
  async loadTemplates(dir, baseDir = dir, isPackageDir = false) {
129
+ /** @type {Record<string, string>} */
129
130
  const templates = {}
130
131
 
131
132
  try {
@@ -177,6 +178,7 @@ class TemplateLoader {
177
178
  * @returns {Promise<Object>} Merged template map
178
179
  */
179
180
  async mergeTemplates(customDir, defaultsDir) {
181
+ /** @type {Record<string, string>} */
180
182
  const merged = {}
181
183
 
182
184
  // Load defaults first (from package directory - restrict to known template dirs)
package/lib/ui-helpers.js CHANGED
@@ -55,7 +55,8 @@ function showProgress(message) {
55
55
 
56
56
  // Try to use ora for interactive terminals
57
57
  try {
58
- const ora = require('ora')
58
+ const oraImport = require('ora')
59
+ const ora = /** @type {any} */ (oraImport.default || oraImport)
59
60
  return ora(message).start()
60
61
  } catch {
61
62
  // Fallback if ora not installed (graceful degradation)
@@ -1,5 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ /**
4
+ * @typedef {Error & {code?: string}} ErrWithCode
5
+ */
6
+
3
7
  /**
4
8
  * Base Validator Class
5
9
  * Provides common error handling, state management, and validation patterns
@@ -81,7 +85,7 @@ class BaseValidator {
81
85
 
82
86
  /**
83
87
  * Format error message for user
84
- * @param {Error} error - The error object
88
+ * @param {ErrWithCode} error - The error object
85
89
  * @param {string} context - The context
86
90
  * @returns {string} Formatted error message
87
91
  */
@@ -14,6 +14,7 @@ class CacheManager {
14
14
  options.cacheDir || path.join(process.cwd(), '.create-qa-architect-cache')
15
15
  this.ttl = options.ttl || 24 * 60 * 60 * 1000 // Default: 24 hours in milliseconds
16
16
  this.enabled = options.enabled !== false // Enable by default
17
+ this.verbose = Boolean(options.verbose)
17
18
 
18
19
  // Ensure cache directory exists
19
20
  if (this.enabled) {
@@ -10,16 +10,17 @@ const { showProgress } = require('../ui-helpers')
10
10
 
11
11
  // Pinned gitleaks version for reproducible security scanning
12
12
  const GITLEAKS_VERSION = '8.28.0'
13
- // Real SHA256 checksums from https://github.com/gitleaks/gitleaks/releases/tag/v8.28.0
13
+ // SHA256 checksums of EXTRACTED BINARIES from gitleaks v8.28.0 release
14
+ // Note: These are checksums of the binary itself, not the tarball/zip archives
14
15
  const GITLEAKS_CHECKSUMS = {
15
16
  'linux-x64':
16
- 'a65b5253807a68ac0cafa4414031fd740aeb55f54fb7e55f386acb52e6a840eb',
17
+ '5fd1b3b0073269484d40078662e921d07427340ab9e6ed526ccd215a565b3298',
17
18
  'darwin-x64':
18
- 'edf5a507008b0d2ef4959575772772770586409c1f6f74dabf19cbe7ec341ced',
19
+ 'cf09ad7a85683d90221db8324f036f23c8c29107145e1fc4a0dffbfa9e89c09a',
19
20
  'darwin-arm64':
20
21
  '5588b5d942dffa048720f7e6e1d274283219fb5722a2c7564d22e83ba39087d7',
21
22
  'win32-x64':
22
- 'da6458e8864af553807de1c46a7a8eac0880bd6b99ba56288e87e86a45af884f',
23
+ '54230c22688d19939f316cd3e2e040cd067ece40a3a8c5b684e5110c62ecbf52',
23
24
  }
24
25
 
25
26
  /**
@@ -75,7 +75,7 @@ class ValidationFactory {
75
75
 
76
76
  /**
77
77
  * Run all validators
78
- * @returns {object} Validation results
78
+ * @returns {Promise<object>} Validation results
79
79
  */
80
80
  async validateAll() {
81
81
  const results = {
package/lib/yaml-utils.js CHANGED
@@ -82,17 +82,22 @@ function convertToYaml(obj, indent = 0) {
82
82
  if (Array.isArray(obj)) {
83
83
  obj.forEach(item => {
84
84
  if (typeof item === 'object' && item !== null) {
85
- // For objects in arrays, handle first property inline with dash, rest indented
86
- const itemYaml = convertToYaml(item, indent + 2)
87
- const lines = itemYaml.split('\n').filter(line => line.trim())
88
- if (lines.length > 0) {
89
- // First property goes inline with the dash
90
- yaml += `${spaces}- ${lines[0].trim()}\n`
91
- // Additional properties are properly indented
92
- for (let i = 1; i < lines.length; i++) {
93
- yaml += `${spaces} ${lines[i].trim()}\n`
85
+ // For objects in arrays, prefix first line with "- " and indent rest
86
+ const entries = Object.entries(item)
87
+ entries.forEach(([key, value], idx) => {
88
+ const safeKey = formatYamlValue(key)
89
+ const prefix = idx === 0 ? `${spaces}- ` : `${spaces} `
90
+
91
+ if (Array.isArray(value)) {
92
+ yaml += `${prefix}${safeKey}:\n`
93
+ yaml += convertToYaml(value, indent + 4)
94
+ } else if (typeof value === 'object' && value !== null) {
95
+ yaml += `${prefix}${safeKey}:\n`
96
+ yaml += convertToYaml(value, indent + 4)
97
+ } else {
98
+ yaml += `${prefix}${safeKey}: ${formatYamlValue(value)}\n`
94
99
  }
95
- }
100
+ })
96
101
  } else {
97
102
  yaml += `${spaces}- ${formatYamlValue(item)}\n`
98
103
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qa-architect",
3
- "version": "5.0.0",
3
+ "version": "5.0.6",
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": {
@@ -12,26 +12,26 @@
12
12
  "format": "prettier --write .",
13
13
  "format:check": "prettier --check .",
14
14
  "lint": "eslint . && stylelint \"**/*.{css,scss,sass,less,pcss}\" --allow-empty-input",
15
+ "type-check": "tsc --noEmit",
15
16
  "lint:fix": "eslint . --fix && stylelint \"**/*.{css,scss,sass,less,pcss}\" --fix --allow-empty-input",
16
17
  "security:audit": "npm audit --audit-level high",
17
18
  "security:secrets": "node -e \"const fs=require('fs');const content=fs.readFileSync('package.json','utf8');if(/[\\\"\\'][a-zA-Z0-9+/]{20,}[\\\"\\']/.test(content)){console.error('❌ Potential hardcoded secrets in package.json');process.exit(1)}else{console.log('✅ No secrets detected in package.json')}\"",
18
19
  "security:config": "node setup.js --security-config",
19
20
  "validate:docs": "node setup.js --validate-docs",
20
- "validate:claude": "node scripts/validate-claude-md.js",
21
21
  "validate:comprehensive": "node setup.js --comprehensive --no-markdownlint",
22
- "validate:all": "npm run validate:comprehensive && npm run security:audit && npm run validate:claude",
22
+ "validate:all": "npm run validate:comprehensive && npm run security:audit",
23
23
  "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",
24
- "test": "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-claude-md.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",
25
- "test:unit": "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-claude-md.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",
24
+ "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",
25
+ "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",
26
26
  "test:fast": "npm run test:unit",
27
27
  "test:medium": "npm run test:fast && npm run test:patterns && npm run test:commands",
28
- "test:slow": "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.test.js && npm run test:e2e",
28
+ "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",
29
29
  "test:comprehensive": "npm run test:patterns && npm test && npm run test:commands && npm run test:e2e && npm run security:audit",
30
30
  "test:real-binary": "RUN_REAL_BINARY_TEST=1 node tests/gitleaks-real-binary-test.js",
31
- "test:commands": "node tests/command-execution.test.js",
31
+ "test:commands": "export QAA_DEVELOPER=true && node tests/command-execution.test.js",
32
32
  "test:patterns": "node scripts/validate-command-patterns.js",
33
33
  "test:coverage": "c8 --reporter=html --reporter=text --reporter=lcov npm test",
34
- "test:e2e": "bash scripts/test-e2e-package.sh",
34
+ "test:e2e": "export QAA_DEVELOPER=true && bash scripts/test-e2e-package.sh",
35
35
  "test:all": "npm run test:patterns && npm test && npm run test:commands && npm run test:e2e",
36
36
  "coverage": "npm run test:coverage && echo '\nCoverage report generated in coverage/index.html'",
37
37
  "docs:check": "bash scripts/check-docs.sh",
@@ -63,14 +63,18 @@
63
63
  "security-audit"
64
64
  ],
65
65
  "author": "Brett Stark",
66
- "license": "MIT",
66
+ "license": "SEE LICENSE IN LICENSE",
67
67
  "files": [
68
68
  "setup.js",
69
69
  "create-saas-monetization.js",
70
70
  "config/",
71
+ "docs/",
71
72
  "lib/",
72
73
  "legal/",
73
74
  "marketing/",
75
+ "templates/",
76
+ "scripts/",
77
+ "LICENSE",
74
78
  ".github/",
75
79
  ".prettierrc",
76
80
  ".prettierignore",
@@ -82,12 +86,12 @@
82
86
  ],
83
87
  "repository": {
84
88
  "type": "git",
85
- "url": "git+https://github.com/brettstark73/qa-architect.git"
89
+ "url": "git+https://github.com/vibebuildlab/qa-architect.git"
86
90
  },
87
91
  "bugs": {
88
- "url": "https://github.com/brettstark73/qa-architect/issues"
92
+ "url": "https://github.com/vibebuildlab/qa-architect/issues"
89
93
  },
90
- "homepage": "https://github.com/brettstark73/qa-architect#readme",
94
+ "homepage": "https://vibebuildlab.com/tools/qa-architect",
91
95
  "engines": {
92
96
  "node": ">=20"
93
97
  },
@@ -102,7 +106,9 @@
102
106
  }
103
107
  },
104
108
  "devDependencies": {
109
+ "@types/node": "^20",
105
110
  "actionlint": "^2.0.6",
111
+ "typescript": "^5",
106
112
  "c8": "^10.1.2",
107
113
  "eslint": "^9.12.0",
108
114
  "eslint-plugin-security": "^3.0.1",
@@ -119,7 +125,6 @@
119
125
  },
120
126
  "lint-staged": {
121
127
  "CLAUDE.md": [
122
- "node scripts/validate-claude-md.js",
123
128
  "prettier --write"
124
129
  ],
125
130
  "config/defaults.js": [
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # Documentation consistency checker
3
+ # Run before any release to catch documentation gaps
4
+
5
+ set -e
6
+
7
+ echo "🔍 Checking documentation consistency..."
8
+
9
+ # Check version consistency
10
+ PACKAGE_VERSION=$(node -p "require('./package.json').version")
11
+ if ! grep -q "## \[$PACKAGE_VERSION\]" CHANGELOG.md; then
12
+ echo "❌ CHANGELOG.md missing entry for version $PACKAGE_VERSION"
13
+ exit 1
14
+ fi
15
+
16
+ # Check that setup.js file creation matches README documentation
17
+ echo "📁 Verifying file inventory..."
18
+
19
+ # Extract files created by setup.js
20
+ SETUP_FILES=$(grep -E "writeFileSync.*Path" setup.js | sed -E 's/.*writeFileSync\([^,]+, [^)]+\)//' | wc -l)
21
+ echo "Setup script creates approximately $SETUP_FILES files"
22
+
23
+ # Check for common missing files in README
24
+ MISSING_FILES=()
25
+
26
+ if grep -q "\.nvmrc" setup.js && ! grep -q "\.nvmrc" README.md; then
27
+ MISSING_FILES+=(".nvmrc")
28
+ fi
29
+
30
+ if grep -q "\.npmrc" setup.js && ! grep -q "\.npmrc" README.md; then
31
+ MISSING_FILES+=(".npmrc")
32
+ fi
33
+
34
+ if grep -q "stylelintrc" setup.js && ! grep -q "stylelintrc" README.md; then
35
+ MISSING_FILES+=(".stylelintrc.json")
36
+ fi
37
+
38
+ if grep -q "lighthouserc" setup.js && ! grep -q "lighthouserc" README.md; then
39
+ MISSING_FILES+=(".lighthouserc.js")
40
+ fi
41
+
42
+ if [ ${#MISSING_FILES[@]} -gt 0 ]; then
43
+ echo "❌ README.md missing documentation for files:"
44
+ printf ' - %s\n' "${MISSING_FILES[@]}"
45
+ exit 1
46
+ fi
47
+
48
+ # Check for Python features if implemented
49
+ if grep -q "Python" setup.js; then
50
+ if ! grep -q "Python" README.md; then
51
+ echo "❌ Python features implemented but not documented in README.md"
52
+ exit 1
53
+ fi
54
+ fi
55
+
56
+ # Security validation is now handled by:
57
+ # - /bs:audit --security command
58
+ # - security-auditor agent
59
+ # - npm audit in CI workflows
60
+ # - gitleaks in pre-push hooks
61
+ echo "🔐 Security validation handled by automated tooling (npm audit, gitleaks, CI workflows)"
62
+
63
+ echo "✅ Documentation consistency checks passed!"