|
| 1 | +import { |
| 2 | + listFindingWorkflow, |
| 3 | + type FindingWorkflowSummary, |
| 4 | +} from "../findings.js"; |
| 5 | +import { readWorkspaceActivity, workspaceStatus, type WorkspaceActivityEntry, type WorkspaceStatus } from "../workspace.js"; |
| 6 | +import { wantsJson } from "./shared.js"; |
| 7 | +import { command as cmd, empty, kv, panel, readiness, statusBadge, table, title, truncate, warn } from "../tui.js"; |
| 8 | + |
| 9 | +export async function run(args: string[]): Promise<void> { |
| 10 | + const json = wantsJson(args); |
| 11 | + const [status, workflow, activity] = await Promise.all([ |
| 12 | + workspaceStatus(), |
| 13 | + listFindingWorkflow(), |
| 14 | + readWorkspaceActivity(), |
| 15 | + ]); |
| 16 | + const result = { status, workflow, activity: activity.slice(-8) }; |
| 17 | + if (json) { |
| 18 | + console.log(JSON.stringify(result, null, 2)); |
| 19 | + return; |
| 20 | + } |
| 21 | + printDashboard(status, workflow, activity.slice(-8)); |
| 22 | +} |
| 23 | + |
| 24 | +function printDashboard( |
| 25 | + status: WorkspaceStatus, |
| 26 | + workflow: FindingWorkflowSummary[], |
| 27 | + activity: WorkspaceActivityEntry[], |
| 28 | +): void { |
| 29 | + console.log(title("oh-my-vul dashboard")); |
| 30 | + const statuses = Object.entries(status.statusCounts) |
| 31 | + .map(([name, count]) => `${name}=${count}`) |
| 32 | + .join(", "); |
| 33 | + console.log( |
| 34 | + panel("workspace", [ |
| 35 | + ...kv([ |
| 36 | + ["root", status.root], |
| 37 | + ["active", String(status.activeCount)], |
| 38 | + ["archived", String(status.archivedCount)], |
| 39 | + ["statuses", statuses || "none"], |
| 40 | + ["next", workflow[0] ? cmd(workflow[0].nextAction) : cmd("omv findings init <id>")], |
| 41 | + ]), |
| 42 | + ...status.warnings.map((item) => warn(`warning ${item}`)), |
| 43 | + ]), |
| 44 | + ); |
| 45 | + |
| 46 | + if (workflow.length === 0) { |
| 47 | + console.log(empty("No active findings. Start with omv findings init <id> or /omv-find.")); |
| 48 | + } else { |
| 49 | + console.log( |
| 50 | + table( |
| 51 | + ["id", "status", "evidence", "submission", "next action"], |
| 52 | + workflow.slice(0, 8).map((finding) => [ |
| 53 | + truncate(finding.id, 30), |
| 54 | + statusBadge(finding.status), |
| 55 | + readiness(finding.evidenceScore), |
| 56 | + readiness(finding.submissionScore), |
| 57 | + cmd(truncate(finding.nextAction, 54)), |
| 58 | + ]), |
| 59 | + ), |
| 60 | + ); |
| 61 | + } |
| 62 | + |
| 63 | + if (activity.length > 0) { |
| 64 | + console.log( |
| 65 | + table( |
| 66 | + ["time", "action", "id"], |
| 67 | + activity.map((entry) => [ |
| 68 | + truncate(entry.timestamp, 27), |
| 69 | + entry.action, |
| 70 | + truncate(entry.id ?? "-", 28), |
| 71 | + ]), |
| 72 | + ), |
| 73 | + ); |
| 74 | + } |
| 75 | +} |
0 commit comments