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
package/setup.js CHANGED
@@ -113,6 +113,27 @@ const STYLELINT_EXTENSION_GLOB = `*.{${STYLELINT_EXTENSIONS.join(',')}}`
113
113
  const STYLELINT_SCAN_EXCLUDES = new Set(EXCLUDE_DIRECTORIES.STYLELINT)
114
114
  const MAX_STYLELINT_SCAN_DEPTH = SCAN_LIMITS.STYLELINT_MAX_DEPTH
115
115
 
116
+ function injectCollaborationSteps(workflowContent, options = {}) {
117
+ const { enableSlackAlerts = false, enablePrComments = false } = options
118
+ let updated = workflowContent
119
+
120
+ if (workflowContent.includes('# ALERTS_PLACEHOLDER')) {
121
+ const alertsJob = enableSlackAlerts
122
+ ? ` alerts:\n runs-on: ubuntu-latest\n needs: [summary]\n if: failure() || cancelled()\n steps:\n - name: Notify Slack on failures\n env:\n SLACK_WEBHOOK_URL: \${{ secrets.SLACK_WEBHOOK_URL }}\n run: |\n if [ -z "$SLACK_WEBHOOK_URL" ]; then\n echo "::warning::SLACK_WEBHOOK_URL not set; skipping Slack notification"\n exit 0\n fi\n payload='{"text":"❌ Quality checks failed for $GITHUB_REPOSITORY ($GITHUB_REF)"}'\n curl -X POST -H 'Content-type: application/json' --data "$payload" "$SLACK_WEBHOOK_URL"\n`
123
+ : ' # Slack alerts not enabled (use --alerts-slack to add)'
124
+ updated = updated.replace('# ALERTS_PLACEHOLDER', alertsJob)
125
+ }
126
+
127
+ if (workflowContent.includes('# PR_COMMENTS_PLACEHOLDER')) {
128
+ const prSteps = enablePrComments
129
+ ? ` - name: Post PR summary comment\n if: github.event_name == 'pull_request'\n uses: actions/github-script@v7\n with:\n script: |\n const summaryPath = process.env.GITHUB_STEP_SUMMARY\n const fs = require('fs')\n const body = summaryPath && fs.existsSync(summaryPath)\n ? fs.readFileSync(summaryPath, 'utf8')\n : 'Quality checks completed.'\n const { context, github } = require('@actions/github')\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.payload.pull_request.number,\n body,\n })\n`
130
+ : ' # PR comment step not enabled (use --pr-comments to add)'
131
+ updated = updated.replace('# PR_COMMENTS_PLACEHOLDER', prSteps)
132
+ }
133
+
134
+ return updated
135
+ }
136
+
116
137
  /**
117
138
  * Safely reads directory contents without throwing on permission errors
118
139
  *
@@ -312,6 +333,13 @@ function parseArguments(rawArgs) {
312
333
  const isValidateConfigMode = sanitizedArgs.includes('--validate-config')
313
334
  const isActivateLicenseMode = sanitizedArgs.includes('--activate-license')
314
335
  const isDryRun = sanitizedArgs.includes('--dry-run')
336
+ const ciProviderIndex = sanitizedArgs.findIndex(arg => arg === '--ci')
337
+ const ciProvider =
338
+ ciProviderIndex !== -1 && sanitizedArgs[ciProviderIndex + 1]
339
+ ? sanitizedArgs[ciProviderIndex + 1].toLowerCase()
340
+ : 'github'
341
+ const enableSlackAlerts = sanitizedArgs.includes('--alerts-slack')
342
+ const enablePrComments = sanitizedArgs.includes('--pr-comments')
315
343
 
316
344
  // Custom template directory - use raw args to preserve valid path characters (&, <, >, etc.)
317
345
  // Normalize path to prevent traversal attacks and make absolute
@@ -344,6 +372,9 @@ function parseArguments(rawArgs) {
344
372
  isValidateConfigMode,
345
373
  isActivateLicenseMode,
346
374
  isDryRun,
375
+ ciProvider,
376
+ enableSlackAlerts,
377
+ enablePrComments,
347
378
  customTemplatePath,
348
379
  disableNpmAudit,
349
380
  disableGitleaks,
@@ -378,6 +409,9 @@ function parseArguments(rawArgs) {
378
409
  isValidateConfigMode,
379
410
  isActivateLicenseMode,
380
411
  isDryRun,
412
+ ciProvider,
413
+ enableSlackAlerts,
414
+ enablePrComments,
381
415
  customTemplatePath,
382
416
  disableNpmAudit,
383
417
  disableGitleaks,
@@ -444,7 +478,12 @@ function parseArguments(rawArgs) {
444
478
  isTelemetryStatusMode,
445
479
  isErrorReportingStatusMode,
446
480
  isCheckMaturityMode,
481
+ isValidateConfigMode,
482
+ isActivateLicenseMode,
447
483
  isDryRun,
484
+ ciProvider,
485
+ enableSlackAlerts,
486
+ enablePrComments,
448
487
  customTemplatePath,
449
488
  disableNpmAudit,
450
489
  disableGitleaks,
@@ -481,6 +520,7 @@ SETUP OPTIONS:
481
520
  --update Update existing configuration
482
521
  --deps Add basic dependency monitoring (Free Tier)
483
522
  --dependency-monitoring Same as --deps
523
+ --ci <provider> Select CI provider: github (default) | gitlab | circleci
484
524
  --template <path> Use custom templates from specified directory
485
525
  --dry-run Preview changes without modifying files
486
526
 
@@ -506,6 +546,10 @@ GRANULAR TOOL CONTROL:
506
546
  --no-markdownlint Disable markdownlint markdown formatting checks
507
547
  --no-eslint-security Disable ESLint security rule checking
508
548
 
549
+ ALERTING & COLLABORATION (GitHub CI):
550
+ --alerts-slack Add Slack webhook notification step (expects secret SLACK_WEBHOOK_URL)
551
+ --pr-comments Add PR summary comment step (uses GitHub token)
552
+
509
553
  EXAMPLES:
510
554
  npx create-qa-architect@latest
511
555
  → Set up quality automation with all tools
@@ -697,7 +741,7 @@ HELP:
697
741
  if (!capCheck.allowed) {
698
742
  console.error(`❌ ${capCheck.reason}`)
699
743
  console.error(
700
- ' Upgrade to Pro, Team, or Enterprise for unlimited runs: https://vibebuildlab.com/cqa'
744
+ ' Upgrade to Pro, Team, or Enterprise for unlimited runs: https://vibebuildlab.com/tools/qa-architect'
701
745
  )
702
746
  process.exit(1)
703
747
  }
@@ -822,9 +866,31 @@ HELP:
822
866
  showUpgradeMessage('Framework-Aware Dependency Grouping')
823
867
  }
824
868
 
869
+ // Auto-enable Dependabot on GitHub if token available
870
+ console.log('\n🔧 Attempting to enable Dependabot on GitHub...')
871
+ try {
872
+ const { setupDependabot } = require('./lib/github-api')
873
+ const result = await setupDependabot(projectPath, { verbose: true })
874
+
875
+ if (result.success) {
876
+ console.log('✅ Dependabot alerts and security updates enabled!')
877
+ } else if (result.errors.length > 0) {
878
+ console.log('⚠️ Could not auto-enable Dependabot:')
879
+ result.errors.forEach(err => console.log(` • ${err}`))
880
+ console.log('\n💡 Manual steps needed:')
881
+ console.log(' • Go to GitHub repo → Settings → Code security')
882
+ console.log(
883
+ ' • Enable "Dependabot alerts" and "Dependabot security updates"'
884
+ )
885
+ }
886
+ } catch (error) {
887
+ console.log('⚠️ Could not auto-enable Dependabot:', error.message)
888
+ console.log('\n💡 Manual steps:')
889
+ console.log(' • Enable Dependabot in GitHub repo settings')
890
+ }
891
+
825
892
  console.log('\n💡 Next steps:')
826
893
  console.log(' • Review and commit .github/dependabot.yml')
827
- console.log(' • Enable Dependabot alerts in GitHub repository settings')
828
894
  console.log(
829
895
  ' • Dependabot will start monitoring weekly for dependency updates'
830
896
  )
@@ -856,11 +922,11 @@ HELP:
856
922
  console.log('\n❌ License activation failed.')
857
923
  console.log('• Check your license key format (QAA-XXXX-XXXX-XXXX-XXXX)')
858
924
  console.log('• Verify your email address')
859
- console.log('• Contact support: hello@aibuilderlab.com')
925
+ console.log('• Contact support: support@vibebuildlab.com')
860
926
  }
861
927
  } catch (error) {
862
928
  console.error('\n❌ License activation error:', error.message)
863
- console.log('Contact support for assistance: hello@aibuilderlab.com')
929
+ console.log('Contact support for assistance: support@vibebuildlab.com')
864
930
  }
865
931
 
866
932
  process.exit(0)
@@ -961,7 +1027,7 @@ HELP:
961
1027
  if (!repoCheck.allowed) {
962
1028
  console.error(`\n❌ ${repoCheck.reason}`)
963
1029
  console.error(
964
- ' Upgrade to Pro for unlimited repos: https://vibebuildlab.com/cqa'
1030
+ ' Upgrade to Pro for unlimited repos: https://vibebuildlab.com/tools/qa-architect'
965
1031
  )
966
1032
  process.exit(1)
967
1033
  }
@@ -969,7 +1035,7 @@ HELP:
969
1035
  // Register this repo
970
1036
  incrementUsage('repo', 1, repoId)
971
1037
  console.log(
972
- `✅ Registered repo (FREE tier: ${currentRepos.length + 1}/1 repos used)`
1038
+ `✅ Registered repo (FREE tier: ${(repoCheck.usage?.repoCount || 0) + 1}/1 repos used)`
973
1039
  )
974
1040
  }
975
1041
  }
@@ -1054,6 +1120,8 @@ HELP:
1054
1120
  description: '',
1055
1121
  main: 'index.js',
1056
1122
  scripts: {},
1123
+ devDependencies: {},
1124
+ 'lint-staged': {},
1057
1125
  }
1058
1126
  }
1059
1127
 
@@ -1215,8 +1283,8 @@ HELP:
1215
1283
  }
1216
1284
 
1217
1285
  packageJson['lint-staged'] = mergeLintStaged(
1218
- packageJson['lint-staged'] || {},
1219
1286
  finalLintStaged,
1287
+ packageJson['lint-staged'] || {},
1220
1288
  { stylelintTargets },
1221
1289
  patternIncludesStylelintExtension
1222
1290
  )
@@ -1351,28 +1419,72 @@ HELP:
1351
1419
  process.exit(1)
1352
1420
  }
1353
1421
 
1354
- // Create .github/workflows directory if it doesn't exist
1422
+ // Create CI configuration based on provider
1355
1423
  const configSpinner = showProgress('Copying configuration files...')
1356
- const workflowDir = path.join(process.cwd(), '.github', 'workflows')
1357
- if (!fs.existsSync(workflowDir)) {
1358
- fs.mkdirSync(workflowDir, { recursive: true })
1359
- console.log('📁 Created .github/workflows directory')
1360
- }
1424
+ const githubWorkflowDir = path.join(process.cwd(), '.github', 'workflows')
1361
1425
 
1362
- // Copy workflow file if it doesn't exist
1363
- const workflowFile = path.join(workflowDir, 'quality.yml')
1364
- if (!fs.existsSync(workflowFile)) {
1365
- const templateWorkflow =
1366
- templateLoader.getTemplate(
1367
- templates,
1368
- path.join('.github', 'workflows', 'quality.yml')
1369
- ) ||
1370
- fs.readFileSync(
1371
- path.join(__dirname, '.github/workflows/quality.yml'),
1372
- 'utf8'
1373
- )
1374
- fs.writeFileSync(workflowFile, templateWorkflow)
1375
- console.log('✅ Added GitHub Actions workflow')
1426
+ if (ciProvider === 'gitlab') {
1427
+ const gitlabConfigPath = path.join(process.cwd(), '.gitlab-ci.yml')
1428
+ if (!fs.existsSync(gitlabConfigPath)) {
1429
+ const templateGitlab =
1430
+ templateLoader.getTemplate(
1431
+ templates,
1432
+ path.join('ci', 'gitlab-ci.yml')
1433
+ ) ||
1434
+ fs.readFileSync(
1435
+ path.join(__dirname, 'templates/ci/gitlab-ci.yml'),
1436
+ 'utf8'
1437
+ )
1438
+ fs.writeFileSync(gitlabConfigPath, templateGitlab)
1439
+ console.log('✅ Added GitLab CI workflow')
1440
+ }
1441
+ } else if (ciProvider === 'circleci') {
1442
+ const circleDir = path.join(process.cwd(), '.circleci')
1443
+ if (!fs.existsSync(circleDir)) {
1444
+ fs.mkdirSync(circleDir, { recursive: true })
1445
+ console.log('📁 Created .circleci directory')
1446
+ }
1447
+ const circleConfigPath = path.join(circleDir, 'config.yml')
1448
+ if (!fs.existsSync(circleConfigPath)) {
1449
+ const templateCircle =
1450
+ templateLoader.getTemplate(
1451
+ templates,
1452
+ path.join('ci', 'circleci-config.yml')
1453
+ ) ||
1454
+ fs.readFileSync(
1455
+ path.join(__dirname, 'templates/ci/circleci-config.yml'),
1456
+ 'utf8'
1457
+ )
1458
+ fs.writeFileSync(circleConfigPath, templateCircle)
1459
+ console.log('✅ Added CircleCI workflow')
1460
+ }
1461
+ } else {
1462
+ // Default: GitHub Actions
1463
+ if (!fs.existsSync(githubWorkflowDir)) {
1464
+ fs.mkdirSync(githubWorkflowDir, { recursive: true })
1465
+ console.log('📁 Created .github/workflows directory')
1466
+ }
1467
+
1468
+ const workflowFile = path.join(githubWorkflowDir, 'quality.yml')
1469
+ if (!fs.existsSync(workflowFile)) {
1470
+ let templateWorkflow =
1471
+ templateLoader.getTemplate(
1472
+ templates,
1473
+ path.join('.github', 'workflows', 'quality.yml')
1474
+ ) ||
1475
+ fs.readFileSync(
1476
+ path.join(__dirname, '.github/workflows/quality.yml'),
1477
+ 'utf8'
1478
+ )
1479
+
1480
+ templateWorkflow = injectCollaborationSteps(templateWorkflow, {
1481
+ enableSlackAlerts,
1482
+ enablePrComments,
1483
+ })
1484
+
1485
+ fs.writeFileSync(workflowFile, templateWorkflow)
1486
+ console.log('✅ Added GitHub Actions workflow')
1487
+ }
1376
1488
  }
1377
1489
 
1378
1490
  // Copy Prettier config if it doesn't exist
@@ -1582,7 +1694,7 @@ let tier = 'FREE'
1582
1694
  try {
1583
1695
  const data = JSON.parse(fs.readFileSync(licenseFile, 'utf8'))
1584
1696
  tier = (data && data.tier) || 'FREE'
1585
- } catch (_error) {
1697
+ } catch {
1586
1698
  tier = 'FREE'
1587
1699
  }
1588
1700
 
@@ -1595,14 +1707,14 @@ try {
1595
1707
  if (data.month === currentMonth) {
1596
1708
  usage = { ...usage, ...data }
1597
1709
  }
1598
- } catch (_error) {
1710
+ } catch {
1599
1711
  // First run or corrupt file – start fresh
1600
1712
  }
1601
1713
 
1602
1714
  const CAP = 50
1603
1715
  if (usage.prePushRuns >= CAP) {
1604
1716
  console.error('❌ Free tier limit reached: ' + usage.prePushRuns + '/' + CAP + ' pre-push runs this month')
1605
- console.error(' Upgrade to Pro, Team, or Enterprise: https://vibebuildlab.com/cqa')
1717
+ console.error(' Upgrade to Pro, Team, or Enterprise: https://vibebuildlab.com/tools/qa-architect')
1606
1718
  process.exit(1)
1607
1719
  }
1608
1720
 
@@ -1762,20 +1874,25 @@ echo "✅ Pre-push validation passed!"
1762
1874
  console.log('✅ Added requirements-dev.txt')
1763
1875
  }
1764
1876
 
1765
- // Copy Python workflow
1766
- const pythonWorkflowFile = path.join(workflowDir, 'quality-python.yml')
1767
- if (!fs.existsSync(pythonWorkflowFile)) {
1768
- const templatePythonWorkflow =
1769
- templateLoader.getTemplate(
1770
- templates,
1771
- path.join('config', 'quality-python.yml')
1772
- ) ||
1773
- fs.readFileSync(
1774
- path.join(__dirname, 'config/quality-python.yml'),
1775
- 'utf8'
1776
- )
1777
- fs.writeFileSync(pythonWorkflowFile, templatePythonWorkflow)
1778
- console.log('✅ Added Python GitHub Actions workflow')
1877
+ // Copy Python workflow (GitHub Actions only)
1878
+ if (ciProvider === 'github') {
1879
+ const pythonWorkflowFile = path.join(
1880
+ githubWorkflowDir,
1881
+ 'quality-python.yml'
1882
+ )
1883
+ if (!fs.existsSync(pythonWorkflowFile)) {
1884
+ const templatePythonWorkflow =
1885
+ templateLoader.getTemplate(
1886
+ templates,
1887
+ path.join('config', 'quality-python.yml')
1888
+ ) ||
1889
+ fs.readFileSync(
1890
+ path.join(__dirname, 'config/quality-python.yml'),
1891
+ 'utf8'
1892
+ )
1893
+ fs.writeFileSync(pythonWorkflowFile, templatePythonWorkflow)
1894
+ console.log('✅ Added Python GitHub Actions workflow')
1895
+ }
1779
1896
  }
1780
1897
 
1781
1898
  // Create tests directory if it doesn't exist