@vibecodeqa/cli 0.9.0 → 0.10.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.
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
- # vibe-check
1
+ # VibeCode QA
2
2
 
3
3
  **Code health scanner for the AI coding era.**
4
4
 
5
5
  One command. 15 checks. Full report. Zero config.
6
6
 
7
7
  ```bash
8
- npx vibe-check
8
+ npx @vibecodeqa/cli
9
9
  ```
10
10
 
11
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)
12
12
 
13
13
  ## What it does
14
14
 
15
- vibe-check 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 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.
16
16
 
17
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.
18
18
 
@@ -20,19 +20,19 @@ The output is a self-contained HTML report with radar charts, architecture diagr
20
20
 
21
21
  ```bash
22
22
  # Scan current directory (runs tests + coverage)
23
- npx vibe-check
23
+ npx @vibecodeqa/cli
24
24
 
25
25
  # Fast mode (skip test execution)
26
- npx vibe-check --skip-tests
26
+ npx @vibecodeqa/cli --skip-tests
27
27
 
28
28
  # CI mode (exit code 1 if score < 60)
29
- npx vibe-check --ci
29
+ npx @vibecodeqa/cli --ci
30
30
 
31
31
  # JSON output (pipe to other tools)
32
- npx vibe-check --json
32
+ npx @vibecodeqa/cli --json
33
33
 
34
34
  # Scan a specific directory
35
- npx vibe-check /path/to/project
35
+ npx @vibecodeqa/cli /path/to/project
36
36
  ```
37
37
 
38
38
  Output goes to `.vibe-check/`:
@@ -123,7 +123,7 @@ Each check produces a score from 0-100. The composite score is a weighted averag
123
123
 
124
124
  ## Trend tracking
125
125
 
126
- vibe-check reads the previous `.vibe-check/report.json` on each run and shows:
126
+ vcqa reads the previous `.vibe-check/report.json` on each run and shows:
127
127
  - Score change (↑ improved / ↓ declined)
128
128
  - Per-check deltas
129
129
  - New vs. fixed issue counts
@@ -170,5 +170,5 @@ MIT — Free forever as a CLI tool.
170
170
  ## Links
171
171
 
172
172
  - **GitHub:** https://github.com/freeappstore-online/vibe-check
173
- - **Website:** https://vibechecker.online (coming soon)
173
+ - **Website:** https://vibecodeqa.online
174
174
  - **Issues:** https://github.com/freeappstore-online/vibe-check/issues
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, writeFileSync } from "node:fs";
3
+ import { existsSync, mkdirSync, 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,7 @@ 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 VERSION = "0.9.0";
25
+ const VERSION = "0.10.0";
26
26
  const args = process.argv.slice(2);
27
27
  const flags = new Set(args.filter((a) => a.startsWith("--")));
28
28
  const cwd = resolve(args.find((a) => !a.startsWith("--")) || ".");
@@ -41,7 +41,7 @@ async function main() {
41
41
  const start = Date.now();
42
42
  if (!jsonOnly) {
43
43
  console.log("");
44
- console.log(" \x1b[1mvibe-check\x1b[0m v" + VERSION);
44
+ console.log(" \x1b[1m\x1b[38;5;141mvcqa\x1b[0m v" + VERSION);
45
45
  console.log(" \x1b[2m" + cwd + "\x1b[0m");
46
46
  console.log("");
47
47
  }
@@ -106,6 +106,22 @@ async function main() {
106
106
  const trend = computeTrend(report, outputDir);
107
107
  if (!existsSync(outputDir))
108
108
  mkdirSync(outputDir, { recursive: true });
109
+ // Save to history before overwriting current report
110
+ const historyDir = join(outputDir, "history");
111
+ if (!existsSync(historyDir))
112
+ mkdirSync(historyDir, { recursive: true });
113
+ const historyFile = join(historyDir, `${report.timestamp.replace(/[:.]/g, "-")}.json`);
114
+ writeFileSync(historyFile, JSON.stringify(report, null, 2));
115
+ // Keep only last 30 history entries
116
+ const historyFiles = readdirSync(historyDir).filter((f) => f.endsWith(".json")).sort();
117
+ if (historyFiles.length > 30) {
118
+ for (const old of historyFiles.slice(0, historyFiles.length - 30)) {
119
+ try {
120
+ unlinkSync(join(historyDir, old));
121
+ }
122
+ catch { /* ignore */ }
123
+ }
124
+ }
109
125
  writeFileSync(join(outputDir, "report.json"), JSON.stringify(report, null, 2));
110
126
  writeFileSync(join(outputDir, "report.html"), generateHTML(report));
111
127
  if (jsonOnly) {
@@ -9,6 +9,7 @@
9
9
  * All in one self-contained HTML file using hash routing + show/hide.
10
10
  */
11
11
  import { getCheckMeta } from "../check-meta.js";
12
+ import { generateArchSVG } from "../runners/architecture.js";
12
13
  function e(s) {
13
14
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
14
15
  }
@@ -116,7 +117,7 @@ export function generateHTML(report) {
116
117
  const subPages = cs.checks.map((c, i) => {
117
118
  const meta = getCheckMeta(c.name);
118
119
  const sk = c.details.skipped;
119
- const details = Object.entries(c.details).filter(([k]) => k !== "skipped" && k !== "reason").map(([k, v]) => {
120
+ const detailsFiltered = Object.entries(c.details).filter(([k]) => k !== "skipped" && k !== "reason" && k !== "graph").map(([k, v]) => {
120
121
  const d = Array.isArray(v) ? v.join(", ") : typeof v === "object" ? JSON.stringify(v) : String(v);
121
122
  return `<div class="kv"><span class="k">${e(k)}</span><span class="v">${e(d)}</span></div>`;
122
123
  }).join("");
@@ -138,7 +139,8 @@ export function generateHTML(report) {
138
139
  for (const [file, issues] of byFile) {
139
140
  issuesHtml += `<div class="fg"><div class="fn">${fl(file)} <span class="fc">${issues.length}</span></div>`;
140
141
  for (const iss of issues) {
141
- 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>` : ""}</div>`;
142
+ const prompt = `Fix this issue in ${file}${iss.line ? ":" + iss.line : ""}\\n${iss.severity}: ${iss.message}${iss.rule ? " (" + iss.rule + ")" : ""}\\nCheck: ${c.name}`;
143
+ 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('${prompt.replace(/'/g, "\\'")}');this.textContent='✓';setTimeout(()=>this.textContent='📋',1000)" title="Copy fix prompt">📋</button></div>`;
142
144
  }
143
145
  issuesHtml += `</div>`;
144
146
  }
@@ -153,7 +155,8 @@ export function generateHTML(report) {
153
155
  <div class="ch-head"><span class="ch-g" style="color:${sk ? "#555" : gc(c.grade)}">${sk ? "—" : c.grade}</span><div><b>${e(meta.label)}</b><span class="ch-s">${sk ? "skipped" : c.score + "/100"} · weight ${meta.weight}% · ${c.duration}ms · ${c.issues.length} issues</span></div><span class="pri" style="color:${pc(meta.priority)}">${meta.priority}</span></div>
154
156
  ${meta.description ? `<div class="info-panel"><div class="ip-row"><span class="ip-label">What</span><span>${e(meta.description)}</span></div><div class="ip-row"><span class="ip-label">Risk</span><span>${e(meta.risk)}</span></div><div class="ip-row"><span class="ip-label">Fix</span><span>${e(meta.recommendation)}</span></div></div>` : ""}
155
157
  ${sk ? `<p class="skip-r">${e(c.details.reason || "skipped")}</p>` : ""}
156
- ${details ? `<div class="kvs">${details}</div>` : ""}
158
+ ${c.name === "architecture" && !sk ? `<div class="arch-svg">${generateArchSVG(c.details)}</div>` : ""}
159
+ ${detailsFiltered ? `<div class="kvs">${detailsFiltered}</div>` : ""}
157
160
  ${issuesHtml ? `<div class="iss-list">${issuesHtml}</div>` : '<p style="color:var(--muted);font-size:0.8rem;margin-top:1rem">No issues found.</p>'}
158
161
  </div>`;
159
162
  }).join("");
@@ -192,7 +195,7 @@ ${fileRows || '<p style="color:var(--muted)">No file-level issues found.</p>'}
192
195
  <head>
193
196
  <meta charset="utf-8">
194
197
  <meta name="viewport" content="width=device-width,initial-scale=1">
195
- <title>Vibe Check — ${e(proj)}</title>
198
+ <title>VibeCode QA — ${e(proj)}</title>
196
199
  <style>
197
200
  :root{--bg:#09090b;--card:#111115;--border:#1e1e24;--text:#e5e5e5;--muted:#6b7280;--pass:#22c55e;--fail:#ef4444;--warn:#eab308;--info:#6366f1;--accent:#818cf8}
198
201
  *{margin:0;padding:0;box-sizing:border-box}
@@ -312,13 +315,17 @@ h3{font-size:0.85rem;color:var(--muted);text-transform:uppercase;letter-spacing:
312
315
  .footer{text-align:center;color:var(--muted);font-size:0.58rem;margin-top:2rem;padding:0.8rem 0;border-top:1px solid var(--border)}
313
316
  .footer a{color:var(--muted)}
314
317
  .flink{color:var(--accent);text-decoration:none;font-family:"SF Mono",monospace}.flink:hover{text-decoration:underline}
318
+ .arch-svg{margin:1rem 0;overflow-x:auto}
319
+ .arch-svg svg{border-radius:8px}
320
+ .cp-btn{background:none;border:none;cursor:pointer;font-size:0.6rem;opacity:0.3;padding:0 0.2rem;flex-shrink:0}.cp-btn:hover{opacity:1}
321
+ .ir:hover .cp-btn{opacity:0.6}
315
322
  @media(max-width:768px){.side{display:none}.content{margin-left:0;padding:1rem}.cats{grid-template-columns:1fr 1fr}.dash{flex-direction:column}}
316
323
  </style>
317
324
  </head>
318
325
  <body>
319
326
 
320
327
  <nav class="top">
321
- <div class="logo"><span>vibe</span>-check</div>
328
+ <div class="logo"><span>VibeCode</span> QA</div>
322
329
  ${topNav}
323
330
  </nav>
324
331
 
@@ -338,7 +345,7 @@ h3{font-size:0.85rem;color:var(--muted);text-transform:uppercase;letter-spacing:
338
345
  ${catPages}
339
346
  ${issuesPage}
340
347
  ${filesPage}
341
- <div class="footer">Generated by <a href="https://github.com/freeappstore-online/vibe-check">vibe-check</a> v${report.version}</div>
348
+ <div class="footer">Generated by <a href="https://vibecodeqa.online">VibeCode QA</a> v${report.version} &mdash; <code>npx @vibecodeqa/cli</code></div>
342
349
  </div>
343
350
 
344
351
  <script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecodeqa/cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Code health scanner for the AI coding era. 15 checks, zero config, full report.",
5
5
  "type": "module",
6
6
  "bin": {