@vibecodeqa/cli 0.11.0 → 0.12.1
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.
- package/README.md +17 -6
- package/dist/cli.js +3 -2
- package/dist/report/html.js +3 -2
- package/package.json +1 -1
- package/dist/runners/coverage.d.ts +0 -3
- package/dist/runners/coverage.js +0 -65
- package/dist/runners/tests.d.ts +0 -3
- package/dist/runners/tests.js +0 -54
package/README.md
CHANGED
|
@@ -25,6 +25,9 @@ npx @vibecodeqa/cli
|
|
|
25
25
|
# Fast mode (skip test execution)
|
|
26
26
|
npx @vibecodeqa/cli --skip-tests
|
|
27
27
|
|
|
28
|
+
# Watch mode (re-scan on file changes)
|
|
29
|
+
npx @vibecodeqa/cli --watch
|
|
30
|
+
|
|
28
31
|
# CI mode (exit code 1 if score < 60)
|
|
29
32
|
npx @vibecodeqa/cli --ci
|
|
30
33
|
|
|
@@ -36,8 +39,9 @@ npx @vibecodeqa/cli /path/to/project
|
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
Output goes to `.vibe-check/`:
|
|
39
|
-
- `report.html` — navigable dashboard (open in browser)
|
|
42
|
+
- `report.html` — navigable multi-page dashboard (open in browser)
|
|
40
43
|
- `report.json` — machine-readable results
|
|
44
|
+
- `history/` — last 30 reports for trend tracking
|
|
41
45
|
|
|
42
46
|
## Checks
|
|
43
47
|
|
|
@@ -113,12 +117,18 @@ Each check produces a score from 0-100. The composite score is a weighted averag
|
|
|
113
117
|
|
|
114
118
|
## Report features
|
|
115
119
|
|
|
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
|
|
116
124
|
- **Radar chart** — 6-axis view of category scores
|
|
117
|
-
- **Architecture diagram** —
|
|
118
|
-
- **
|
|
119
|
-
- **
|
|
120
|
-
- **
|
|
121
|
-
- **
|
|
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
|
|
129
|
+
- **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
|
|
131
|
+
- **Info panels** — each check has What/Risk/Fix explanations with research citations
|
|
122
132
|
- **Priority badges** — critical/high/medium/low on each check
|
|
123
133
|
|
|
124
134
|
## Trend tracking
|
|
@@ -133,6 +143,7 @@ vcqa reads the previous `.vibe-check/report.json` on each run and shows:
|
|
|
133
143
|
| Flag | Description |
|
|
134
144
|
|------|-------------|
|
|
135
145
|
| `--skip-tests` | Skip test execution and coverage (fast mode) |
|
|
146
|
+
| `--watch` | Re-scan automatically on file changes |
|
|
136
147
|
| `--ci` | Exit code 1 if composite score < 60 |
|
|
137
148
|
| `--json` | Output JSON to stdout (no HTML, no browser) |
|
|
138
149
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/** vibe-check — code health scanner for the AI coding era. */
|
|
3
|
-
import { existsSync, mkdirSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { detectRepoUrl, detectStack } from "./detect.js";
|
|
6
6
|
import { generateHTML } from "./report/html.js";
|
|
@@ -22,7 +22,8 @@ import { runTypeSafety } from "./runners/type-safety.js";
|
|
|
22
22
|
import { computeScore } from "./score.js";
|
|
23
23
|
import { computeTrend, formatTrend } from "./trend.js";
|
|
24
24
|
import { gradeFromScore } from "./types.js";
|
|
25
|
-
const
|
|
25
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
26
|
+
const VERSION = pkg.version;
|
|
26
27
|
const args = process.argv.slice(2);
|
|
27
28
|
const flags = new Set(args.filter((a) => a.startsWith("--")));
|
|
28
29
|
const cwd = resolve(args.find((a) => !a.startsWith("--")) || ".");
|
package/dist/report/html.js
CHANGED
|
@@ -140,8 +140,9 @@ export function generateHTML(report) {
|
|
|
140
140
|
for (const [file, issues] of byFile) {
|
|
141
141
|
issuesHtml += `<div class="fg"><div class="fn">${fl(file)} <span class="fc">${issues.length}</span></div>`;
|
|
142
142
|
for (const iss of issues) {
|
|
143
|
-
const
|
|
144
|
-
|
|
143
|
+
const promptText = `Fix this issue in ${e(file)}${iss.line ? ":" + iss.line : ""}\n${iss.severity}: ${e(iss.message)}${iss.rule ? " (" + e(iss.rule) + ")" : ""}\nCheck: ${e(c.name)}`;
|
|
144
|
+
const safePrompt = promptText.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n");
|
|
145
|
+
issuesHtml += `<div class="ir ${iss.severity}"><span class="is">${iss.severity[0].toUpperCase()}</span>${iss.line ? `<span class="il">${iss.line}</span>` : ""}<span class="im">${e(iss.message)}</span>${iss.rule ? `<span class="iru">${e(iss.rule)}</span>` : ""}<button class="cp-btn" onclick="navigator.clipboard.writeText('${safePrompt}');this.textContent='✓';setTimeout(()=>this.textContent='📋',1000)" title="Copy fix prompt">📋</button></div>`;
|
|
145
146
|
}
|
|
146
147
|
issuesHtml += `</div>`;
|
|
147
148
|
}
|
package/package.json
CHANGED
package/dist/runners/coverage.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/** Coverage runner — runs tests with coverage and parses the summary. */
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { gradeFromScore } from "../types.js";
|
|
5
|
-
import { run } from "./exec.js";
|
|
6
|
-
export function runCoverage(cwd, stack) {
|
|
7
|
-
const start = Date.now();
|
|
8
|
-
if (stack.testRunner === "none") {
|
|
9
|
-
return {
|
|
10
|
-
name: "coverage",
|
|
11
|
-
score: 0,
|
|
12
|
-
grade: "F",
|
|
13
|
-
details: { skipped: true, reason: "no test runner" },
|
|
14
|
-
issues: [],
|
|
15
|
-
duration: Date.now() - start,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
// Run tests with coverage
|
|
19
|
-
const cmd = stack.testRunner === "vitest"
|
|
20
|
-
? "npx vitest run --coverage 2>/dev/null || true"
|
|
21
|
-
: "npx jest --coverage --coverageReporters=json-summary 2>/dev/null || true";
|
|
22
|
-
run(cmd, cwd, 120_000);
|
|
23
|
-
// Look for coverage summary
|
|
24
|
-
const searchPaths = [
|
|
25
|
-
"coverage/coverage-summary.json",
|
|
26
|
-
"test-results/coverage/coverage-summary.json",
|
|
27
|
-
];
|
|
28
|
-
let summary = null;
|
|
29
|
-
for (const p of searchPaths) {
|
|
30
|
-
const full = join(cwd, p);
|
|
31
|
-
if (existsSync(full)) {
|
|
32
|
-
try {
|
|
33
|
-
summary = JSON.parse(readFileSync(full, "utf-8"));
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
/* parse failed */
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (!summary?.total) {
|
|
42
|
-
return {
|
|
43
|
-
name: "coverage",
|
|
44
|
-
score: 0,
|
|
45
|
-
grade: "F",
|
|
46
|
-
details: { skipped: true, reason: "no coverage data generated" },
|
|
47
|
-
issues: [],
|
|
48
|
-
duration: Date.now() - start,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
const stmts = summary.total.statements?.pct || 0;
|
|
52
|
-
const lines = summary.total.lines?.pct || 0;
|
|
53
|
-
const branches = summary.total.branches?.pct || 0;
|
|
54
|
-
const functions = summary.total.functions?.pct || 0;
|
|
55
|
-
// Score is the average of all four metrics
|
|
56
|
-
const score = Math.round((stmts + lines + branches + functions) / 4);
|
|
57
|
-
return {
|
|
58
|
-
name: "coverage",
|
|
59
|
-
score,
|
|
60
|
-
grade: gradeFromScore(score),
|
|
61
|
-
details: { statements: stmts, lines, branches, functions },
|
|
62
|
-
issues: [],
|
|
63
|
-
duration: Date.now() - start,
|
|
64
|
-
};
|
|
65
|
-
}
|
package/dist/runners/tests.d.ts
DELETED
package/dist/runners/tests.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/** Test runner — auto-detects vitest or jest. */
|
|
2
|
-
import { gradeFromScore } from "../types.js";
|
|
3
|
-
import { run } from "./exec.js";
|
|
4
|
-
export function runTests(cwd, stack) {
|
|
5
|
-
const start = Date.now();
|
|
6
|
-
if (stack.testRunner === "none") {
|
|
7
|
-
return {
|
|
8
|
-
name: "tests",
|
|
9
|
-
score: 0,
|
|
10
|
-
grade: "F",
|
|
11
|
-
details: { skipped: true, reason: "no test runner" },
|
|
12
|
-
issues: [],
|
|
13
|
-
duration: Date.now() - start,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
const cmd = stack.testRunner === "vitest"
|
|
17
|
-
? "npx vitest run --reporter=json 2>/dev/null || true"
|
|
18
|
-
: "npx jest --json 2>/dev/null || true";
|
|
19
|
-
const { stdout } = run(cmd, cwd, 120_000);
|
|
20
|
-
// Extract JSON from output (vitest may print other stuff before the JSON)
|
|
21
|
-
let data = null;
|
|
22
|
-
try {
|
|
23
|
-
// Find the JSON object in stdout
|
|
24
|
-
const jsonStart = stdout.indexOf("{");
|
|
25
|
-
if (jsonStart >= 0) {
|
|
26
|
-
data = JSON.parse(stdout.slice(jsonStart));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
/* parse failed */
|
|
31
|
-
}
|
|
32
|
-
if (!data) {
|
|
33
|
-
return {
|
|
34
|
-
name: "tests",
|
|
35
|
-
score: 0,
|
|
36
|
-
grade: "F",
|
|
37
|
-
details: { error: "could not parse test output" },
|
|
38
|
-
issues: [],
|
|
39
|
-
duration: Date.now() - start,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
const passed = data.numPassedTests || 0;
|
|
43
|
-
const failed = data.numFailedTests || 0;
|
|
44
|
-
const total = data.numTotalTests || 0;
|
|
45
|
-
const score = total === 0 ? 0 : Math.round((passed / total) * 100);
|
|
46
|
-
return {
|
|
47
|
-
name: "tests",
|
|
48
|
-
score,
|
|
49
|
-
grade: gradeFromScore(score),
|
|
50
|
-
details: { passed, failed, total, runner: stack.testRunner },
|
|
51
|
-
issues: [],
|
|
52
|
-
duration: Date.now() - start,
|
|
53
|
-
};
|
|
54
|
-
}
|