@vibecodeqa/cli 0.37.1 → 0.37.3

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 (2) hide show
  1. package/dist/monitor.js +71 -9
  2. package/package.json +1 -1
package/dist/monitor.js CHANGED
@@ -349,8 +349,7 @@ function IssueDetail({ issue, checkName, cwd, height, copied }) {
349
349
  return (_jsxs(Box, { flexDirection: "column", height: height, paddingX: 1, overflowY: "hidden", children: [_jsx(Text, { bold: true, color: "magenta", children: " \u25C8 Issue Detail" }), _jsxs(Text, { children: [_jsxs(Text, { color: sc(issue.severity), bold: true, children: [" ", issue.severity.toUpperCase(), " "] }), _jsx(Text, { dimColor: true, children: checkName }), issue.rule && _jsxs(Text, { dimColor: true, children: [" \u00B7 ", issue.rule] }), copied && _jsx(Text, { color: "green", bold: true, children: " \u2713 Copied!" })] }), _jsxs(Text, { wrap: "wrap", children: [" ", issue.message] }), issue.file && (_jsxs(Text, { color: "cyan", children: [" ", issue.file, issue.line ? `:${issue.line}` : ""] })), ctx && (_jsxs(Box, { flexDirection: "column", height: srcHeight, overflowY: "hidden", children: [_jsxs(Text, { dimColor: true, children: [" \u2500\u2500\u2500 ", ctx.filePath, " \u2500\u2500\u2500"] }), ctx.lines.slice(0, srcHeight - 2).map((l) => (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: l.highlight ? "yellow" : "gray", children: l.highlight ? "▸" : " " }), _jsxs(Text, { dimColor: true, children: [String(l.num).padStart(4), "\u2502"] }), _jsx(Text, { color: l.highlight ? "white" : undefined, children: l.text })] }, l.num))), _jsx(Text, { dimColor: true, children: " \u2500\u2500\u2500" })] })), _jsxs(Box, { flexDirection: "column", height: Math.max(3, promptHeight), overflowY: "hidden", marginTop: ctx ? 0 : 1, children: [_jsxs(Text, { bold: true, color: "green", children: [" Fix prompt ", _jsx(Text, { dimColor: true, children: "(y to copy)" })] }), promptLines.slice(0, Math.max(1, promptHeight - 1)).map((line, i) => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [" ", line] }, i)))] })] }));
350
350
  }
351
351
  // ── Git Changes View ──
352
- function GitChangesView({ cwd, checks, height, cursor }) {
353
- const changes = useMemo(() => getGitChanges(cwd), [cwd]);
352
+ function GitChangesView({ changes, checks, height, cursor }) {
354
353
  // Cross-reference with issues
355
354
  const issuesByFile = useMemo(() => {
356
355
  const map = new Map();
@@ -371,6 +370,39 @@ function GitChangesView({ cwd, checks, height, cursor }) {
371
370
  return (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: sel ? "white" : "gray", children: sel ? "▸" : " " }), _jsxs(Text, { color: statusColor[ch.status] || "gray", bold: true, children: [" ", ch.status, " "] }), _jsxs(Text, { color: sel ? "white" : undefined, children: [ch.file, " "] }), count > 0 ? (_jsxs(Text, { color: "yellow", children: [count, " issue", count !== 1 ? "s" : ""] })) : (_jsx(Text, { color: "green", children: "clean" }))] }, ch.file));
372
371
  }), changes.length > visibleLines && _jsxs(Text, { dimColor: true, children: [" +", changes.length - visibleLines, " more"] })] }))] }));
373
372
  }
373
+ // ── All Files View ──
374
+ function AllFilesView({ checks, height, cursor }) {
375
+ // Build file list from all issues, sorted by issue count descending
376
+ const fileMap = useMemo(() => {
377
+ const map = new Map();
378
+ for (const c of checks) {
379
+ for (const iss of c.issues) {
380
+ if (!iss.file || typeof iss.file !== "string")
381
+ continue;
382
+ const entry = map.get(iss.file) || { errors: 0, warnings: 0, infos: 0 };
383
+ if (iss.severity === "error")
384
+ entry.errors++;
385
+ else if (iss.severity === "warning")
386
+ entry.warnings++;
387
+ else
388
+ entry.infos++;
389
+ map.set(iss.file, entry);
390
+ }
391
+ }
392
+ return [...map.entries()]
393
+ .map(([file, counts]) => ({ file, total: counts.errors + counts.warnings + counts.infos, ...counts }))
394
+ .sort((a, b) => b.total - a.total);
395
+ }, [checks]);
396
+ const visibleLines = Math.max(1, height - 5);
397
+ // Scroll window
398
+ const scrollStart = Math.max(0, Math.min(cursor - Math.floor(visibleLines / 2), fileMap.length - visibleLines));
399
+ const visible = fileMap.slice(scrollStart, scrollStart + visibleLines);
400
+ return (_jsxs(Box, { flexDirection: "column", height: height, paddingX: 1, overflowY: "hidden", children: [_jsxs(Text, { bold: true, color: "magenta", children: [" \u25C8 Files with Issues (", fileMap.length, ")"] }), _jsx(Text, { dimColor: true, children: " sorted by issue count \u00B7 Enter to drill in" }), _jsx(Text, { children: " " }), fileMap.length === 0 ? (_jsx(Text, { color: "green", children: " No issues in any file." })) : (_jsxs(_Fragment, { children: [visible.map((f, i) => {
401
+ const idx = scrollStart + i;
402
+ const sel = idx === cursor;
403
+ return (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: sel ? "white" : "gray", children: sel ? "▸" : " " }), f.errors > 0 ? _jsxs(Text, { color: "red", bold: true, children: [String(f.errors).padStart(2), "E "] }) : _jsx(Text, { dimColor: true, children: " " }), f.warnings > 0 ? _jsxs(Text, { color: "yellow", children: [String(f.warnings).padStart(2), "W "] }) : _jsx(Text, { dimColor: true, children: " " }), f.infos > 0 ? _jsxs(Text, { dimColor: true, children: [String(f.infos).padStart(2), "I "] }) : _jsx(Text, { dimColor: true, children: " " }), _jsx(Text, { color: sel ? "white" : "cyan", children: f.file })] }, f.file));
404
+ }), fileMap.length > scrollStart + visibleLines && _jsxs(Text, { dimColor: true, children: [" +", fileMap.length - scrollStart - visibleLines, " more (\u2193)"] })] }))] }));
405
+ }
374
406
  function MonitorApp({ cwd }) {
375
407
  const { exit } = useApp();
376
408
  const { stdout } = useStdout();
@@ -407,6 +439,18 @@ function MonitorApp({ cwd }) {
407
439
  return (o[a.severity] ?? 2) - (o[b.severity] ?? 2);
408
440
  }), [state.checks]);
409
441
  const currentList = panel === "checks" ? activeChecks : allIssues;
442
+ // Derived data for file views (memoized, used by both render + keyboard)
443
+ const filesWithIssues = useMemo(() => {
444
+ const map = new Map();
445
+ for (const c of state.checks) {
446
+ for (const iss of c.issues) {
447
+ if (iss.file && typeof iss.file === "string")
448
+ map.set(iss.file, (map.get(iss.file) || 0) + 1);
449
+ }
450
+ }
451
+ return [...map.keys()].sort((a, b) => (map.get(b) || 0) - (map.get(a) || 0));
452
+ }, [state.checks]);
453
+ const gitChanges = useMemo(() => getGitChanges(cwd), [cwd, state.scanCount]);
410
454
  // Clamp cursor when data changes
411
455
  useEffect(() => {
412
456
  setCursor((c) => Math.min(c, Math.max(0, currentList.length - 1)));
@@ -504,7 +548,7 @@ function MonitorApp({ cwd }) {
504
548
  return;
505
549
  }
506
550
  if (mode.view === "file-issues") {
507
- setMode({ view: "git-changes" });
551
+ setMode({ view: "dashboard" });
508
552
  setCursor(0);
509
553
  return;
510
554
  }
@@ -577,6 +621,11 @@ function MonitorApp({ cwd }) {
577
621
  setCursor(0);
578
622
  return;
579
623
  }
624
+ if (input === "f") {
625
+ setMode({ view: "all-files" });
626
+ setCursor(0);
627
+ return;
628
+ }
580
629
  if (input === "c") {
581
630
  setMode({ view: "config" });
582
631
  setConfigCursor(0);
@@ -639,15 +688,25 @@ function MonitorApp({ cwd }) {
639
688
  }
640
689
  }
641
690
  }
691
+ // ── All files: ↑↓ navigate, Enter drill into file issues ──
692
+ if (mode.view === "all-files") {
693
+ if (key.upArrow)
694
+ setCursor((c) => Math.max(0, c - 1));
695
+ if (key.downArrow)
696
+ setCursor((c) => Math.min(filesWithIssues.length - 1, c + 1));
697
+ if (key.return && filesWithIssues[cursor]) {
698
+ setMode({ view: "file-issues", file: filesWithIssues[cursor] });
699
+ setCursor(0);
700
+ }
701
+ }
642
702
  // ── Git changes: ↑↓ navigate, Enter drill into file issues ──
643
703
  if (mode.view === "git-changes") {
644
- const changes = getGitChanges(cwd);
645
704
  if (key.upArrow)
646
705
  setCursor((c) => Math.max(0, c - 1));
647
706
  if (key.downArrow)
648
- setCursor((c) => Math.min(changes.length - 1, c + 1));
649
- if (key.return && changes[cursor]) {
650
- setMode({ view: "file-issues", file: changes[cursor].file });
707
+ setCursor((c) => Math.min(gitChanges.length - 1, c + 1));
708
+ if (key.return && gitChanges[cursor]) {
709
+ setMode({ view: "file-issues", file: gitChanges[cursor].file });
651
710
  setCursor(0);
652
711
  }
653
712
  }
@@ -681,8 +740,11 @@ function MonitorApp({ cwd }) {
681
740
  const proj = basename(cwd);
682
741
  const p = monCfg.panels;
683
742
  // ── Render views ──
743
+ if (mode.view === "all-files") {
744
+ return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), _jsx(AllFilesView, { checks: state.checks, height: rows - 3, cursor: cursor }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 \u2191\u2193 select \u00B7 Enter view file issues \u00B7 q quit" }) })] }));
745
+ }
684
746
  if (mode.view === "git-changes") {
685
- return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), _jsx(GitChangesView, { cwd: cwd, checks: state.checks, height: rows - 3, cursor: cursor }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 \u2191\u2193 select \u00B7 Enter view file issues \u00B7 q quit" }) })] }));
747
+ return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), _jsx(GitChangesView, { changes: gitChanges, checks: state.checks, height: rows - 3, cursor: cursor }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 \u2191\u2193 select \u00B7 Enter view file issues \u00B7 q quit" }) })] }));
686
748
  }
687
749
  if (mode.view === "file-issues") {
688
750
  const fileIssues = state.checks.flatMap((c) => c.issues.filter((i) => i.file === mode.file).map((i) => ({ check: c.name, ...i })));
@@ -722,7 +784,7 @@ function MonitorApp({ cwd }) {
722
784
  })] }))] })), mainVisible && (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [p.activity && _jsx(ActivityPanel, { log: log, height: activityH }), p.issues && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: panel === "issues" ? "magenta" : "gray", paddingX: 1, height: issuesH, overflowY: "hidden", children: [_jsxs(Text, { bold: true, color: "magenta", children: [" ", "\u25C8 Issues (", allIssues.length, ") ", panel === "issues" && _jsx(Text, { dimColor: true, children: "\u25C4" })] }), allIssues.slice(0, issuesH - 3).map((iss, i) => {
723
785
  const sel = panel === "issues" && i === cursor;
724
786
  return (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: sel ? "white" : "gray", children: sel ? "▸" : " " }), _jsxs(Text, { color: sc(iss.severity), bold: true, children: [iss.severity[0].toUpperCase(), " "] }), _jsxs(Text, { dimColor: true, children: [(iss.check || "").slice(0, 11).padEnd(11), " "] }), iss.file && _jsxs(Text, { color: "cyan", children: [basename(String(iss.file)).slice(0, 18).padEnd(18), " "] }), _jsx(Text, { children: iss.message.slice(0, 40) })] }, i));
725
- }), allIssues.length > issuesH - 3 && _jsxs(Text, { dimColor: true, children: [" +", allIssues.length - (issuesH - 3), " more"] })] }))] })), !sidebarVisible && !mainVisible && (_jsx(Box, { height: bodyRows, justifyContent: "center", alignItems: "center", children: _jsx(Text, { dimColor: true, children: "All panels hidden. Press c to configure." }) }))] }), _jsx(Box, { paddingX: 1, justifyContent: "space-between", children: _jsx(Text, { dimColor: true, children: "Tab panel \u00B7 \u2191\u2193 Enter Esc \u00B7 r scan \u00B7 g git \u00B7 t trends \u00B7 c config \u00B7 q quit" }) })] }));
787
+ }), allIssues.length > issuesH - 3 && _jsxs(Text, { dimColor: true, children: [" +", allIssues.length - (issuesH - 3), " more"] })] }))] })), !sidebarVisible && !mainVisible && (_jsx(Box, { height: bodyRows, justifyContent: "center", alignItems: "center", children: _jsx(Text, { dimColor: true, children: "All panels hidden. Press c to configure." }) }))] }), _jsx(Box, { paddingX: 1, justifyContent: "space-between", children: _jsx(Text, { dimColor: true, children: "Tab panel \u00B7 \u2191\u2193 Enter Esc \u00B7 r scan \u00B7 f files \u00B7 g git \u00B7 t trends \u00B7 c config \u00B7 q" }) })] }));
726
788
  }
727
789
  function Header({ proj, stack, workspace, state }) {
728
790
  return (_jsxs(Box, { paddingX: 1, justifyContent: "space-between", children: [_jsxs(Text, { children: [_jsx(Text, { color: "magenta", bold: true, children: "vcqa monitor" }), _jsxs(Text, { dimColor: true, children: [" v", VERSION] })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, children: proj }), _jsxs(Text, { dimColor: true, children: [" ", stack.language, "/", stack.framework, workspace.isMonorepo ? ` · ${workspace.tool}` : ""] })] }), _jsxs(Text, { children: [state.score > 0 && _jsxs(Text, { color: gc(state.grade), bold: true, children: [state.grade, " ", state.score, " "] }), _jsx(Text, { dimColor: true, children: state.scanning ? "⟳ scanning" : "● watching" })] })] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecodeqa/cli",
3
- "version": "0.37.1",
3
+ "version": "0.37.3",
4
4
  "description": "Code health scanner for the AI coding era. 25 checks, zero config, full report.",
5
5
  "type": "module",
6
6
  "bin": {