@vibecodeqa/cli 0.16.0 → 0.18.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.
Files changed (47) hide show
  1. package/README.md +73 -63
  2. package/dist/check-meta.d.ts +1 -0
  3. package/dist/check-meta.js +58 -6
  4. package/dist/cli.js +48 -10
  5. package/dist/detect.js +24 -2
  6. package/dist/fs-utils.d.ts +4 -0
  7. package/dist/fs-utils.js +12 -6
  8. package/dist/report/html.d.ts +18 -9
  9. package/dist/report/html.js +108 -68
  10. package/dist/report/pages.d.ts +4 -4
  11. package/dist/report/pages.js +165 -115
  12. package/dist/report/sarif.d.ts +3 -0
  13. package/dist/report/sarif.js +67 -0
  14. package/dist/report/styles.d.ts +1 -1
  15. package/dist/report/styles.js +105 -33
  16. package/dist/report/svg.d.ts +17 -0
  17. package/dist/report/svg.js +99 -0
  18. package/dist/runners/accessibility.d.ts +3 -0
  19. package/dist/runners/accessibility.js +85 -0
  20. package/dist/runners/architecture.d.ts +2 -0
  21. package/dist/runners/architecture.js +232 -20
  22. package/dist/runners/code-coherence.d.ts +17 -0
  23. package/dist/runners/code-coherence.js +39 -0
  24. package/dist/runners/complexity.js +7 -37
  25. package/dist/runners/confusion.js +3 -31
  26. package/dist/runners/context.js +9 -40
  27. package/dist/runners/dependencies.js +28 -0
  28. package/dist/runners/doc-coherence.d.ts +14 -0
  29. package/dist/runners/doc-coherence.js +48 -0
  30. package/dist/runners/docs.js +7 -32
  31. package/dist/runners/duplication.js +9 -37
  32. package/dist/runners/lint.js +17 -0
  33. package/dist/runners/performance.d.ts +10 -0
  34. package/dist/runners/performance.js +174 -0
  35. package/dist/runners/react.d.ts +3 -0
  36. package/dist/runners/react.js +86 -0
  37. package/dist/runners/secrets.js +8 -29
  38. package/dist/runners/security.js +15 -38
  39. package/dist/runners/standards.js +3 -36
  40. package/dist/runners/structure.js +35 -55
  41. package/dist/runners/testing.js +2 -36
  42. package/dist/runners/type-safety.d.ts +1 -1
  43. package/dist/runners/type-safety.js +19 -37
  44. package/dist/runners/types-check.d.ts +1 -1
  45. package/dist/runners/types-check.js +38 -20
  46. package/dist/types.d.ts +5 -5
  47. package/package.json +11 -10
package/README.md CHANGED
@@ -2,19 +2,19 @@
2
2
 
3
3
  **Code health scanner for the AI coding era.**
4
4
 
5
- One command. 15 checks. Full report. Zero config.
5
+ One command. 21 checks. Full report. Zero config.
6
6
 
7
7
  ```bash
8
8
  npx @vibecodeqa/cli
9
9
  ```
10
10
 
11
- ![Grade](https://img.shields.io/badge/checks-15-blue) ![TypeScript](https://img.shields.io/badge/TypeScript-first-3178C6) ![License](https://img.shields.io/badge/license-MIT-green)
11
+ ![Grade](https://img.shields.io/badge/checks-21-blue) ![TypeScript](https://img.shields.io/badge/TypeScript-first-3178C6) ![License](https://img.shields.io/badge/license-MIT-green)
12
12
 
13
13
  ## What it does
14
14
 
15
- vcqa scans your TypeScript/JavaScript codebase and produces a scored health report with actionable findings. It auto-detects your stack (React, Vite, vitest, Biome, etc.) and runs 15 checks across 6 categories.
15
+ vcqa scans your TypeScript/JavaScript/Dart/Flutter codebase and produces a scored health report with actionable findings. It auto-detects your stack (React, Flutter, Vite, vitest, Biome, etc.) and runs 21 checks across 7 categories.
16
16
 
17
- The output is a self-contained HTML report with radar charts, architecture diagrams, file heatmaps, and drill-down issue lists — all navigable via sidebar and tab navigation.
17
+ The output is a self-contained HTML report with radar charts, architecture diagrams, score timeline, testing pyramid, and drill-down issue lists — all navigable via sidebar and tab navigation.
18
18
 
19
19
  ## Quick start
20
20
 
@@ -34,6 +34,12 @@ npx @vibecodeqa/cli --ci
34
34
  # JSON output (pipe to other tools)
35
35
  npx @vibecodeqa/cli --json
36
36
 
37
+ # Generate badge SVG for README
38
+ npx @vibecodeqa/cli --badge
39
+
40
+ # SARIF output for GitHub Security tab
41
+ npx @vibecodeqa/cli --sarif
42
+
37
43
  # Scan a specific directory
38
44
  npx @vibecodeqa/cli /path/to/project
39
45
  ```
@@ -41,6 +47,8 @@ npx @vibecodeqa/cli /path/to/project
41
47
  Output goes to `.vibe-check/`:
42
48
  - `report.html` — navigable multi-page dashboard (open in browser)
43
49
  - `report.json` — machine-readable results
50
+ - `badge.svg` — shields.io-style badge (with `--badge`)
51
+ - `report.sarif` — SARIF 2.1.0 for GitHub Code Scanning (with `--sarif`)
44
52
  - `history/` — last 30 reports for trend tracking
45
53
 
46
54
  ## Checks
@@ -53,17 +61,20 @@ Output goes to `.vibe-check/`:
53
61
  | **Lint** | 5% | Biome or ESLint errors/warnings (auto-detected) |
54
62
  | **Types** | 6% | TypeScript compilation errors (`tsc --noEmit`) |
55
63
  | **Type Safety** | 3% | `as any`, `: any`, `@ts-ignore`, `@ts-nocheck` counts |
56
- | **Standards** | 3% | File naming, large files (>300 lines), code smells (console.log, var, ==, eval, innerHTML), config hygiene |
64
+ | **Standards** | 3% | File naming, large files (>300 lines), code smells (console.log, var, ==, eval), config hygiene |
57
65
 
58
- ### Quality (15%)
66
+ ### Quality (23%)
59
67
 
60
68
  | Check | Weight | What it measures |
61
69
  |-------|--------|-----------------|
62
- | **Complexity** | 7% | Cognitive complexity per function, functions >60 lines |
70
+ | **Complexity** | 3% | Cognitive complexity per function, functions >60 lines |
63
71
  | **Duplication** | 5% | Copy-pasted 6+ line blocks |
72
+ | **Error Handling** | 5% | Empty catch blocks, throw string, missing Error Boundaries |
73
+ | **React Patterns** | 3% | Conditional hooks, missing keys, index keys, prop spreading |
74
+ | **Accessibility** | 4% | img alt, click on non-interactive elements, form labels, html lang |
64
75
  | **Docs** | 3% | README quality, JSDoc coverage of exports |
65
76
 
66
- ### Testing (22%)
77
+ ### Testing (15%)
67
78
 
68
79
  One deep check with 6 sub-dimensions:
69
80
 
@@ -74,34 +85,36 @@ One deep check with 6 sub-dimensions:
74
85
  - **Quality** — assertion density, mock ratio, snapshot ratio
75
86
  - **E2E detection** — Playwright/Cypress configured?
76
87
 
77
- ### Architecture (7%)
88
+ ### Architecture (10%)
78
89
 
79
90
  | Check | Weight | What it measures |
80
91
  |-------|--------|-----------------|
81
- | **Architecture** | 7% | Import graph, circular deps, god modules, orphan files, fan-out, SVG diagram |
92
+ | **Architecture** | 6% | Import graph, circular deps, god modules, orphan files, fan-out, SVG diagram with legend |
93
+ | **Performance** | 4% | Barrel imports, heavy dependencies, dynamic import opportunities, CSS-in-JS overhead |
82
94
 
83
- ### Security (18%)
95
+ ### Security (16%)
84
96
 
85
97
  | Check | Weight | What it measures |
86
98
  |-------|--------|-----------------|
87
99
  | **Secrets** | 6% | 13 patterns (AWS, GitHub, Stripe, OpenAI, private keys) |
88
- | **Security** | 7% | 15 CWE-mapped patterns (XSS, injection, crypto, SSRF) |
89
- | **Dependencies** | 5% | npm audit vulnerabilities + outdated packages |
100
+ | **Security** | 5% | 15 CWE-mapped patterns (XSS, injection, crypto, SSRF) |
101
+ | **Dependencies** | 5% | npm audit / dart pub outdated vulnerabilities + outdated packages |
90
102
 
91
- ### LLM Readiness (15%)
103
+ ### AI Readiness (13%)
92
104
 
93
105
  Novel checks that no other tool offers:
94
106
 
95
107
  | Check | Weight | What it measures |
96
108
  |-------|--------|-----------------|
97
- | **Confusion Index** | 8% | File name similarity, generic names, export collisions, ambiguous abbreviations |
98
- | **Context Locality** | 7% | Token density, import depth, circular deps, context sinks |
109
+ | **Confusion Index** | 7% | File name similarity, generic names, export collisions, ambiguous abbreviations |
110
+ | **Context Locality** | 6% | Token density, import depth, circular deps, context sinks |
99
111
 
100
- **Research backing:**
101
- - "When Names Disappear" (arXiv:2510.03178): GPT-4o drops 28.6% on summarization with ambiguous names
102
- - "Lost in the Middle" (Liu et al. 2023): 30%+ accuracy drop for mid-context information
103
- - "Context Rot" (Chroma 2025): all frontier models degrade with input length
104
- - "Variable Naming Impact" (Research Square 2024): descriptive names = 8.9% better AI performance
112
+ ### AI Analysis (PRO — coming soon)
113
+
114
+ | Check | What it will do |
115
+ |-------|----------------|
116
+ | **Doc Coherence** | LLM-powered detection of contradictions between docs and code |
117
+ | **Code Coherence** | LLM-powered detection of internal inconsistencies across modules |
105
118
 
106
119
  ## Scoring
107
120
 
@@ -117,27 +130,19 @@ Each check produces a score from 0-100. The composite score is a weighted averag
117
130
 
118
131
  ## Report features
119
132
 
120
- The report is a multi-page navigable dashboard:
121
-
122
- - **10 pages**: Overview, Foundations, Quality, Testing, Architecture, Security, LLM Readiness, Issues, File Map, Heatmap
123
- - **Top nav + sidebar** — navigate by category and check
124
- - **Radar chart** — 6-axis view of category scores
125
- - **Architecture SVG diagram** — modules grouped by directory, import edges, node size by fan-in
126
- - **Code heatmap** — colored bars showing issue density per file
127
- - **Trend comparison** — score delta vs. previous run (reads previous report.json)
128
- - **File map** — top files by issue count across all checks
133
+ - **Primary nav**: Overview + 7 dimension tabs (Foundations, Quality, Testing, Architecture, Security, AI Readiness, AI Analysis)
134
+ - **Secondary nav**: Issues + Files (cross-cutting data views)
135
+ - **Score ring + radar chart** 6-axis view of category scores
136
+ - **Score timeline** — last 30 runs with grade-colored dots
137
+ - **Testing pyramid** — proportional SVG showing unit/integration/component/e2e distribution
138
+ - **Architecture SVG** — modules grouped by directory, bezier edges with arrows, color-coded nodes (god module, cycle, orphan), legend
139
+ - **File health map** — heatmap bars showing issue density per file
140
+ - **Trend comparison** — score delta vs. previous run
129
141
  - **GitHub links** — click any file:line to open in GitHub (auto-detected from git remote)
130
- - **Actionable prompts** — 📋 button on every issue copies a fix prompt for Claude/Codex
142
+ - **Actionable prompts** — clipboard button on every issue copies a fix prompt for Claude/Codex
131
143
  - **Info panels** — each check has What/Risk/Fix explanations with research citations
132
144
  - **Priority badges** — critical/high/medium/low on each check
133
145
 
134
- ## Trend tracking
135
-
136
- vcqa reads the previous `.vibe-check/report.json` on each run and shows:
137
- - Score change (↑ improved / ↓ declined)
138
- - Per-check deltas
139
- - New vs. fixed issue counts
140
-
141
146
  ## CLI options
142
147
 
143
148
  | Flag | Description |
@@ -146,33 +151,37 @@ vcqa reads the previous `.vibe-check/report.json` on each run and shows:
146
151
  | `--watch` | Re-scan automatically on file changes |
147
152
  | `--ci` | Exit code 1 if composite score < 60 |
148
153
  | `--json` | Output JSON to stdout (no HTML, no browser) |
154
+ | `--badge` | Generate badge.svg in output directory |
155
+ | `--sarif` | Generate SARIF 2.1.0 for GitHub Code Scanning |
149
156
 
150
157
  ## Stack detection
151
158
 
152
- Auto-detects from `package.json` and config files:
153
- - **Language:** TypeScript, JavaScript
154
- - **Framework:** React, Vue, Svelte
159
+ Auto-detects from `package.json`, `pubspec.yaml`, and config files:
160
+ - **Language:** TypeScript, JavaScript, Dart
161
+ - **Framework:** React, Vue, Svelte, Flutter
155
162
  - **Bundler:** Vite, Webpack, esbuild
156
- - **Test runner:** vitest, jest
157
- - **Linter:** Biome, ESLint
158
- - **Package manager:** pnpm, npm, yarn, bun
159
-
160
- ## References
161
-
162
- Standards and research cited in vibe-check's analysis:
163
-
164
- - ISO/IEC 25010:2023 — Software product quality model
165
- - McCabe, T.J. "A Complexity Measure" (IEEE, 1976) — Cyclomatic complexity
166
- - Campbell, G.A. "Cognitive Complexity" (SonarSource, 2017) — Understandability metric
167
- - Martin, R.C. "Clean Code" (2008) — Naming principles
168
- - OWASP Top 10 — Web application security risks
169
- - CWE Top 25 — Most dangerous software weaknesses
170
- - Liu et al. "Lost in the Middle" (TACL, 2023) — LLM context attention
171
- - Chroma Research "Context Rot" (2025) — LLM degradation with input length
172
- - Wang et al. "How Does Naming Affect LLMs?" (JSEA, 2024) — Naming impact on AI
173
- - arXiv:2510.03178 "When Names Disappear" (2025) — 28.6% accuracy drop
174
- - Arnaoudova et al. "Linguistic Antipatterns" — 17-pattern naming catalog
175
- - Vassilev "Codified Context" (arXiv, 2025) — AI agent context architecture
163
+ - **Test runner:** vitest, jest, flutter_test, dart_test
164
+ - **Linter:** Biome, ESLint, dart analyze
165
+ - **Package manager:** pnpm, npm, yarn, bun, pub
166
+
167
+ ## GitHub Actions
168
+
169
+ Add this to `.github/workflows/vibecodeqa.yml` for automatic PR scanning:
170
+
171
+ ```yaml
172
+ name: VibeCode QA
173
+ on: [pull_request]
174
+ jobs:
175
+ scan:
176
+ runs-on: ubuntu-latest
177
+ steps:
178
+ - uses: actions/checkout@v4
179
+ - run: npx @vibecodeqa/cli --skip-tests --ci --sarif
180
+ - uses: github/codeql-action/upload-sarif@v3
181
+ if: always()
182
+ with:
183
+ sarif_file: .vibe-check/report.sarif
184
+ ```
176
185
 
177
186
  ## License
178
187
 
@@ -180,6 +189,7 @@ MIT — Free forever as a CLI tool.
180
189
 
181
190
  ## Links
182
191
 
183
- - **GitHub:** https://github.com/freeappstore-online/vibe-check
192
+ - **GitHub:** https://github.com/vibecodeqa/cli
184
193
  - **Website:** https://vibecodeqa.online
185
- - **Issues:** https://github.com/freeappstore-online/vibe-check/issues
194
+ - **npm:** https://www.npmjs.com/package/@vibecodeqa/cli
195
+ - **Issues:** https://github.com/vibecodeqa/cli/issues
@@ -10,6 +10,7 @@ export interface CheckMeta {
10
10
  description: string;
11
11
  risk: string;
12
12
  recommendation: string;
13
+ premium?: boolean;
13
14
  }
14
15
  export declare const CHECK_META: Record<string, CheckMeta>;
15
16
  export declare function getCheckMeta(name: string): CheckMeta;
@@ -56,7 +56,7 @@ export const CHECK_META = {
56
56
  label: "Error Handling",
57
57
  category: "Quality",
58
58
  priority: "high",
59
- weight: 2,
59
+ weight: 3,
60
60
  description: "Detects poor error handling: empty catch blocks, throw with string literals, catch-and-rethrow without context, Promise.then() without .catch(), missing React Error Boundaries.",
61
61
  risk: "Empty catch blocks silently swallow errors. throw 'string' loses stack traces. Missing Error Boundaries in React cause the entire app to crash on render errors.",
62
62
  recommendation: "Handle or log every catch. Use throw new Error() for stack traces. Add Error Boundaries in React. Chain .catch() on promises.",
@@ -96,7 +96,7 @@ export const CHECK_META = {
96
96
  label: "Testing",
97
97
  category: "Testing",
98
98
  priority: "critical",
99
- weight: 22,
99
+ weight: 15,
100
100
  description: "Deep assessment of test quality across 6 dimensions: pyramid presence (unit/integration/component/E2E layers), test execution (pass/fail), coverage (statement/branch/line/function), file pairing (test file per source file), test quality (assertion density, mock ratio, snapshot ratio), and E2E tool detection (Playwright/Cypress).",
101
101
  risk: "Code without tests is code you can't safely change. Missing test layers mean entire categories of bugs go undetected: unit tests catch logic bugs, integration tests catch API contract breaks, E2E tests catch user-visible regressions. Low coverage means large portions of code are never exercised.",
102
102
  recommendation: "Follow the testing pyramid: many unit tests, some integration tests, fewer E2E tests. Aim for >80% branch coverage. Every source file should have a corresponding test file. Use Playwright for E2E if you have a web frontend.",
@@ -116,7 +116,7 @@ export const CHECK_META = {
116
116
  label: "Security Patterns",
117
117
  category: "Security",
118
118
  priority: "critical",
119
- weight: 7,
119
+ weight: 5,
120
120
  description: "Static analysis for 15 vulnerability patterns mapped to CWE (Common Weakness Enumeration) IDs. Covers: XSS (innerHTML, dangerouslySetInnerHTML, document.write), injection (eval, new Function, SQL template literals, command injection), weak crypto (Math.random for tokens, MD5/SHA1), prototype pollution, path traversal, SSRF, and missing security headers.",
121
121
  risk: "These patterns represent the most commonly exploited vulnerabilities in web applications (OWASP Top 10). A single XSS or injection vulnerability can lead to account takeover, data theft, or complete system compromise.",
122
122
  recommendation: "Replace innerHTML with textContent or DOM APIs. Never use eval(). Use parameterized queries for SQL. Use crypto.randomUUID() instead of Math.random() for tokens. Validate all user input before use in file paths or URLs.",
@@ -136,7 +136,7 @@ export const CHECK_META = {
136
136
  label: "Architecture",
137
137
  category: "Architecture",
138
138
  priority: "high",
139
- weight: 7,
139
+ weight: 6,
140
140
  description: "Analyzes the import graph to detect structural problems: circular dependencies, god modules (imported by >50% of files), orphan modules (dead code), high fan-out (importing too many modules), and connector modules (high coupling). Generates an SVG architecture diagram.",
141
141
  risk: "Circular dependencies create build order issues and make refactoring impossible without breaking changes. God modules become bottlenecks — any change ripples through the entire codebase. High coupling means you can't change one module without testing everything it touches.",
142
142
  recommendation: "Break circular deps by extracting shared types to a separate file. Split god modules by concern. Reduce fan-out by co-locating related code. Use dependency injection for loose coupling.",
@@ -146,7 +146,7 @@ export const CHECK_META = {
146
146
  label: "Confusion Index",
147
147
  category: "LLM Readiness",
148
148
  priority: "high",
149
- weight: 8,
149
+ weight: 7,
150
150
  description: "Measures naming ambiguity that causes LLMs to misunderstand or edit the wrong code. Checks: file name confusability (Levenshtein distance + synonym detection), generic function/variable names, export name collisions across files, and ambiguous abbreviations.",
151
151
  risk: "GPT-4o drops 28.6 percentage points on code summarization when names are ambiguous (arXiv:2510.03178). LLMs editing similar-named files is the #1 reported failure mode in AI-assisted development. Generic names like process(), handle(), data cause models to misinterpret intent.",
152
152
  recommendation: "Use descriptive, unique names. Avoid synonym files (utils.ts + helpers.ts — pick one). Avoid generic exports. Disambiguate abbreviations (use 'authentication' not 'auth' if both auth meanings exist in the codebase).",
@@ -156,11 +156,63 @@ export const CHECK_META = {
156
156
  label: "Context Locality",
157
157
  category: "LLM Readiness",
158
158
  priority: "high",
159
- weight: 7,
159
+ weight: 6,
160
160
  description: "Measures how self-contained code is for LLM consumption. Checks: token density per file, import count, circular dependencies, and context sinks (files that import many modules but export little). Based on the finding that LLMs lose 30%+ accuracy for information in the middle of long contexts.",
161
161
  risk: "Files over ~4000 tokens exceed the 'sweet spot' for LLM attention (Liu et al. 2023 'Lost in the Middle'). Circular dependencies create infinite loops in LLM code navigation. Heavy import chains force LLMs to load many files, burning context window budget (Chroma 'Context Rot' 2025).",
162
162
  recommendation: "Keep files under 400 lines / 4000 tokens. Limit imports to <15 per file. Break circular dependencies. Co-locate related code to reduce cross-file jumps.",
163
163
  },
164
+ react: {
165
+ name: "react",
166
+ label: "React Patterns",
167
+ category: "Quality",
168
+ priority: "high",
169
+ weight: 3,
170
+ description: "Checks React-specific patterns: conditional hook calls (violates Rules of Hooks), missing key props in .map(), index as key, prop spreading on DOM elements, and excessive inline handlers.",
171
+ risk: "Conditional hooks cause React to crash at runtime. Missing keys cause incorrect reconciliation — items can swap, duplicate, or lose state. Index keys break when lists are reordered or filtered.",
172
+ recommendation: "Never call hooks inside conditions, loops, or nested functions. Always provide a unique, stable key in .map(). Avoid spreading unknown props onto DOM elements. Extract inline handlers for readability.",
173
+ },
174
+ accessibility: {
175
+ name: "accessibility",
176
+ label: "Accessibility",
177
+ category: "Quality",
178
+ priority: "high",
179
+ weight: 4,
180
+ description: "Checks common accessibility violations: images without alt text, click handlers on non-interactive elements without keyboard support, form controls without labels, autoFocus usage, positive tabIndex, and missing html lang attribute.",
181
+ risk: "1 in 4 adults has a disability (CDC). Missing alt text makes images invisible to screen readers. Click-only divs exclude keyboard users. Unlabeled inputs are unusable with assistive technology. Missing lang attribute breaks screen reader pronunciation.",
182
+ recommendation: "Add alt text to all images (use alt=\"\" for decorative). Use <button> for clickable elements, not <div onClick>. Label all form controls with <label>, aria-label, or aria-labelledby. Set lang on <html>.",
183
+ },
184
+ performance: {
185
+ name: "performance",
186
+ label: "Performance",
187
+ category: "Architecture",
188
+ priority: "medium",
189
+ weight: 4,
190
+ description: "Detects barrel imports that defeat tree-shaking, heavy dependencies with lighter alternatives, static imports of large libraries that could be lazy-loaded, and runtime CSS-in-JS overhead.",
191
+ risk: "Barrel files (index.ts re-exports) prevent bundlers from tree-shaking unused code, bloating bundles by 2-10x. Heavy dependencies like moment.js add 300KB when date-fns does the same in 7KB. Static imports of visualization libraries delay initial page load.",
192
+ recommendation: "Replace barrel re-exports with direct imports. Swap heavy deps for lighter alternatives. Use dynamic import() for large libraries only needed on interaction. Prefer zero-runtime CSS (Tailwind, CSS Modules) over styled-components.",
193
+ },
194
+ "doc-coherence": {
195
+ name: "doc-coherence",
196
+ label: "Doc Coherence",
197
+ category: "AI Analysis",
198
+ priority: "high",
199
+ weight: 0,
200
+ description: "LLM-powered analysis that detects contradictions between documentation and code. Finds stale README claims, incorrect JSDoc parameters, outdated CHANGELOG references, and comments that no longer match the implementation.",
201
+ risk: "Stale documentation is worse than no documentation — it actively misleads developers and LLMs. When README says 'supports X' but the feature was removed, new contributors waste time. When JSDoc says a param is required but code treats it as optional, callers crash.",
202
+ recommendation: "Enable doc-coherence with a VibeCode QA Pro subscription. The LLM scans all documentation against the actual code and surfaces contradictions with specific file references.",
203
+ premium: true,
204
+ },
205
+ "code-coherence": {
206
+ name: "code-coherence",
207
+ label: "Code Coherence",
208
+ category: "AI Analysis",
209
+ priority: "high",
210
+ weight: 0,
211
+ description: "LLM-powered analysis that detects internal contradictions within the codebase itself. Finds inconsistent validation logic, conflicting defaults across modules, naming convention drift, dead config flags, and behavioral mismatches.",
212
+ risk: "Incoherent codebases are the #1 source of 'it works on my machine' bugs. When module A validates email with regex and module B uses a different regex, some emails pass one and fail the other. When timeouts differ across modules, race conditions emerge under load.",
213
+ recommendation: "Enable code-coherence with a VibeCode QA Pro subscription. The LLM analyzes cross-module patterns and surfaces behavioral contradictions that static analysis cannot detect.",
214
+ premium: true,
215
+ },
164
216
  };
165
217
  export function getCheckMeta(name) {
166
218
  return (CHECK_META[name] || {
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { join, resolve } from "node:path";
5
5
  import { detectRepoUrl, detectStack } from "./detect.js";
6
- import { generateHTML } from "./report/html.js";
6
+ import { generatePages } from "./report/html.js";
7
7
  import { runArchitecture } from "./runners/architecture.js";
8
8
  import { runComplexity } from "./runners/complexity.js";
9
9
  import { runConfusion } from "./runners/confusion.js";
@@ -11,8 +11,13 @@ import { runContext } from "./runners/context.js";
11
11
  import { runDependencies } from "./runners/dependencies.js";
12
12
  import { runDocs } from "./runners/docs.js";
13
13
  import { runDuplication } from "./runners/duplication.js";
14
+ import { runPerformance } from "./runners/performance.js";
14
15
  import { runErrorHandling } from "./runners/error-handling.js";
15
16
  import { runLint } from "./runners/lint.js";
17
+ import { runReact } from "./runners/react.js";
18
+ import { runAccessibility } from "./runners/accessibility.js";
19
+ import { runDocCoherence } from "./runners/doc-coherence.js";
20
+ import { runCodeCoherence } from "./runners/code-coherence.js";
16
21
  import { runSecrets } from "./runners/secrets.js";
17
22
  import { runSecurity } from "./runners/security.js";
18
23
  import { runStandards } from "./runners/standards.js";
@@ -33,6 +38,8 @@ const jsonOnly = flags.has("--json");
33
38
  const ciMode = flags.has("--ci");
34
39
  const skipTests = flags.has("--skip-tests");
35
40
  const watchMode = flags.has("--watch");
41
+ const badgeMode = flags.has("--badge");
42
+ const sarifMode = flags.has("--sarif");
36
43
  function color(grade) {
37
44
  if (grade === "A")
38
45
  return "\x1b[32m";
@@ -55,18 +62,21 @@ async function main() {
55
62
  console.log("");
56
63
  }
57
64
  const checks = [];
65
+ const isDart = stack.language === "dart";
58
66
  // All runners grouped by category
59
67
  const runners = [
60
68
  // Foundations
61
69
  { name: "structure", fn: () => runStructure(cwd, stack) },
62
70
  { name: "lint", fn: () => runLint(cwd, stack) },
63
- { name: "types", fn: () => runTypeCheck(cwd) },
64
- { name: "type-safety", fn: () => runTypeSafety(cwd) },
71
+ { name: "types", fn: () => runTypeCheck(cwd, isDart) },
72
+ { name: "type-safety", fn: () => runTypeSafety(cwd, isDart) },
65
73
  { name: "standards", fn: () => runStandards(cwd, stack) },
66
74
  // Quality
67
75
  { name: "complexity", fn: () => runComplexity(cwd) },
68
76
  { name: "duplication", fn: () => runDuplication(cwd) },
69
77
  { name: "error-handling", fn: () => runErrorHandling(cwd, stack) },
78
+ { name: "react", fn: () => runReact(cwd, stack) },
79
+ { name: "accessibility", fn: () => runAccessibility(cwd) },
70
80
  { name: "docs", fn: () => runDocs(cwd) },
71
81
  // Testing
72
82
  { name: "testing", fn: () => runTesting(cwd, stack, skipTests) },
@@ -76,9 +86,13 @@ async function main() {
76
86
  { name: "dependencies", fn: () => runDependencies(cwd, stack) },
77
87
  // Architecture
78
88
  { name: "architecture", fn: () => runArchitecture(cwd) },
89
+ { name: "performance", fn: () => runPerformance(cwd) },
79
90
  // LLM Readiness
80
91
  { name: "confusion", fn: () => runConfusion(cwd) },
81
92
  { name: "context", fn: () => runContext(cwd) },
93
+ // AI Analysis (premium)
94
+ { name: "doc-coherence", fn: () => runDocCoherence(cwd) },
95
+ { name: "code-coherence", fn: () => runCodeCoherence(cwd) },
82
96
  ];
83
97
  for (const runner of runners) {
84
98
  if (!jsonOnly)
@@ -86,10 +100,12 @@ async function main() {
86
100
  const result = runner.fn();
87
101
  checks.push(result);
88
102
  if (!jsonOnly) {
89
- const skipped = result.details.skipped;
90
- const c = skipped ? "\x1b[2m" : color(result.grade);
91
- const label = skipped ? "skip" : result.grade;
92
- const scoreStr = skipped ? "" : `${result.score}/100`;
103
+ const det = result.details;
104
+ const skipped = det.skipped;
105
+ const premium = det.comingSoon;
106
+ const c = premium ? "\x1b[2m" : skipped ? "\x1b[2m" : color(result.grade);
107
+ const label = premium ? "soon" : skipped ? "skip" : result.grade;
108
+ const scoreStr = premium ? "PRO" : skipped ? "—" : `${result.score}/100`;
93
109
  const issueStr = result.issues.length > 0 ? ` \x1b[2m${result.issues.length} issues\x1b[0m` : "";
94
110
  console.log(`${c}${label.padEnd(5)}${scoreStr}\x1b[0m \x1b[2m${result.duration}ms\x1b[0m${issueStr}`);
95
111
  }
@@ -131,7 +147,25 @@ async function main() {
131
147
  }
132
148
  }
133
149
  writeFileSync(join(outputDir, "report.json"), JSON.stringify(report, null, 2));
134
- writeFileSync(join(outputDir, "report.html"), generateHTML(report));
150
+ // Generate multi-page HTML report
151
+ const reportDir = join(outputDir, "report");
152
+ if (!existsSync(reportDir))
153
+ mkdirSync(reportDir, { recursive: true });
154
+ const pages = generatePages(report, historyDir);
155
+ for (const [filename, html] of pages) {
156
+ writeFileSync(join(reportDir, filename), html);
157
+ }
158
+ // Badge SVG
159
+ if (badgeMode) {
160
+ const { buildBadge } = await import("./report/svg.js");
161
+ const badgeSvg = buildBadge(score, grade);
162
+ writeFileSync(join(outputDir, "badge.svg"), badgeSvg);
163
+ }
164
+ // SARIF output for GitHub Code Scanning
165
+ if (sarifMode) {
166
+ const { generateSARIF } = await import("./report/sarif.js");
167
+ writeFileSync(join(outputDir, "report.sarif"), generateSARIF(report));
168
+ }
135
169
  if (jsonOnly) {
136
170
  console.log(JSON.stringify(report));
137
171
  }
@@ -142,8 +176,12 @@ async function main() {
142
176
  if (trend)
143
177
  console.log(formatTrend(trend));
144
178
  console.log("");
145
- console.log(` \x1b[2mReport: ${join(outputDir, "report.html")}\x1b[0m`);
179
+ console.log(` \x1b[2mReport: ${join(outputDir, "report/index.html")}\x1b[0m`);
146
180
  console.log(` \x1b[2mJSON: ${join(outputDir, "report.json")}\x1b[0m`);
181
+ if (badgeMode)
182
+ console.log(` \x1b[2mBadge: ${join(outputDir, "badge.svg")}\x1b[0m`);
183
+ if (sarifMode)
184
+ console.log(` \x1b[2mSARIF: ${join(outputDir, "report.sarif")}\x1b[0m`);
147
185
  console.log("");
148
186
  }
149
187
  if (ciMode && score < 60) {
@@ -153,7 +191,7 @@ async function main() {
153
191
  try {
154
192
  const { execFileSync } = await import("node:child_process");
155
193
  const openCmd = process.platform === "darwin" ? "open" : "xdg-open";
156
- execFileSync(openCmd, [join(outputDir, "report.html")], { stdio: "ignore" });
194
+ execFileSync(openCmd, [join(outputDir, "report/index.html")], { stdio: "ignore" });
157
195
  }
158
196
  catch {
159
197
  /* failed to open browser */
package/dist/detect.js CHANGED
@@ -12,9 +12,31 @@ export function detectStack(cwd) {
12
12
  return "";
13
13
  }
14
14
  };
15
+ // ── Dart/Flutter detection ──
16
+ const pubspec = read("pubspec.yaml");
17
+ if (pubspec || has("pubspec.lock")) {
18
+ const isFlutter = pubspec.includes("flutter:") || pubspec.includes("flutter_test:");
19
+ const hasTest = pubspec.includes("test:") || pubspec.includes("flutter_test:");
20
+ const hasAnalysis = has("analysis_options.yaml");
21
+ return {
22
+ language: "dart",
23
+ framework: isFlutter ? "flutter" : "none",
24
+ bundler: "none",
25
+ testRunner: isFlutter ? (hasTest ? "flutter_test" : "none") : hasTest ? "dart_test" : "none",
26
+ linter: hasAnalysis ? "dart_analyze" : "none",
27
+ packageManager: "pub",
28
+ };
29
+ }
30
+ // ── Node.js/TypeScript detection ──
15
31
  const pkg = read("package.json");
16
- const deps = pkg ? JSON.parse(pkg) : {};
17
- const allDeps = { ...deps.dependencies, ...deps.devDependencies };
32
+ let allDeps = {};
33
+ try {
34
+ const deps = pkg ? JSON.parse(pkg) : {};
35
+ allDeps = { ...deps.dependencies, ...deps.devDependencies };
36
+ }
37
+ catch {
38
+ // invalid package.json
39
+ }
18
40
  const language = has("tsconfig.json") || has("tsconfig.app.json") || allDeps.typescript
19
41
  ? "typescript"
20
42
  : allDeps.react || allDeps.vue
@@ -21,3 +21,7 @@ export declare function getTestFiles(cwd: string): SourceFile[];
21
21
  export declare function readSafe(cwd: string, path: string): string;
22
22
  /** Parse package.json dependencies. */
23
23
  export declare function readDeps(cwd: string): Record<string, string>;
24
+ /** Walk from cwd root (not just src/) — for checks like secrets that scan all project files. */
25
+ export declare function collectAllFiles(cwd: string, opts?: {
26
+ extraExts?: boolean;
27
+ }): SourceFile[];
package/dist/fs-utils.js CHANGED
@@ -1,13 +1,15 @@
1
1
  /** Shared filesystem utilities — eliminates duplicate file-walking across runners. */
2
2
  import { lstatSync, readdirSync, readFileSync, statSync } from "node:fs";
3
3
  import { basename, extname, join } from "node:path";
4
- const SKIP_DIRS = new Set(["node_modules", "dist", ".git", ".vibe-check", "coverage", "test-results", "__pycache__"]);
5
- const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx"]);
4
+ const SKIP_DIRS = new Set(["node_modules", "dist", ".git", ".vibe-check", "coverage", "test-results", "__pycache__", ".dart_tool", "build", ".flutter-plugins"]);
5
+ const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".dart"]);
6
6
  const ALL_EXTS = new Set([...CODE_EXTS, ".json", ".env", ".yaml", ".yml", ".toml"]);
7
7
  /** Walk source directories and return all code files. */
8
8
  export function collectSourceFiles(cwd, opts) {
9
9
  const files = [];
10
- const dirs = ["src", "web/src"];
10
+ const dirs = ["src", "web/src", "lib"];
11
+ if (opts?.includeTests)
12
+ dirs.push("test", "tests", "__tests__");
11
13
  for (const dir of dirs) {
12
14
  try {
13
15
  walk(join(cwd, dir), cwd, files, opts?.extraExts ? ALL_EXTS : CODE_EXTS);
@@ -16,8 +18,6 @@ export function collectSourceFiles(cwd, opts) {
16
18
  /* dir doesn't exist */
17
19
  }
18
20
  }
19
- if (opts?.includeTests)
20
- return files;
21
21
  return files;
22
22
  }
23
23
  /** Get only production source files (no tests). */
@@ -50,6 +50,12 @@ export function readDeps(cwd) {
50
50
  return {};
51
51
  }
52
52
  }
53
+ /** Walk from cwd root (not just src/) — for checks like secrets that scan all project files. */
54
+ export function collectAllFiles(cwd, opts) {
55
+ const files = [];
56
+ walk(cwd, cwd, files, opts?.extraExts ? ALL_EXTS : CODE_EXTS);
57
+ return files;
58
+ }
53
59
  function walk(dir, cwd, out, exts) {
54
60
  for (const entry of readdirSync(dir)) {
55
61
  if (SKIP_DIRS.has(entry))
@@ -70,7 +76,7 @@ function walk(dir, cwd, out, exts) {
70
76
  continue;
71
77
  const content = readFileSync(full, "utf-8");
72
78
  const relPath = full.replace(`${cwd}/`, "");
73
- const isTest = entry.includes(".test.") || entry.includes(".spec.") || relPath.includes("__tests__");
79
+ const isTest = entry.includes(".test.") || entry.includes(".spec.") || entry.endsWith("_test.dart") || relPath.includes("__tests__") || relPath.includes("test/");
74
80
  out.push({
75
81
  path: relPath,
76
82
  fullPath: full,
@@ -1,12 +1,21 @@
1
- /** Generate a multi-page navigable HTML report.
1
+ /** Generate a multi-page HTML report as separate files.
2
2
  *
3
- * Architecture:
4
- * Top nav: Overview | Foundations | Quality | Testing | Security | Issues
5
- * Sub-nav: Tabs for each check within a category
6
- * Detail: Per-check stats + full issue list grouped by file
7
- * File map: Cross-check heatmap of issues per file
8
- *
9
- * All in one self-contained HTML file using hash routing + show/hide.
3
+ * Layout:
4
+ * Top nav: Logo | Overview | Foundations | Quality | ... | Issues | Files
5
+ * Page-level navigation. Scrollable on mobile.
6
+ * Sidebar: CONTEXTUAL to current page NOT a duplicate of top nav.
7
+ * Overview: score + category scores
8
+ * Category: individual checks with grades (click to jump)
9
+ * Issues: severity breakdown
10
+ * Files: summary stats
11
+ * Mobile: Hamburger toggles both top nav dropdown and sidebar panel.
10
12
  */
11
13
  import type { VibeReport } from "../types.js";
12
- export declare function generateHTML(report: VibeReport): string;
14
+ export declare const GROUPS: {
15
+ id: string;
16
+ label: string;
17
+ file: string;
18
+ checks: string[];
19
+ }[];
20
+ export declare function generatePages(report: VibeReport, historyDir?: string): Map<string, string>;
21
+ export declare function generateHTML(report: VibeReport, historyDir?: string): string;