create-qa-architect 5.13.6 → 5.14.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,130 @@
1
+ # Plan: Vibe-Code Auditor
2
+
3
+ **Created:** 2026-05-27
4
+ **Status:** Active
5
+ **Branch:** feat/vibe-code-auditor (new from feat/polar-migration)
6
+
7
+ ---
8
+
9
+ ## Problem
10
+
11
+ QA Architect currently covers 2/7 security audit categories (secrets via Gitleaks Pro, and CVEs via npm audit free). The product is positioned as a quality bootstrap tool, but the 2026 market opportunity is "vibe-code security auditor" — a self-serve CLI that catches OWASP Top-10 patterns, injection vectors, auth gaps, production misconfigs, and hallucinated packages in AI-generated code. No CLI tool in the market does this for solo/indie developers. New web-based competitors (VibeDoctor, Vibe App Scanner) are filling the web-SaaS gap but not the CLI gap. The current product needs a new `audit` subcommand powered by semgrep, covering 5/7 categories in free tier, repositioned to match the buyer persona: "worried vibe coder about to ship."
12
+
13
+ Additionally the pricing needs a drop from $49/mo to $29/mo to match market expectations, and the README/help text needs a full repositioning.
14
+
15
+ ---
16
+
17
+ ## Options Considered
18
+
19
+ ### Option A: Add `audit` subcommand via semgrep (chosen)
20
+
21
+ Add `lib/commands/audit.js` that runs semgrep with an extended security ruleset covering SQL injection, XSS, command injection, auth bypass, production misconfigs, hardcoded secrets, and hallucinated package checks. Integrate as free-tier feature (basic 5 categories) with Pro extension (hallucination check + full OWASP pack + `--fix` prompt generation).
22
+
23
+ **Pros:**
24
+
25
+ - Semgrep rules already exist in `.semgrep/defensive-patterns.yaml` — extend rather than build from scratch
26
+ - Consistent with existing spawnSync/arg-array security pattern
27
+ - CLI-native = key differentiator vs web-based competitors
28
+ - Adds credible "auditor" positioning without changing existing ship-check/pr-check Pro features
29
+
30
+ **Cons:**
31
+
32
+ - Semgrep must be installed on user machine (document in README, add detection+guidance)
33
+ - Semgrep rules won't catch everything — must be honest about coverage
34
+
35
+ ### Option B: Use eslint-plugin-security only
36
+
37
+ Run eslint with security plugin, no new dependency.
38
+
39
+ **Pros:** No semgrep required
40
+
41
+ **Cons:** Much weaker coverage — misses SQL injection, auth bypass, command injection patterns. eslint-plugin-security already part of existing setup flow so no net new value for "audit" use case.
42
+
43
+ ### Option C: Bundle semgrep binary (like gitleaks)
44
+
45
+ Pin and cache semgrep binary like gitleaks v8.28.0.
46
+
47
+ **Cons:** Semgrep binary is 50-100MB — not viable for npm package. Document as prerequisite instead.
48
+
49
+ ---
50
+
51
+ ## Decision
52
+
53
+ **Approach:** Option A — semgrep-powered `audit` subcommand + pricing update + README repositioning
54
+
55
+ **Rationale:** Semgrep is the de-facto OSS SAST engine with a large rule library and a simple CLI. The existing `.semgrep/defensive-patterns.yaml` gives a head start. The CLI gap in the market is real — web SaaS competitors all require uploading code to their service; this runs entirely locally, which is a trust advantage for security-conscious builders. Pricing drop from $49 to $29 reduces conversion friction without undermining value.
56
+
57
+ ---
58
+
59
+ ## Implementation Plan
60
+
61
+ ### New Files to Create
62
+
63
+ - `lib/commands/audit.js` — main audit command handler
64
+ - `.semgrep/vibe-audit-rules.yaml` — extended security ruleset (SQL, XSS, command injection, auth, CORS, debug mode, hardcoded secrets, missing validation, hallucinated packages)
65
+ - `tests/audit.test.js` — unit tests for audit command
66
+
67
+ ### Files to Modify
68
+
69
+ - `setup.js` — add `--audit` flag parsing + routing to `handleAudit()`, add to help text
70
+ - `lib/licensing.js` — add `auditBasic` (free) and `auditPro` (Pro) feature flags; update pricing from $49→$29
71
+ - `README.md` — full repositioning: vibe-code security auditor, lead with `audit` command, update pricing table
72
+ - `package.json` — update description, add `audit` to scripts if helpful
73
+
74
+ ### Execution Order
75
+
76
+ 1. **Create branch** `feat/vibe-code-auditor` from `feat/polar-migration`
77
+ 2. **Create `.semgrep/vibe-audit-rules.yaml`** — the audit categories (SQL/XSS/cmd injection, auth bypass, CORS/debug misconfigs, hardcoded creds, missing rate limits). Build on existing defensive-patterns.yaml, add new categories.
78
+ 3. **Create `lib/commands/audit.js`** — the audit command:
79
+ - Detect if semgrep is installed, provide install guidance if not
80
+ - Run semgrep with both defensive-patterns.yaml and vibe-audit-rules.yaml
81
+ - Run npm audit (CVEs, free)
82
+ - Check for hallucinated packages (Pro: verify package names against npm registry)
83
+ - Produce structured output: Critical/High/Medium/Low findings with file:line, what's wrong, why it matters, suggested fix
84
+ - Pro: `--fix` flag generates Claude Code prompts for each finding
85
+ - Support `--json` output flag
86
+ - Support `--out <path>` to write markdown report to file
87
+ 4. **Update `setup.js`** — add `--audit` and `--audit-fix` flags, routing, and help text
88
+ 5. **Update `lib/licensing.js`** — add feature flags, change Pro price from 4900 to 2900 (cents)
89
+ 6. **Create `tests/audit.test.js`** — tests for: semgrep not installed handling, result parsing, severity mapping, json output, markdown output
90
+ 7. **Update `README.md`** — full rewrite of positioning sections: new tagline, lead with `audit`, update pricing table ($29/mo), update command reference
91
+ 8. **Run full test suite** — `npm test`, `npm run lint`
92
+ 9. **Version bump** to 5.14.0 (new feature, not patch)
93
+ 10. **Commit + PR** with `/bs:quality --merge`
94
+
95
+ ### Out of Scope
96
+
97
+ - Supabase RLS gap detection (requires DB schema access — defer to v2)
98
+ - GDPR/soft-delete/audit-log checks (high false-positive risk — defer)
99
+ - Python audit rules (defer — focus on JS/TS/Next.js stack for v1)
100
+ - IDE plugin (CLI only)
101
+ - Web dashboard
102
+ - Auto-fix (only generates Claude Code prompts, doesn't apply them)
103
+ - Agentic workflow scanning (LangGraph/CrewAI — different product)
104
+ - Renaming the product (not worth it at this stage)
105
+
106
+ ---
107
+
108
+ ## Verification Steps
109
+
110
+ 1. `node setup.js --audit` on this repo — should detect 0 critical findings (or real ones in test fixtures)
111
+ 2. `node setup.js --audit --json` — valid JSON output
112
+ 3. `node setup.js --audit --out /tmp/report.md` — file written
113
+ 4. Test with semgrep not installed — should show clear install guidance, not crash
114
+ 5. `node tests/audit.test.js` — all pass
115
+ 6. `npm test` — all 50+ tests still pass
116
+ 7. `npm run lint` — clean
117
+ 8. `node setup.js --license-status` — confirms Pro price shows $29/mo
118
+
119
+ ---
120
+
121
+ ## Notes / Gotchas
122
+
123
+ - Semgrep detection: use `which semgrep` or `semgrep --version` via spawnSync, handle ENOENT gracefully
124
+ - Semgrep output is JSON (`semgrep --json`), parse `results[].path`, `.start.line`, `.check_id`, `.message`, `.severity`, `.extra.message`
125
+ - Semgrep severity levels: `ERROR` → Critical, `WARNING` → High/Medium depending on rule metadata
126
+ - The existing `.semgrep/defensive-patterns.yaml` rules are already good for SQL injection, command injection, auth bypass, CORS, hardcoded secrets — extend rather than duplicate
127
+ - Hallucinated package check (Pro): hit `https://registry.npmjs.org/<package>` for each dep in package.json, flag 404s. Cache results to avoid rate limits.
128
+ - Pricing: `lib/licensing.js` stores price in cents. Change from `4900` to `2900`. Also update any string references to "$49" → "$29".
129
+ - The `quality.yml` template-as-product invariant: if audit is added to the project's own CI, ensure it uses `npx @latest` pattern and not `node_modules/` references.
130
+ - `--fix` flag for Pro: format as "Copy this prompt into Claude Code:" followed by a structured prompt that includes the file path, line number, issue, and the recommended fix pattern.
@@ -0,0 +1,111 @@
1
+ # Polar.sh Migration Plan
2
+
3
+ **Status:** in progress
4
+ **Date:** 2026-05-17
5
+ **Replaces:** Stripe-direct billing
6
+
7
+ ## Why
8
+
9
+ We're migrating billing from **Stripe-direct** to **Polar.sh** (Merchant-of-Record).
10
+
11
+ | | Stripe direct | Polar.sh (MoR) |
12
+ | ---------------------------------------- | ------------------------------------------------------------------------- | ----------------------- |
13
+ | Effective fee on $49/mo | ~3.5% | ~4.8% (~1.3% premium) |
14
+ | Global sales tax / VAT / GST | **We owe it** (~$200-400/mo for Anrok at scale, plus state registrations) | Polar collects + remits |
15
+ | Customer portal (cancel/update/invoices) | Build it | Built-in |
16
+ | Dunning / failed payment retries | Build it | Built-in |
17
+ | Effort to ship v1 | High (tax, portal, dunning) | Low (webhook swap only) |
18
+
19
+ Crossover where Stripe-direct wins: ~$50K MRR. Until then, Polar is **cheaper in total cost** and ships faster.
20
+
21
+ ## Architecture: what stays, what changes
22
+
23
+ ### Stays (the moat)
24
+
25
+ - `lib/license-signing.js` — Ed25519 signing primitives (re-exports `@buildproven/license-core`)
26
+ - `lib/license-validator.js` — offline signature verification
27
+ - `lib/licensing.js` — tier definitions, feature gates, activation flow
28
+ - `public-key.pem` bundled in the npm package — CLI verifies signed payloads offline
29
+ - `lib/blob-storage.js` — Vercel Blob layout for private DB + public signed registry
30
+ - `--activate-license` CLI flow — fetches public registry, falls back to cached offline data
31
+ - License key format `QAA-XXXX-XXXX-XXXX-XXXX`, deterministic from customer ID
32
+
33
+ ### Changes
34
+
35
+ - `webhook-handler.js` — event source swap: Stripe `checkout.session.completed` → Polar `subscription.created/active/canceled/revoked`. Same Vercel Blob writes, same signing.
36
+ - `docs/STRIPE-LIVE-MODE-DEPLOYMENT.md` → archived. Replaced by `docs/POLAR-DEPLOYMENT.md`.
37
+ - `lib/billing-dashboard.html` → archived. Polar's hosted customer portal replaces it.
38
+ - Buy URLs (`buildproven.ai/qa-architect`) → Polar checkout URL.
39
+ - `admin-license.js` → kept, comments updated to clarify it's a manual fallback only.
40
+
41
+ ### New
42
+
43
+ - `subscription.canceled` / `subscription.revoked` → revocation list. Signed JSON at known URL, cached by CLI with grace period so offline CI doesn't break. Closes the "cancel but keep Pro forever" loophole.
44
+ - `COMMERCIAL.md` — paid-tier terms gated by the license-key check at runtime.
45
+ - `LICENSE` swap: custom EULA → standard **Apache-2.0**.
46
+
47
+ ## Why we don't use Polar's built-in license keys
48
+
49
+ Polar's built-in license-key benefit requires online validation against `/v1/customer-portal/license-keys/validate`. Our CLI is designed for **offline verification** — `npx create-qa-architect` must work in CI sandboxes with no outbound HTTP. We use Polar only for billing/MoR/checkout/portal/dunning. Our existing Ed25519 signing + Vercel Blob + offline-verifying CLI stays as-is.
50
+
51
+ ## Polar webhook events we handle
52
+
53
+ | Event | Action |
54
+ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------- |
55
+ | `subscription.created` | Generate license key, sign payload, write to private DB + public signed registry |
56
+ | `subscription.active` | Idempotent re-issue (covers renewal + late activations) |
57
+ | `subscription.updated` | If `product_id` changed (plan switch), update tier in DB |
58
+ | `subscription.canceled` | Mark as `pending_cancel` in private DB. Subscription is still active until `current_period_end`. **Do not** revoke yet. |
59
+ | `subscription.revoked` | Move license key to revocation list. CLI will refuse it after next registry pull (with cache + grace period). |
60
+
61
+ ## Polar product setup (manual, user does this)
62
+
63
+ 1. Create Polar org at https://polar.sh
64
+ 2. Create product **"QA Architect Pro"** with two prices:
65
+ - $49/mo (recurring monthly)
66
+ - $490/yr (recurring yearly)
67
+ 3. Save the `product_id` — single product, two prices.
68
+ 4. Configure webhook endpoint: `https://<your-vercel-domain>/webhook`
69
+ 5. Webhook secret → env var `POLAR_WEBHOOK_SECRET`
70
+ 6. API token (for any server-side Polar API calls) → env var `POLAR_ACCESS_TOKEN`
71
+
72
+ ## Env vars (replaces Stripe vars)
73
+
74
+ | Old (Stripe) | New (Polar) |
75
+ | ------------------------------ | ----------------------------------------- |
76
+ | `STRIPE_SECRET_KEY` | `POLAR_ACCESS_TOKEN` |
77
+ | `STRIPE_WEBHOOK_SECRET` | `POLAR_WEBHOOK_SECRET` |
78
+ | `LICENSE_REGISTRY_PRIVATE_KEY` | (unchanged) |
79
+ | `LICENSE_REGISTRY_KEY_ID` | (unchanged) |
80
+ | `BLOB_READ_WRITE_TOKEN` | (unchanged) |
81
+ | (none) | `POLAR_PRO_PRODUCT_ID` — maps to PRO tier |
82
+
83
+ ## Verification
84
+
85
+ Before declaring done:
86
+
87
+ 1. `npm test` — full suite passes
88
+ 2. `npm run lint` — clean
89
+ 3. Manual smoke test: simulate a `subscription.created` event with Polar's CLI / Postman → verify license appears in Blob → run `npx . --activate-license` with the issued key → confirm Pro feature unlocks.
90
+ 4. Manual revocation test: simulate `subscription.revoked` → confirm license appears in revocation list → confirm CLI rejects key after registry pull.
91
+
92
+ ## Replicate to claude-kit-pro
93
+
94
+ Same migration, same architecture. Differences:
95
+
96
+ - License key prefix differs (`CKP-` instead of `QAA-`)
97
+ - Webhook URL differs (deploy under claude-kit-pro's Vercel project)
98
+ - `POLAR_PRO_PRODUCT_ID` env var points at claude-kit-pro's Polar product
99
+
100
+ Follow this doc step-by-step in `../claude-kit-pro/`.
101
+
102
+ ## Rollback
103
+
104
+ If Polar fails for any reason, the migration is reversible in ~half a day:
105
+
106
+ 1. Restore `webhook-handler.js` from git (it was just an event-source swap)
107
+ 2. Restore `docs/STRIPE-LIVE-MODE-DEPLOYMENT.md`
108
+ 3. Repoint Vercel webhook to Stripe events
109
+ 4. Existing signed licenses in Vercel Blob keep working — they're product-agnostic.
110
+
111
+ The signing/verification layer never depended on the billing provider. That's why this swap is cheap.
@@ -0,0 +1,159 @@
1
+ # Pro Feature Expansion — May 2026
2
+
3
+ Spec for 4 new Pro-tier commands. Positioning: "quality gate for AI-assisted small teams."
4
+
5
+ ## 1. `--ship-check` (unified release readiness)
6
+
7
+ **CLI**: `npx create-qa-architect --ship-check [--json] [--out <path>]`
8
+
9
+ **Module**: `lib/commands/ship-check.js`
10
+
11
+ **Gating**: requires Pro tier (proxy: `hasFeature('coverageThresholds')`).
12
+
13
+ **Behavior**: orchestrates existing Pro checks, never re-implements them. For each check:
14
+
15
+ - run the existing command/validator in a child process or via direct import
16
+ - capture pass/fail + summary
17
+ - never fail-fast; collect all results
18
+
19
+ Checks (in order):
20
+
21
+ 1. Lint (`npm run lint` if script exists)
22
+ 2. Tests (`npm test` if script exists — short timeout, allow opt-out via `--skip-tests`)
23
+ 3. Security scan (gitleaks current-files, plus `npm audit --omit=dev` if package.json)
24
+ 4. Coverage thresholds (read `coverage/coverage-summary.json` if present, compare to `.qualityrc.json` thresholds)
25
+ 5. Bundle size (run `size-limit` if configured)
26
+ 6. Lighthouse thresholds (skip if not configured — info only)
27
+ 7. Env validation (check `.env.example` vs documented env vars)
28
+ 8. CI cost summary (call existing `analyze-ci` module functions in `--summary` mode)
29
+ 9. Docs validation (existing docs validator)
30
+
31
+ **Output**:
32
+
33
+ - Default: human-readable terminal report with section headers + final verdict.
34
+ - `--json`: machine-readable JSON (for CI consumption).
35
+ - `--out report.md`: write markdown suitable for PR comments.
36
+
37
+ **Verdict logic**:
38
+
39
+ - `SHIP`: zero failures, zero critical warnings.
40
+ - `REVIEW`: warnings but no failures.
41
+ - `BLOCK`: any failure.
42
+
43
+ **Exit code**: 0 on SHIP/REVIEW, 1 on BLOCK.
44
+
45
+ ---
46
+
47
+ ## 2. `--pr-check` (diff-aware risk classifier)
48
+
49
+ **CLI**: `npx create-qa-architect --pr-check [--base <branch>] [--json] [--out <path>]`
50
+
51
+ **Module**: `lib/commands/pr-check.js`
52
+
53
+ **Gating**: requires Pro tier.
54
+
55
+ **Behavior**:
56
+
57
+ 1. Determine base branch (default: `main`, fallback `master`).
58
+ 2. Get diff: `git diff --name-status <base>...HEAD`.
59
+ 3. Classify each changed file by path patterns + content sniff:
60
+ - **HIGH risk**: auth, crypto, payments, env files, db migrations, GitHub workflows, security headers, license logic, anything matching `/auth|crypto|payment|stripe|webhook|migration|secret|token|key/i`.
61
+ - **MEDIUM risk**: config (package.json, tsconfig, eslint), public API surface (`index.ts`, `lib/**` exports), dependency changes (`package*.json`, `requirements.txt`).
62
+ - **LOW risk**: docs (`*.md`), tests (`*.test.*`, `tests/**`), comments-only.
63
+ 4. For each non-test source file changed, check if a matching test file changed too. Flag missing tests.
64
+ 5. For HIGH-risk files: check if covered by CODEOWNERS (if file exists).
65
+ 6. Emit risk summary + per-file table.
66
+
67
+ **Output**: markdown report (PR-comment-ready) with:
68
+
69
+ - Risk summary (counts per tier)
70
+ - Missing tests warning
71
+ - High-risk file list with reasons
72
+ - Verdict: SHIP / REVIEW / BLOCK (BLOCK only if HIGH + no tests + no codeowner)
73
+
74
+ **Exit code**: 0 on SHIP/REVIEW, 1 on BLOCK (configurable via `--no-fail`).
75
+
76
+ ---
77
+
78
+ ## 3. CI Doctor (expand `--analyze-ci`)
79
+
80
+ **CLI**: existing `--analyze-ci` adds new `--doctor` flag for the extra checks. Default still shows cost analysis.
81
+
82
+ **Module**: extend `lib/commands/analyze-ci.js` — add a `runDoctor(workflows)` function.
83
+
84
+ **New findings** (each with concrete fix suggestion):
85
+
86
+ 1. **Duplicated jobs**: detect jobs with identical `runs-on` + steps signature → suggest reusable workflow.
87
+ 2. **Missing path filters**: workflows triggered on every push without `paths:` or `paths-ignore:` → suggest path filters for monorepos / docs-only changes.
88
+ 3. **Expensive matrix**: matrix with >10 combinations → suggest pruning or `include`/`exclude`.
89
+ 4. **Cache mistakes**: `actions/setup-node` without `cache:` parameter → suggest enabling.
90
+ 5. **Unnecessary scheduled runs**: cron more frequent than weekly with no obvious need → suggest reducing.
91
+ 6. **Flaky test detection**: parse `gh run list --json` if `gh` CLI available, look for jobs with success rate <90% over last 30 runs. Skip gracefully if `gh` not authenticated.
92
+
93
+ **Output**: appended section to existing report. Each finding shows: title, affected workflow/job, fix suggestion (1-2 lines), estimated savings if applicable.
94
+
95
+ ---
96
+
97
+ ## 4. `--history-scan` (historical secrets)
98
+
99
+ **CLI**: `npx create-qa-architect --history-scan [--depth <N>] [--json]`
100
+
101
+ **Module**: `lib/commands/history-scan.js`
102
+
103
+ **Gating**: requires `hasFeature('securityScanning')`.
104
+
105
+ **Behavior**:
106
+
107
+ 1. Reuse `resolveGitleaksBinary()` from `lib/validation/config-security.js`.
108
+ 2. Run: `<gitleaks> detect --no-banner --redact --report-format=json --report-path=<tmp> --log-opts="--all"` (or `HEAD~<depth>` if `--depth` given).
109
+ 3. Parse JSON output, deduplicate by `{secret, file, commit}`.
110
+ 4. Group findings by commit SHA, list files, secret types.
111
+ 5. Report counts per secret type + top 10 oldest exposures.
112
+
113
+ **Output**: terminal report + optional JSON. Markdown export for PR.
114
+
115
+ **Exit code**: 0 if zero findings, 1 if any.
116
+
117
+ **Safety**: pass `--all` only when explicitly requested; default `HEAD~1000` to bound cost on huge repos.
118
+
119
+ ---
120
+
121
+ ## Licensing changes
122
+
123
+ Add flags to `lib/licensing.js` FEATURES map:
124
+
125
+ - `shipCheck`: PRO only
126
+ - `prCheck`: PRO only
127
+ - `ciDoctor`: PRO only (expansion of existing `ciCostAnalysis`)
128
+ - `historicalSecretsScan`: PRO only (under existing `securityScanning` umbrella)
129
+
130
+ Update PRO roadmap array. Add FREE roadmap line: "❌ No release readiness gate (--ship-check), risk-aware PR review, CI doctor, or historical secrets scan".
131
+
132
+ ---
133
+
134
+ ## Testing
135
+
136
+ One test file per command:
137
+
138
+ - `tests/ship-check.test.js`
139
+ - `tests/pr-check.test.js`
140
+ - `tests/ci-doctor.test.js`
141
+ - `tests/history-scan.test.js`
142
+
143
+ Each covers:
144
+
145
+ - Free tier blocked (proper upgrade message)
146
+ - Pro tier runs (via `QAA_DEVELOPER=true` or stub license)
147
+ - Output format validates (markdown structure / JSON shape)
148
+ - Edge cases: empty diff (pr-check), no workflows (ci-doctor), no .git history (history-scan), no coverage report (ship-check)
149
+
150
+ Goal: keep coverage ≥75% lines / 70% functions per project standard.
151
+
152
+ ---
153
+
154
+ ## Out of scope (deferred)
155
+
156
+ - LLM-powered fix suggestions (depends on API key, adds cost dimension)
157
+ - Monorepo selective CI (deeper architecture change)
158
+ - Team dashboard (needs hosted component)
159
+ - PR inline annotations via Checks API (depends on GH App / token model; document for v6)
@@ -12,7 +12,11 @@ const path = require('path')
12
12
  const { execSync } = require('child_process')
13
13
  const yaml = require('js-yaml')
14
14
  const { showProgress } = require('../ui-helpers')
15
- const { hasFeature, showUpgradeMessage } = require('../licensing')
15
+ const {
16
+ hasFeature,
17
+ showUpgradeMessage,
18
+ ensureLicenseFresh,
19
+ } = require('../licensing')
16
20
 
17
21
  const DAYS_PER_MONTH = 30
18
22
  const DEFAULT_PULL_REQUEST_FACTOR = 0.8
@@ -771,20 +775,26 @@ function generateReport(analysis) {
771
775
  }
772
776
 
773
777
  /**
774
- * Main handler for --analyze-ci command
778
+ * Main handler for --analyze-ci command. When `options.doctor` is true,
779
+ * appends the CI Doctor diagnostics (flaky tests, duplicated jobs, etc.)
775
780
  */
776
- async function handleAnalyzeCi() {
781
+ async function handleAnalyzeCi(options = {}) {
777
782
  const projectPath = process.cwd()
778
783
 
784
+ await ensureLicenseFresh()
779
785
  if (!hasFeature('ciCostAnalysis')) {
780
786
  showUpgradeMessage('GitHub Actions cost analysis')
781
787
  process.exit(1)
782
788
  }
783
789
 
790
+ if (options.doctor && !hasFeature('ciDoctor')) {
791
+ showUpgradeMessage('CI Doctor (workflow health + flaky test detection)')
792
+ process.exit(1)
793
+ }
794
+
784
795
  const spinner = showProgress('Analyzing GitHub Actions workflows...')
785
796
 
786
797
  try {
787
- // Step 1: Discover workflows
788
798
  const workflowFiles = discoverWorkflows(projectPath)
789
799
 
790
800
  if (workflowFiles.length === 0) {
@@ -796,7 +806,6 @@ async function handleAnalyzeCi() {
796
806
  process.exit(1)
797
807
  }
798
808
 
799
- // Step 2: Parse and analyze workflows
800
809
  const workflows = []
801
810
  for (const wf of workflowFiles) {
802
811
  try {
@@ -815,13 +824,8 @@ async function handleAnalyzeCi() {
815
824
  }
816
825
  }
817
826
 
818
- // Step 3: Get commit frequency
819
827
  const commitStats = getCommitFrequency(projectPath)
820
-
821
- // Step 4: Calculate costs
822
828
  const costs = calculateMonthlyCosts(workflows, commitStats.commitsPerDay)
823
-
824
- // Step 5: Analyze optimization opportunities
825
829
  const optimizations = analyzeOptimizations(
826
830
  workflows,
827
831
  commitStats.commitsPerDay
@@ -829,7 +833,6 @@ async function handleAnalyzeCi() {
829
833
 
830
834
  spinner.succeed('Analysis complete')
831
835
 
832
- // Step 6: Generate report
833
836
  generateReport({
834
837
  workflows,
835
838
  costs,
@@ -837,6 +840,12 @@ async function handleAnalyzeCi() {
837
840
  optimizations,
838
841
  })
839
842
 
843
+ if (options.doctor) {
844
+ const { runDoctorChecks, buildDoctorReport } = require('./ci-doctor')
845
+ const findings = runDoctorChecks(workflows, projectPath, options)
846
+ process.stdout.write(buildDoctorReport(findings))
847
+ }
848
+
840
849
  process.exit(0)
841
850
  } catch (error) {
842
851
  spinner.fail('Analysis failed')