@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.
- package/dist/monitor.js +71 -9
- 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({
|
|
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: "
|
|
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(
|
|
649
|
-
if (key.return &&
|
|
650
|
-
setMode({ view: "file-issues", 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, {
|
|
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
|
|
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" })] })] }));
|