create-qa-architect 5.11.1 → 5.12.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.
@@ -0,0 +1,39 @@
1
+ name: Auto Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Get previous tag
20
+ id: prev_tag
21
+ run: |
22
+ PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
23
+ echo "tag=$PREV_TAG" >> $GITHUB_OUTPUT
24
+
25
+ - name: Generate release notes
26
+ run: |
27
+ TAG=${GITHUB_REF#refs/tags/}
28
+ PREV_TAG=${{ steps.prev_tag.outputs.tag }}
29
+ if [ -n "$PREV_TAG" ]; then
30
+ echo "## Changes since $PREV_TAG" > notes.md
31
+ git log ${PREV_TAG}..${TAG} --pretty=format:"- %s" >> notes.md
32
+ echo -e "\n\n**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${TAG}" >> notes.md
33
+ else
34
+ echo "Initial release" > notes.md
35
+ fi
36
+
37
+ - uses: softprops/action-gh-release@v2
38
+ with:
39
+ body_path: notes.md
@@ -32,8 +32,11 @@ concurrency:
32
32
 
33
33
  jobs:
34
34
  # Step 1: Detect project maturity level and package manager
35
+ # Skip for Dependabot PRs - they auto-merge based on their own checks
36
+ # This reduces GitHub Actions minutes by ~50% on active repos
35
37
  detect-maturity:
36
38
  runs-on: ubuntu-latest
39
+ if: github.actor != 'dependabot[bot]' || github.event_name == 'schedule'
37
40
  outputs:
38
41
  maturity: ${{ steps.detect.outputs.maturity }}
39
42
  source-count: ${{ steps.detect.outputs.source-count }}
@@ -338,7 +341,7 @@ jobs:
338
341
  gitleaks-8.28.0-linux-x64-
339
342
 
340
343
  - name: Run real gitleaks binary verification test
341
- if: runner.os == 'Linux'
344
+ if: runner.os == 'Linux' && hashFiles('tests/gitleaks-real-binary-test.js') != ''
342
345
  run: |
343
346
  echo "🔐 Running real gitleaks binary verification test..."
344
347
  QAA_DEVELOPER=true RUN_REAL_BINARY_TEST=1 node tests/gitleaks-real-binary-test.js
@@ -75,6 +75,9 @@ const baseDevDependencies = {
75
75
  '@lhci/cli': '^0.14.0',
76
76
  vitest: '^2.1.8',
77
77
  '@vitest/coverage-v8': '^2.1.8',
78
+ commitlint: '^20.4.1',
79
+ '@commitlint/cli': '^20.4.1',
80
+ '@commitlint/config-conventional': '^20.4.1',
78
81
  }
79
82
 
80
83
  const typeScriptDevDependencies = {
@@ -91,6 +91,81 @@
91
91
  },
92
92
  "additionalProperties": false
93
93
  }
94
+ },
95
+ "performance": {
96
+ "type": "object",
97
+ "description": "Performance budget configuration",
98
+ "properties": {
99
+ "lighthouse": {
100
+ "type": "object",
101
+ "description": "Lighthouse CI performance thresholds",
102
+ "properties": {
103
+ "performance": {
104
+ "type": "number",
105
+ "minimum": 0,
106
+ "maximum": 1,
107
+ "description": "Minimum performance score (0-1)"
108
+ },
109
+ "accessibility": {
110
+ "type": "number",
111
+ "minimum": 0,
112
+ "maximum": 1,
113
+ "description": "Minimum accessibility score (0-1)"
114
+ },
115
+ "bestPractices": {
116
+ "type": "number",
117
+ "minimum": 0,
118
+ "maximum": 1,
119
+ "description": "Minimum best practices score (0-1)"
120
+ },
121
+ "seo": {
122
+ "type": "number",
123
+ "minimum": 0,
124
+ "maximum": 1,
125
+ "description": "Minimum SEO score (0-1)"
126
+ },
127
+ "maxFCP": {
128
+ "type": "number",
129
+ "minimum": 0,
130
+ "description": "Max First Contentful Paint in ms"
131
+ },
132
+ "maxLCP": {
133
+ "type": "number",
134
+ "minimum": 0,
135
+ "description": "Max Largest Contentful Paint in ms"
136
+ },
137
+ "maxCLS": {
138
+ "type": "number",
139
+ "minimum": 0,
140
+ "description": "Max Cumulative Layout Shift"
141
+ },
142
+ "maxTBT": {
143
+ "type": "number",
144
+ "minimum": 0,
145
+ "description": "Max Total Blocking Time in ms"
146
+ }
147
+ },
148
+ "additionalProperties": false
149
+ },
150
+ "bundleSize": {
151
+ "type": "object",
152
+ "description": "Bundle size limits",
153
+ "properties": {
154
+ "maxJs": {
155
+ "type": "string",
156
+ "pattern": "^[0-9]+ [kKmM][bB]$",
157
+ "description": "Max JS bundle size (e.g., '250 kB')"
158
+ },
159
+ "maxCss": {
160
+ "type": "string",
161
+ "pattern": "^[0-9]+ [kKmM][bB]$",
162
+ "description": "Max CSS bundle size (e.g., '50 kB')"
163
+ }
164
+ },
165
+ "additionalProperties": false
166
+ }
167
+ },
168
+ "additionalProperties": false
94
169
  }
95
170
  },
96
171
  "additionalProperties": false
@@ -1,323 +1,123 @@
1
- # GitHub Actions Cost Analysis: Is qa-architect Over-Engineering CI/CD?
1
+ # GitHub Actions Cost Analysis
2
2
 
3
- **Date**: 2026-01-06
4
- **Finding**: YES - qa-architect's default setup is 3-5x more expensive than industry standards for solo/small projects.
3
+ **Updated**: 2026-02-03
4
+ **Budget**: 2,000 mins/month (GitHub Free tier)
5
5
 
6
6
  ---
7
7
 
8
- ## The Problem
8
+ ## Current Status: Within Budget (with fixes)
9
9
 
10
- Your projects are costing **$469/month** in GitHub Actions CI when they should cost **$0-50/month**.
10
+ ### Actual January 2026 Usage (vibebuildlab org)
11
11
 
12
- | Project | Commits/Day | Minutes/Month | Cost/Month | Status |
13
- | -------------------------- | ----------- | ------------- | ---------- | ----------- |
14
- | vibebuildlab | 7.4 | 46,852 min | $358 | 🔴 CRITICAL |
15
- | qa-architect | 1.7 | 15,810 min | $110 | 🔴 HIGH |
16
- | stark-program-intelligence | 1.6 | 2,160 min | $1.28 | 🟢 OK |
17
- | vibelab-claude-setup | 2.0 | 531 min | $0 | OPTIMAL |
12
+ | Repo | Minutes | Runs | Avg/Run |
13
+ | ----------------------- | ---------- | ----- | ------- |
14
+ | qa-architect | 340 | 349 | 1.0 min |
15
+ | postrail | 1,769 | 295 | 6.0 min |
16
+ | vibebuildlab | 89 | 282 | 0.3 min |
17
+ | keyflash | 74 | 187 | 0.4 min |
18
+ | wfhroulette | 56 | 138 | 0.4 min |
19
+ | jobrecon | 56 | 44 | 1.3 min |
20
+ | ai-second-act | 4 | 33 | 0.1 min |
21
+ | vibebuildlab-newsletter | 1 | 22 | 0.0 min |
22
+ | **TOTAL** | **~2,400** | 1,350 | 1.8 min |
18
23
 
19
- ---
20
-
21
- ## Root Cause Analysis
22
-
23
- ### What qa-architect Is Doing (vibebuildlab example)
24
-
25
- **Current quality.yml**: 161 minutes per commit, runs 221 times/month
26
-
27
- ```yaml
28
- Jobs running on EVERY push:
29
- 1. detect-maturity (1 job) ~ 2 min
30
- 2. core-checks (2 jobs) ~ 10 min # Node 20 + 22 matrix
31
- 3. linting (1 job) ~ 8 min
32
- 4. security (1 job) ~ 25 min # Gitleaks + Semgrep + 3× npm audit
33
- 5. tests (2 jobs) ~ 30 min # Node 20 + 22 matrix
34
- 6. documentation (1 job) ~ 15 min # Only if production-ready
35
- 7. summary (1 job) ~ 1 min
36
-
37
- TOTAL: ~90-100 minutes per push (when all jobs run)
38
- ```
39
-
40
- **Problems identified**:
41
-
42
- 1. ❌ **No path filters** - Runs full CI on docs/README commits
43
- 2. ❌ **Duplicate matrix testing** - Both core-checks AND tests run Node 20/22
44
- 3. ❌ **Security overkill** - Gitleaks + Semgrep + npm audit (3 variants) on EVERY push
45
- 4. ❌ **No job concurrency limits** - Rapid commits queue up expensive builds
46
- 5. ❌ **Production checks on every commit** - Documentation validation should be release-only
47
-
48
- ---
49
-
50
- ## Industry Standards (Successful Projects)
51
-
52
- ### Vite (Major Framework, 1000+ contributors)
53
-
54
- - **Runtime**: 50-60 min/commit
55
- - **Path filters**: ✅ Skips tests on docs-only changes
56
- - **Matrix**: Node 20, 22, 24 (3 versions)
57
- - **Cross-platform**: Only on latest Node, not all versions
58
- - **Security**: Runs on schedule, not every commit
24
+ ### February Projection (Pre-Fix)
59
25
 
60
- ### Ky (Popular Library, Sindre Sorhus)
26
+ Based on Feb 1-3 data extrapolated:
61
27
 
62
- - **Runtime**: 10-15 min/commit
63
- - **Matrix**: Node 20, 22, 24, latest (4 versions)
64
- - **Platform**: macOS only (assumes Linux/Windows compatibility)
65
- - **Security**: Separate workflow
28
+ - **Projected**: 3,425 mins/month
29
+ - **Budget**: 2,000 mins/month
30
+ - **Overage**: 71%
66
31
 
67
- ### Common Patterns
32
+ ### Root Cause: Dependabot PR Spam
68
33
 
69
- 1. **Minimal on push** - Lint + test current Node only
70
- 2. **Matrix testing** - Only on main branch or scheduled
71
- 3. **Security scans** - Weekly/nightly, not per commit
72
- 4. **Documentation** - Only on release branches
73
- 5. **Path filters** - Skip CI for docs/README/LICENSE changes
74
-
75
- **Sources**:
76
-
77
- - [GitHub Actions alternatives for modern CI/CD](https://northflank.com/blog/github-actions-alternatives)
78
- - [Ultimate free CI/CD for open-source projects](https://dev.to/itnext/the-ultimate-free-ci-cd-for-your-open-source-projects-3bkd)
34
+ | Repo | Dependabot % of Runs |
35
+ | ------------ | -------------------- |
36
+ | jobrecon | 91% |
37
+ | postrail | 63% |
38
+ | keyflash | 53% |
39
+ | qa-architect | 8% |
40
+ | vibebuildlab | 0% |
79
41
 
80
42
  ---
81
43
 
82
- ## Recommended Changes
83
-
84
- ### Phase 1: Quick Wins (Reduce by 60-70%)
85
-
86
- #### 1. Add Path Filters
87
-
88
- ```yaml
89
- on:
90
- push:
91
- paths-ignore:
92
- - '**.md'
93
- - 'docs/**'
94
- - 'LICENSE'
95
- - '.gitignore'
96
- - '.editorconfig'
97
- ```
98
-
99
- **Savings**: ~20% of commits are docs-only
100
- **vibebuildlab**: 7,117 min/month saved ($57/mo)
44
+ ## Fixes Applied (v5.11.2)
101
45
 
102
- #### 2. Reduce Matrix Redundancy
46
+ ### 1. Skip Quality Checks for Dependabot PRs
103
47
 
104
48
  ```yaml
105
- # BEFORE: 2 matrix jobs (core-checks + tests)
106
- core-checks:
107
- matrix:
108
- node-version: [20, 22] # Runs twice
109
-
110
- tests:
111
- matrix:
112
- node-version: [20, 22] # Runs twice again!
113
-
114
- # AFTER: 1 matrix job only
115
- tests:
116
- matrix:
117
- node-version: [20, 22] # Runs once
49
+ detect-maturity:
50
+ if: github.actor != 'dependabot[bot]' || github.event_name == 'schedule'
118
51
  ```
119
52
 
120
- **Savings**: 50% reduction in matrix jobs
121
- **vibebuildlab**: ~18,000 min/month saved ($144/mo)
122
-
123
- #### 3. Move Security to Scheduled Workflow
53
+ **Savings**: ~50% reduction in runs (~1,400 mins/month)
124
54
 
125
- ```yaml
126
- # New file: .github/workflows/security-weekly.yml
127
- on:
128
- schedule:
129
- - cron: '0 0 * * 0' # Weekly on Sunday
130
- workflow_dispatch: # Manual trigger
131
-
132
- jobs:
133
- security:
134
- runs-on: ubuntu-latest
135
- steps:
136
- - name: Gitleaks
137
- - name: Semgrep
138
- - name: npm audit
139
- ```
55
+ ### 2. Minimal Workflow Mode (v5.11.1)
140
56
 
141
- **Savings**: From 221 runs/month 4 runs/month
142
- **vibebuildlab**: ~5,400 min/month saved ($43/mo)
57
+ - Security scans: Weekly only (not every push)
58
+ - Test matrix: Node 22 only (not [20, 22])
59
+ - Path filters: Skip docs-only changes
60
+ - Concurrency: Cancel in-progress runs
143
61
 
144
- ### Phase 2: Industry-Standard Setup (Get under $50/mo total)
145
-
146
- ```yaml
147
- # .github/workflows/ci.yml
148
- name: CI
149
-
150
- on:
151
- push:
152
- branches: [main, develop]
153
- paths-ignore:
154
- - '**.md'
155
- - 'docs/**'
156
- - 'LICENSE'
157
- pull_request:
158
-
159
- concurrency:
160
- group: ${{ github.workflow }}-${{ github.ref }}
161
- cancel-in-progress: true # Cancel old runs
162
-
163
- jobs:
164
- # Quick checks on every commit (current Node only)
165
- quick-check:
166
- runs-on: ubuntu-latest
167
- steps:
168
- - uses: actions/checkout@v5
169
- - uses: actions/setup-node@v6
170
- with:
171
- node-version: 22
172
- cache: npm
173
- - run: npm ci
174
- - run: npm run lint
175
- - run: npm run format:check
176
- - run: npm test
177
-
178
- # Matrix testing only on main branch
179
- cross-version:
180
- if: github.ref == 'refs/heads/main'
181
- runs-on: ubuntu-latest
182
- strategy:
183
- matrix:
184
- node-version: [20, 22]
185
- steps:
186
- - uses: actions/checkout@v5
187
- - uses: actions/setup-node@v6
188
- with:
189
- node-version: ${{ matrix.node-version }}
190
- cache: npm
191
- - run: npm ci
192
- - run: npm test
193
- ```
62
+ ### Expected February Usage (Post-Fix)
194
63
 
195
- **Estimated runtime**:
196
-
197
- - Pull requests: 5-10 min (quick-check only)
198
- - Main branch: 15-20 min (quick-check + cross-version)
199
-
200
- **Estimated cost for vibebuildlab**:
201
-
202
- - Current: 46,852 min/month ($358/mo)
203
- - After changes: ~3,500 min/month ($12/mo)
204
- - **Savings: $346/month (97% reduction)**
64
+ | Metric | Before | After | Savings |
65
+ | ------------------ | ------ | ------------ | ------- |
66
+ | Minutes/Month | 3,425 | ~1,200-1,500 | 55-65% |
67
+ | Budget Utilization | 171% | 60-75% | ✅ |
205
68
 
206
69
  ---
207
70
 
208
- ## Strategic Recommendations
209
-
210
- ### For Solo Developers / Small Teams
211
-
212
- **Make all repos public** → GitHub Actions is FREE
213
-
214
- - If code can be public, this is the best option
215
- - vibebuildlab, qa-architect could potentially be public
216
-
217
- ### For Private Repos
71
+ ## Workflow Tiers
218
72
 
219
- **Option A: Minimal CI** (Recommended)
73
+ qa-architect supports three workflow modes:
220
74
 
221
- ```
222
- Lint + format on every commit (5 min)
223
- Test on current Node only (10 min)
224
- Matrix testing on main branch only
225
- Security scans weekly, not per commit
226
- ✅ Documentation checks on releases only
227
-
228
- Total: ~500-1,000 min/month ($0-8/mo)
229
- ```
230
-
231
- **Option B: Self-Hosted Runner**
75
+ | Mode | When to Use | Estimated Cost |
76
+ | --------------------- | ----------------------- | -------------- |
77
+ | **Minimal** (default) | Solo dev, private repos | ~$0-10/mo |
78
+ | **Standard** | Team projects, PRs | ~$10-30/mo |
79
+ | **Comprehensive** | Enterprise, compliance | ~$50-100/mo |
232
80
 
233
- - Rent $10-20/mo VPS (Hetzner, DigitalOcean)
234
- - Install GitHub self-hosted runner
235
- - Total cost: $20/mo for UNLIMITED minutes
236
- - **Best if you have 5+ active private repos**
81
+ ### Minimal Mode (Default)
237
82
 
238
- **Option C: Strategic Testing**
239
-
240
- ```yaml
241
- # Only test what matters
242
- on:
243
- pull_request: # Test on PRs
244
- push:
245
- branches: [main] # Test on main
246
- paths-ignore:
247
- - '**.md'
248
- - 'docs/**'
249
-
250
- # Skip matrix on draft PRs
251
- if: github.event.pull_request.draft == false
252
- ```
83
+ - Single Node.js version (22)
84
+ - Security scans weekly only
85
+ - Path filters enabled
86
+ - Skip Dependabot PRs
87
+ - Concurrency limits
253
88
 
254
- ### For qa-architect Product
89
+ ### Standard Mode (`--workflow-standard`)
255
90
 
256
- **Current Default** (what qa-architect creates):
91
+ - Matrix on main only (20, 22)
92
+ - Security on PR + weekly
93
+ - Full test coverage
257
94
 
258
- - Comprehensive CI for solo devs
259
- - ❌ Costs $100-350/mo for typical projects
260
- - ❌ Over-engineering: Gitleaks + Semgrep on every commit
95
+ ### Comprehensive Mode (`--workflow-comprehensive`)
261
96
 
262
- **Recommended Default**:
263
-
264
- ```yaml
265
- Basic (Free tier friendly):
266
- ✅ Lint + format + test (current Node only)
267
- ✅ Security scans weekly
268
- ✅ Matrix testing opt-in only
269
- ✅ Path filters enabled by default
270
-
271
- Pro tier enhancements:
272
- ✅ Add matrix testing (if needed)
273
- ✅ Add cross-platform testing (if needed)
274
- ✅ Add comprehensive security (scheduled)
275
- ```
97
+ - Matrix every commit
98
+ - Inline security scans
99
+ - E2E tests on every PR
276
100
 
277
101
  ---
278
102
 
279
- ## Action Items
280
-
281
- ### Immediate (This Week)
282
-
283
- 1. Add path filters to all repos → Save 20% instantly
284
- 2. Move security scans to weekly schedule → Save 95% of security costs
285
- 3. Remove duplicate matrix jobs → Save 50% of test costs
286
-
287
- ### Short Term (This Month)
288
-
289
- 1. Redesign qa-architect default template (minimal-first approach)
290
- 2. Create three tiers:
291
- - `--minimal`: Lint + test (current Node), FREE tier friendly
292
- - `--standard`: + matrix testing (main branch only)
293
- - `--comprehensive`: Current setup (for large teams)
294
- 3. Add `--public` flag that optimizes for unlimited minutes
103
+ ## Optimization Tips
295
104
 
296
- ### Long Term (Q1 2026)
297
-
298
- 1. Add cost analyzer to `npx create-qa-architect` (show estimated costs)
299
- 2. Default to minimal setup, prompt for upgrades
300
- 3. Document self-hosted runner setup guide
301
- 4. Create cost monitoring dashboard (track actual usage)
105
+ 1. **Make repos public** → Unlimited free minutes
106
+ 2. **Group Dependabot updates** → Fewer PRs/week
107
+ 3. **Use path filters** Skip docs-only changes
108
+ 4. **Disable CI on inactive repos** Zero cost
302
109
 
303
110
  ---
304
111
 
305
- ## Conclusion
306
-
307
- **YES, you're right to question this.**
308
-
309
- qa-architect is creating **enterprise-grade CI for solo developers**, resulting in:
112
+ ## Commands
310
113
 
311
- - 3-5x longer CI times than industry standards
312
- - 10-20x higher costs than necessary
313
- - Excessive testing that doesn't add proportional value
114
+ ```bash
115
+ # Check workflow mode
116
+ npx create-qa-architect --check-maturity
314
117
 
315
- **The fix**: Shift to "minimal by default, comprehensive on demand."
118
+ # Analyze CI costs
119
+ npx create-qa-architect --analyze-ci
316
120
 
317
- For your specific projects:
318
-
319
- - **vibebuildlab**: $358/mo → $12/mo (implement Phase 1 + 2)
320
- - **qa-architect**: $110/mo → $5/mo (same changes)
321
- - **Total savings**: $451/month ($5,412/year)
322
-
323
- Or just make repos public → **$0/month**.
121
+ # Switch to minimal mode
122
+ npx create-qa-architect --workflow-minimal --force
123
+ ```
@@ -119,6 +119,11 @@ class ProjectMaturityDetector {
119
119
  stats.testFiles === 0
120
120
  ) {
121
121
  maturity = 'bootstrap'
122
+ } else if (
123
+ stats.totalSourceFiles < MATURITY_THRESHOLDS.MIN_BOOTSTRAP_FILES &&
124
+ stats.testFiles > 0
125
+ ) {
126
+ maturity = 'bootstrap'
122
127
  } else if (
123
128
  stats.testFiles > 0 &&
124
129
  stats.totalSourceFiles >= MATURITY_THRESHOLDS.MIN_BOOTSTRAP_FILES &&
@@ -25,6 +25,7 @@ function generateLighthouseConfig(options = {}) {
25
25
  hasThresholds = false,
26
26
  collectUrl = 'http://localhost:3000',
27
27
  staticDistDir = null,
28
+ budgets = null,
28
29
  } = options
29
30
 
30
31
  const collectConfig = staticDistDir
@@ -34,29 +35,42 @@ function generateLighthouseConfig(options = {}) {
34
35
  startServerReadyPattern: 'ready|listening|started',
35
36
  startServerReadyTimeout: 30000,`
36
37
 
37
- const assertConfig = hasThresholds
38
- ? `
38
+ let assertConfig
39
+ if (hasThresholds) {
40
+ // Use custom budgets from .qualityrc.json if provided, otherwise defaults
41
+ const b = budgets || {}
42
+ const fcp = b.maxFCP || 2000
43
+ const lcp = b.maxLCP || 2500
44
+ const cls = b.maxCLS || 0.1
45
+ const tbt = b.maxTBT || 300
46
+ const perf = b.performance || 0.8
47
+ const a11y = b.accessibility || 0.9
48
+ const bp = b.bestPractices || 0.9
49
+ const seo = b.seo || 0.9
50
+
51
+ assertConfig = `
39
52
  assert: {
40
53
  preset: 'lighthouse:recommended',
41
54
  assertions: {
42
55
  // Performance
43
- 'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
44
- 'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
45
- 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
46
- 'total-blocking-time': ['warn', { maxNumericValue: 300 }],
56
+ 'first-contentful-paint': ['warn', { maxNumericValue: ${fcp} }],
57
+ 'largest-contentful-paint': ['error', { maxNumericValue: ${lcp} }],
58
+ 'cumulative-layout-shift': ['error', { maxNumericValue: ${cls} }],
59
+ 'total-blocking-time': ['warn', { maxNumericValue: ${tbt} }],
47
60
 
48
61
  // Categories (0-1 scale)
49
- 'categories:performance': ['warn', { minScore: 0.8 }],
50
- 'categories:accessibility': ['error', { minScore: 0.9 }],
51
- 'categories:best-practices': ['warn', { minScore: 0.9 }],
52
- 'categories:seo': ['warn', { minScore: 0.9 }],
62
+ 'categories:performance': ['warn', { minScore: ${perf} }],
63
+ 'categories:accessibility': ['error', { minScore: ${a11y} }],
64
+ 'categories:best-practices': ['warn', { minScore: ${bp} }],
65
+ 'categories:seo': ['warn', { minScore: ${seo} }],
53
66
 
54
67
  // Allow some common warnings
55
68
  'unsized-images': 'off',
56
69
  'uses-responsive-images': 'off',
57
70
  },
58
71
  },`
59
- : `
72
+ } else {
73
+ assertConfig = `
60
74
  assert: {
61
75
  // Basic assertions for Free tier - just warnings, no failures
62
76
  assertions: {
@@ -64,6 +78,7 @@ function generateLighthouseConfig(options = {}) {
64
78
  'categories:best-practices': ['warn', { minScore: 0.7 }],
65
79
  },
66
80
  },`
81
+ }
67
82
 
68
83
  return `module.exports = {
69
84
  ci: {
@@ -86,7 +101,7 @@ function generateLighthouseConfig(options = {}) {
86
101
  * @returns {Array} size-limit config array
87
102
  */
88
103
  function generateSizeLimitConfig(options = {}) {
89
- const { projectPath = process.cwd() } = options
104
+ const { projectPath = process.cwd(), budgets = null } = options
90
105
 
91
106
  // Detect build output paths
92
107
  const possibleDists = ['dist', 'build', '.next', 'out', 'public']
@@ -99,6 +114,10 @@ function generateSizeLimitConfig(options = {}) {
99
114
  }
100
115
  }
101
116
 
117
+ // Use custom budgets from .qualityrc.json if provided
118
+ const jsLimit = (budgets && budgets.maxJs) || null
119
+ const cssLimit = (budgets && budgets.maxCss) || null
120
+
102
121
  // Detect if it's a Next.js app
103
122
  const isNextJS =
104
123
  fs.existsSync(path.join(projectPath, 'next.config.js')) ||
@@ -108,7 +127,7 @@ function generateSizeLimitConfig(options = {}) {
108
127
  return [
109
128
  {
110
129
  path: '.next/static/**/*.js',
111
- limit: '300 kB',
130
+ limit: jsLimit || '300 kB',
112
131
  webpack: false,
113
132
  },
114
133
  ]
@@ -117,11 +136,11 @@ function generateSizeLimitConfig(options = {}) {
117
136
  return [
118
137
  {
119
138
  path: `${distDir}/**/*.js`,
120
- limit: '250 kB',
139
+ limit: jsLimit || '250 kB',
121
140
  },
122
141
  {
123
142
  path: `${distDir}/**/*.css`,
124
- limit: '50 kB',
143
+ limit: cssLimit || '50 kB',
125
144
  },
126
145
  ]
127
146
  }
@@ -525,8 +544,8 @@ function getQualityToolsDependencies(features = {}) {
525
544
  }
526
545
 
527
546
  if (features.commitlint) {
528
- deps['@commitlint/cli'] = '^19.0.0'
529
- deps['@commitlint/config-conventional'] = '^19.0.0'
547
+ deps['@commitlint/cli'] = '^20.4.1'
548
+ deps['@commitlint/config-conventional'] = '^20.4.1'
530
549
  }
531
550
 
532
551
  if (features.axeCore) {
@@ -109,46 +109,17 @@ id = "jwt-token"
109
109
  regex = '''eyJ[A-Za-z0-9_/+-]{10,}={0,2}'''
110
110
  tags = ["key", "JWT"]
111
111
 
112
- [[rules]]
113
- description = "Base64 encoded secrets (long)"
114
- id = "base64-secret"
115
- regex = '''[A-Za-z0-9+/]{40,}={0,2}'''
116
- tags = ["secret", "base64"]
117
- keywords = ["secret", "key", "token", "password"]
118
-
119
112
  [[rules]]
120
113
  description = "Environment variable secrets"
121
114
  id = "env-secret"
122
115
  regex = '''(?i)(api_key|secret|password|token)\\s*=\\s*['""][^'"\\s]{10,}['""]'''
123
116
  tags = ["env", "secret"]
124
117
 
125
- # Allowlist for test files and examples
126
- [[rules.allowlist]]
127
- description = "Test secrets and examples"
128
- regexes = [
129
- '''test_secret_.*''',
130
- '''example_.*''',
131
- '''dummy_.*''',
132
- '''fake_.*'''
133
- ]
134
- paths = [
135
- '''tests/''',
136
- '''test/''',
137
- '''__tests__/''',
138
- '''examples/''',
139
- '''docs/''',
140
- '''.md$'''
141
- ]
142
-
143
- # Global allowlist for common false positives
144
- [[allowlist]]
145
- description = "Common false positives"
146
- regexes = [
147
- '''EXAMPLE_.*''',
148
- '''your_.*_here''',
149
- '''replace_with_.*''',
150
- '''TODO:.*'''
151
- ]
118
+ # Allowlist for test/example files (broad exclusion)
119
+ [allowlist]
120
+ description = "Test and example files"
121
+ regexes = ['''test_secret_.*|example_.*|dummy_.*|fake_.*|EXAMPLE_.*|your_.*_here|replace_with_.*|TODO:.*''']
122
+ paths = ['''(tests/|test/|__tests__/|examples/|docs/|\\.md$|\\.gitleaksignore$|node_modules/|dist/|build/|\\.next/|coverage/)''']
152
123
  `
153
124
  }
154
125
 
@@ -179,7 +179,17 @@ function injectWorkflowMode(workflowContent, mode) {
179
179
  "has-css: 'false'"
180
180
  )
181
181
 
182
- // 4. Simplify "Display Detection Report" to show only package manager info
182
+ // 4. Remove dev-only gitleaks binary test steps (only relevant for qa-architect itself)
183
+ updated = updated.replace(
184
+ /\s+- name: Cache gitleaks binary for real download test[\s\S]*?restore-keys: \|[^\n]*\n[^\n]*\n/,
185
+ '\n'
186
+ )
187
+ updated = updated.replace(
188
+ /\s+- name: Run real gitleaks binary verification test[\s\S]*?node tests\/gitleaks-real-binary-test\.js\n/,
189
+ '\n'
190
+ )
191
+
192
+ // 5. Simplify "Display Detection Report" to show only package manager info
183
193
  updated = updated.replace(
184
194
  /- name: Display Detection Report\s+run: \|[\s\S]*?echo "Has CSS files:[^"]*"/,
185
195
  `- name: Display Detection Report
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qa-architect",
3
- "version": "5.11.1",
3
+ "version": "5.12.0",
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": {
@@ -51,7 +51,8 @@
51
51
  "size": "size-limit",
52
52
  "size:why": "size-limit --why",
53
53
  "test:a11y": "vitest run tests/accessibility.test.js",
54
- "test:coverage:check": "vitest run --coverage --coverage.thresholds.lines=70 --coverage.thresholds.functions=70"
54
+ "test:coverage:check": "vitest run --coverage --coverage.thresholds.lines=70 --coverage.thresholds.functions=70",
55
+ "test:changed": "vitest run --changed HEAD~1 --passWithNoTests"
55
56
  },
56
57
  "keywords": [
57
58
  "qa-architect",
@@ -82,11 +82,17 @@ echo " ⚡ Speed Bonus: $SPEED_BONUS"
82
82
  echo ""
83
83
 
84
84
  # Test tier selection based on risk score
85
+ # NOTE: E2E tests and slow command tests are ALWAYS excluded from pre-push
86
+ # - E2E tests: Require dev server, browsers, proper infrastructure (run in CI only)
87
+ # - Command tests: Take 60+ seconds, verify npm scripts work (run in CI only)
88
+ # These run in GitHub Actions on every PR and push to main
89
+
85
90
  if [[ $RISK_SCORE -ge 7 ]]; then
86
- echo "🔴 HIGH RISK - Comprehensive validation"
87
- echo " • All tests + security audit"
88
- # Runs: npm run test:comprehensive 2>/dev/null || npm run test 2>/dev/null || npm test
89
- npm run test:comprehensive 2>/dev/null || npm run test 2>/dev/null || npm test
91
+ echo "🔴 HIGH RISK - Comprehensive validation (pre-push)"
92
+ echo " • Unit + integration tests + security audit"
93
+ echo " • (E2E and command tests run in CI only)"
94
+ # Runs: npm run test:medium 2>/dev/null || npm run test:fast 2>/dev/null || npm test
95
+ npm run test:medium 2>/dev/null || npm run test:fast 2>/dev/null || npm test
90
96
  elif [[ $RISK_SCORE -ge 4 ]]; then
91
97
  echo "🟡 MEDIUM RISK - Standard validation"
92
98
  echo " • Fast tests + integration (excludes slow tests)"
package/setup.js CHANGED
@@ -927,13 +927,44 @@ HELP:
927
927
  const hasConventionalCommits = hasFeature('conventionalCommits')
928
928
  const hasCoverageThresholds = hasFeature('coverageThresholds')
929
929
 
930
+ // Load .qualityrc.json for performance budgets and check overrides
931
+ let performanceBudgets = null
932
+ let qualityChecks = {}
933
+ const qualityrcPath = path.join(projectPath, '.qualityrc.json')
934
+ if (fs.existsSync(qualityrcPath)) {
935
+ try {
936
+ const qualityrc = JSON.parse(fs.readFileSync(qualityrcPath, 'utf8'))
937
+ if (qualityrc.performance) {
938
+ performanceBudgets = qualityrc.performance
939
+ }
940
+ if (qualityrc.checks) {
941
+ qualityChecks = qualityrc.checks
942
+ }
943
+ } catch {
944
+ // Ignore parse errors - config validation handles this elsewhere
945
+ }
946
+ }
947
+
948
+ // Helper: check if a quality check is enabled (respects .qualityrc.json overrides)
949
+ function isCheckEnabled(checkName, licenseDefault) {
950
+ const override = qualityChecks[checkName]
951
+ if (override && override.enabled === false) return false
952
+ if (override && override.enabled === true) return true
953
+ // "auto" or missing: use license-based default
954
+ return licenseDefault
955
+ }
956
+
930
957
  // 1. Lighthouse CI - available to all, thresholds for Pro+
931
- if (hasLighthouse) {
958
+ if (isCheckEnabled('lighthouse', hasLighthouse)) {
932
959
  try {
933
960
  const lighthousePath = path.join(projectPath, 'lighthouserc.js')
934
961
  if (!fs.existsSync(lighthousePath)) {
935
962
  writeLighthouseConfig(projectPath, {
936
963
  hasThresholds: hasLighthouseThresholds,
964
+ budgets:
965
+ performanceBudgets && performanceBudgets.lighthouse
966
+ ? performanceBudgets.lighthouse
967
+ : null,
937
968
  })
938
969
  addedTools.push(
939
970
  hasLighthouseThresholds
@@ -953,7 +984,12 @@ HELP:
953
984
  if (hasBundleSizeLimits) {
954
985
  try {
955
986
  if (!pkgJson.content['size-limit']) {
956
- writeSizeLimitConfig(projectPath)
987
+ writeSizeLimitConfig(projectPath, {
988
+ budgets:
989
+ performanceBudgets && performanceBudgets.bundleSize
990
+ ? performanceBudgets.bundleSize
991
+ : null,
992
+ })
957
993
  addedTools.push('Bundle size limits (size-limit)')
958
994
  }
959
995
  } catch (error) {