@vertaaux/cli 0.3.3 → 0.5.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/CHANGELOG.md +97 -0
- package/MIGRATION.md +239 -0
- package/README.md +34 -16
- package/dist/app/interactive-app.d.ts +101 -0
- package/dist/app/interactive-app.d.ts.map +1 -0
- package/dist/app/interactive-app.js +309 -0
- package/dist/app/layout/canvas.d.ts +23 -0
- package/dist/app/layout/canvas.d.ts.map +1 -0
- package/dist/app/layout/canvas.js +36 -0
- package/dist/app/layout/footer.d.ts +31 -0
- package/dist/app/layout/footer.d.ts.map +1 -0
- package/dist/app/layout/footer.js +41 -0
- package/dist/app/layout/header.d.ts +20 -0
- package/dist/app/layout/header.d.ts.map +1 -0
- package/dist/app/layout/header.js +27 -0
- package/dist/app/menu/categories.d.ts +20 -0
- package/dist/app/menu/categories.d.ts.map +1 -0
- package/dist/app/menu/categories.js +181 -0
- package/dist/app/menu/filter.d.ts +17 -0
- package/dist/app/menu/filter.d.ts.map +1 -0
- package/dist/app/menu/filter.js +33 -0
- package/dist/app/menu/menu-view.d.ts +35 -0
- package/dist/app/menu/menu-view.d.ts.map +1 -0
- package/dist/app/menu/menu-view.js +230 -0
- package/dist/app/menu/recent.d.ts +24 -0
- package/dist/app/menu/recent.d.ts.map +1 -0
- package/dist/app/menu/recent.js +49 -0
- package/dist/app/types.d.ts +43 -0
- package/dist/app/types.d.ts.map +1 -0
- package/dist/app/types.js +7 -0
- package/dist/app/views/command-runner.d.ts +36 -0
- package/dist/app/views/command-runner.d.ts.map +1 -0
- package/dist/app/views/command-runner.js +372 -0
- package/dist/app/views/help-overlay.d.ts +21 -0
- package/dist/app/views/help-overlay.d.ts.map +1 -0
- package/dist/app/views/help-overlay.js +45 -0
- package/dist/auth/ci-token.d.ts +14 -2
- package/dist/auth/ci-token.d.ts.map +1 -1
- package/dist/auth/ci-token.js +15 -30
- package/dist/auth/device-flow.d.ts +2 -1
- package/dist/auth/device-flow.d.ts.map +1 -1
- package/dist/auth/device-flow.js +13 -10
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +12 -2
- package/dist/baseline/diff.d.ts +2 -2
- package/dist/baseline/diff.d.ts.map +1 -1
- package/dist/baseline/diff.js +15 -34
- package/dist/commands/a11y.d.ts +9 -0
- package/dist/commands/a11y.d.ts.map +1 -0
- package/dist/commands/a11y.js +76 -0
- package/dist/commands/audit/artifacts.d.ts +27 -0
- package/dist/commands/audit/artifacts.d.ts.map +1 -0
- package/dist/commands/audit/artifacts.js +158 -0
- package/dist/commands/audit/ci-detection.d.ts +18 -0
- package/dist/commands/audit/ci-detection.d.ts.map +1 -0
- package/dist/commands/audit/ci-detection.js +71 -0
- package/dist/commands/audit/explain.d.ts +11 -0
- package/dist/commands/audit/explain.d.ts.map +1 -0
- package/dist/commands/audit/explain.js +45 -0
- package/dist/commands/audit/filters.d.ts +17 -0
- package/dist/commands/audit/filters.d.ts.map +1 -0
- package/dist/commands/audit/filters.js +40 -0
- package/dist/commands/audit/index.d.ts +18 -0
- package/dist/commands/audit/index.d.ts.map +1 -0
- package/dist/commands/audit/index.js +564 -0
- package/dist/commands/audit/output.d.ts +32 -0
- package/dist/commands/audit/output.d.ts.map +1 -0
- package/dist/commands/audit/output.js +130 -0
- package/dist/commands/audit/policy.d.ts +19 -0
- package/dist/commands/audit/policy.d.ts.map +1 -0
- package/dist/commands/audit/policy.js +102 -0
- package/dist/commands/audit/scoring.d.ts +23 -0
- package/dist/commands/audit/scoring.d.ts.map +1 -0
- package/dist/commands/audit/scoring.js +70 -0
- package/dist/commands/audit/types.d.ts +88 -0
- package/dist/commands/audit/types.d.ts.map +1 -0
- package/dist/commands/audit/types.js +8 -0
- package/dist/commands/audit.d.ts +2 -60
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +2 -1038
- package/dist/commands/baseline.d.ts +1 -0
- package/dist/commands/baseline.d.ts.map +1 -1
- package/dist/commands/baseline.js +205 -121
- package/dist/commands/comment.d.ts +22 -0
- package/dist/commands/comment.d.ts.map +1 -1
- package/dist/commands/comment.js +122 -58
- package/dist/commands/compare.d.ts +17 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +287 -180
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +168 -141
- package/dist/commands/doc.d.ts +10 -0
- package/dist/commands/doc.d.ts.map +1 -1
- package/dist/commands/doc.js +134 -76
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +164 -17
- package/dist/commands/download.d.ts +10 -0
- package/dist/commands/download.d.ts.map +1 -1
- package/dist/commands/download.js +169 -112
- package/dist/commands/explain.d.ts +5 -0
- package/dist/commands/explain.d.ts.map +1 -1
- package/dist/commands/explain.js +241 -155
- package/dist/commands/fix-all.d.ts +25 -0
- package/dist/commands/fix-all.d.ts.map +1 -0
- package/dist/commands/fix-all.js +206 -0
- package/dist/commands/fix-plan.d.ts +9 -0
- package/dist/commands/fix-plan.d.ts.map +1 -1
- package/dist/commands/fix-plan.js +152 -89
- package/dist/commands/fix.d.ts +17 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +111 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +94 -42
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +268 -95
- package/dist/commands/patch-review.d.ts +11 -0
- package/dist/commands/patch-review.d.ts.map +1 -1
- package/dist/commands/patch-review.js +159 -97
- package/dist/commands/policy.d.ts +31 -0
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +269 -124
- package/dist/commands/release-notes.d.ts +10 -0
- package/dist/commands/release-notes.d.ts.map +1 -1
- package/dist/commands/release-notes.js +127 -73
- package/dist/commands/scan.d.ts +13 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +133 -0
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/suggest.d.ts +10 -0
- package/dist/commands/suggest.d.ts.map +1 -1
- package/dist/commands/suggest.js +153 -82
- package/dist/commands/triage.d.ts +35 -0
- package/dist/commands/triage.d.ts.map +1 -1
- package/dist/commands/triage.js +206 -81
- package/dist/commands/upload.d.ts +9 -0
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +140 -101
- package/dist/commands/verify.d.ts +13 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +118 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +125 -990
- package/dist/interactive/fix-wizard.d.ts +3 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -1
- package/dist/interactive/fix-wizard.js +130 -112
- package/dist/interactive/init-wizard.d.ts +3 -1
- package/dist/interactive/init-wizard.d.ts.map +1 -1
- package/dist/interactive/init-wizard.js +207 -138
- package/dist/interactive/prompts.d.ts +7 -3
- package/dist/interactive/prompts.d.ts.map +1 -1
- package/dist/interactive/prompts.js +44 -23
- package/dist/output/envelope.d.ts +2 -0
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +18 -2
- package/dist/output/factory.d.ts +9 -1
- package/dist/output/factory.d.ts.map +1 -1
- package/dist/output/html.d.ts +2 -1
- package/dist/output/html.d.ts.map +1 -1
- package/dist/output/html.js +3 -2
- package/dist/output/human.d.ts +9 -1
- package/dist/output/human.d.ts.map +1 -1
- package/dist/output/human.js +17 -2
- package/dist/output/json.d.ts +2 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/junit.d.ts +2 -1
- package/dist/output/junit.d.ts.map +1 -1
- package/dist/output/sarif.d.ts +2 -1
- package/dist/output/sarif.d.ts.map +1 -1
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/ui/banner.d.ts +34 -0
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +97 -5
- package/dist/ui/diagnostics.d.ts +9 -4
- package/dist/ui/diagnostics.d.ts.map +1 -1
- package/dist/ui/diagnostics.js +32 -82
- package/dist/ui/strings.d.ts +373 -0
- package/dist/ui/strings.d.ts.map +1 -0
- package/dist/ui/strings.js +499 -0
- package/dist/ui/table.d.ts +0 -2
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +3 -4
- package/dist/utils/api-client.d.ts +46 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +170 -0
- package/dist/utils/client.d.ts +29 -18
- package/dist/utils/client.d.ts.map +1 -1
- package/dist/utils/client.js +102 -12
- package/dist/utils/formatters.d.ts +38 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +277 -0
- package/dist/utils/local-capture.d.ts +25 -0
- package/dist/utils/local-capture.d.ts.map +1 -0
- package/dist/utils/local-capture.js +57 -0
- package/dist/utils/url-classify.d.ts +18 -0
- package/dist/utils/url-classify.d.ts.map +1 -0
- package/dist/utils/url-classify.js +106 -0
- package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
- package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
- package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.js +689 -21
- package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
- package/package.json +13 -5
- package/dist/commands/client.d.ts +0 -14
- package/dist/commands/client.d.ts.map +0 -1
- package/dist/commands/client.js +0 -362
- package/dist/commands/drift.d.ts +0 -15
- package/dist/commands/drift.d.ts.map +0 -1
- package/dist/commands/drift.js +0 -309
- package/dist/commands/protect.d.ts +0 -16
- package/dist/commands/protect.d.ts.map +0 -1
- package/dist/commands/protect.js +0 -323
- package/dist/commands/report.d.ts +0 -15
- package/dist/commands/report.d.ts.map +0 -1
- package/dist/commands/report.js +0 -214
- package/dist/policy/sync.d.ts +0 -67
- package/dist/policy/sync.d.ts.map +0 -1
- package/dist/policy/sync.js +0 -147
|
@@ -196,6 +196,7 @@ var tokens = {
|
|
|
196
196
|
var _colorEnabled = true;
|
|
197
197
|
function setColorEnabled(enabled) {
|
|
198
198
|
_colorEnabled = enabled;
|
|
199
|
+
chalk.level = enabled ? 3 : 0;
|
|
199
200
|
}
|
|
200
201
|
function isColorEnabled() {
|
|
201
202
|
return _colorEnabled;
|
|
@@ -216,6 +217,17 @@ function bold(text) {
|
|
|
216
217
|
if (!_colorEnabled) return text;
|
|
217
218
|
return chalk.bold(text);
|
|
218
219
|
}
|
|
220
|
+
function severityColor(level) {
|
|
221
|
+
const normalized = (level || "info").toLowerCase();
|
|
222
|
+
const hex = severity[normalized] ?? severity.info;
|
|
223
|
+
const isBold = ["critical", "error", "serious", "warning"].includes(normalized);
|
|
224
|
+
const label2 = normalized.toUpperCase();
|
|
225
|
+
return isBold ? boldColor(label2, hex) : colorize(label2, hex);
|
|
226
|
+
}
|
|
227
|
+
function bgColor(text, hex) {
|
|
228
|
+
if (!_colorEnabled) return text;
|
|
229
|
+
return chalk.bgHex(hex)(text);
|
|
230
|
+
}
|
|
219
231
|
function applyGradient(text, colors = gradient) {
|
|
220
232
|
if (!_colorEnabled) return text;
|
|
221
233
|
const colorCount = colors.length;
|
|
@@ -254,7 +266,7 @@ function shouldUseColor() {
|
|
|
254
266
|
return isTTY();
|
|
255
267
|
}
|
|
256
268
|
function getTerminalWidth() {
|
|
257
|
-
return process.stderr.columns || 80;
|
|
269
|
+
return parseInt(process.env.COLUMNS ?? "", 10) || process.stderr.columns || 80;
|
|
258
270
|
}
|
|
259
271
|
function getTerminalHeight() {
|
|
260
272
|
return process.stderr.rows || 24;
|
|
@@ -267,6 +279,96 @@ function supportsUnicode() {
|
|
|
267
279
|
return true;
|
|
268
280
|
}
|
|
269
281
|
|
|
282
|
+
// src/symbols.ts
|
|
283
|
+
var SYMBOL_MAP = {
|
|
284
|
+
nerd: {
|
|
285
|
+
// Nerd Font Material Design icons (private use area U+F0000+)
|
|
286
|
+
success: "\u{F012C}",
|
|
287
|
+
// nf-md-check_circle
|
|
288
|
+
fail: "\u{F0156}",
|
|
289
|
+
// nf-md-close_circle
|
|
290
|
+
warning: "\u{F01A6}",
|
|
291
|
+
// nf-md-alert
|
|
292
|
+
info: "\u{F02FD}",
|
|
293
|
+
// nf-md-information
|
|
294
|
+
pending: "\u25EF",
|
|
295
|
+
// ◯ large circle (no NF required)
|
|
296
|
+
running: "\u25C9"
|
|
297
|
+
// ◉ fisheye (no NF required)
|
|
298
|
+
},
|
|
299
|
+
unicode: {
|
|
300
|
+
success: "\u2713",
|
|
301
|
+
fail: "\u2717",
|
|
302
|
+
warning: "\u25B2",
|
|
303
|
+
info: "\u2139",
|
|
304
|
+
pending: "\u25CB",
|
|
305
|
+
running: "\u25C6"
|
|
306
|
+
},
|
|
307
|
+
ascii: {
|
|
308
|
+
success: "+",
|
|
309
|
+
fail: "x",
|
|
310
|
+
warning: "!",
|
|
311
|
+
info: "i",
|
|
312
|
+
pending: "-",
|
|
313
|
+
running: "*"
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var _tier = "unicode";
|
|
317
|
+
function setSymbolTier(tier) {
|
|
318
|
+
_tier = tier;
|
|
319
|
+
}
|
|
320
|
+
function sym(role) {
|
|
321
|
+
return SYMBOL_MAP[_tier][role];
|
|
322
|
+
}
|
|
323
|
+
function detectSymbolTier(options = {}) {
|
|
324
|
+
if (options.plainMode) return "ascii";
|
|
325
|
+
const envIcons = process.env.VERTAA_ICONS;
|
|
326
|
+
if (envIcons === "nerd" || envIcons === "unicode" || envIcons === "ascii") {
|
|
327
|
+
return envIcons;
|
|
328
|
+
}
|
|
329
|
+
const termProgram = process.env.TERM_PROGRAM;
|
|
330
|
+
if (termProgram === "iTerm.app" || termProgram === "WezTerm") {
|
|
331
|
+
return "nerd";
|
|
332
|
+
}
|
|
333
|
+
if (supportsUnicode()) return "unicode";
|
|
334
|
+
return "ascii";
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/plain.ts
|
|
338
|
+
var _plainMode = false;
|
|
339
|
+
function setPlainMode(enabled) {
|
|
340
|
+
_plainMode = enabled;
|
|
341
|
+
if (enabled) {
|
|
342
|
+
setColorEnabled(false);
|
|
343
|
+
setSymbolTier("ascii");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function isPlainMode() {
|
|
347
|
+
return _plainMode;
|
|
348
|
+
}
|
|
349
|
+
function toPlainBox(str) {
|
|
350
|
+
if (!_plainMode) return str;
|
|
351
|
+
return str.replace(/[─━═]/g, "-").replace(/[│┃║]/g, "|").replace(/[╭╮╰╯]/g, "+").replace(/[┌┍┎┏╔]/g, "+").replace(/[┐┑┒┓╗]/g, "+").replace(/[└┕┖┗╚]/g, "+").replace(/[┘┙┚┛╝]/g, "+").replace(/[├┤┬┴┼]/g, "+");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/easing.ts
|
|
355
|
+
function linear(t) {
|
|
356
|
+
return t;
|
|
357
|
+
}
|
|
358
|
+
function easeIn(t) {
|
|
359
|
+
return t * t;
|
|
360
|
+
}
|
|
361
|
+
function easeOut(t) {
|
|
362
|
+
return t * (2 - t);
|
|
363
|
+
}
|
|
364
|
+
function easeInOut(t) {
|
|
365
|
+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
366
|
+
}
|
|
367
|
+
function lerp(from, to, t, ease = linear) {
|
|
368
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
369
|
+
return from + (to - from) * ease(clamped);
|
|
370
|
+
}
|
|
371
|
+
|
|
270
372
|
// src/primitives/text.ts
|
|
271
373
|
var text_exports = {};
|
|
272
374
|
__export(text_exports, {
|
|
@@ -385,7 +487,8 @@ function box(content, opts = {}) {
|
|
|
385
487
|
result.push(bc(chars.vertical) + " ".repeat(termWidth - 2) + bc(chars.vertical));
|
|
386
488
|
}
|
|
387
489
|
result.push(renderBottomBorder(chars, termWidth, subtitle, borderColor));
|
|
388
|
-
|
|
490
|
+
const output = result.join("\n");
|
|
491
|
+
return toPlainBox(output);
|
|
389
492
|
}
|
|
390
493
|
function renderNoBorder(content, padding) {
|
|
391
494
|
const pad = " ".repeat(padding);
|
|
@@ -530,6 +633,9 @@ function alignCell(text, width, align) {
|
|
|
530
633
|
// src/primitives/spinner.ts
|
|
531
634
|
var BRAILLE_FRAMES = ["\u287F", "\u28DF", "\u28EF", "\u28F7", "\u28FE", "\u28FD", "\u28FB", "\u28BF"];
|
|
532
635
|
var FRAME_INTERVAL = 80;
|
|
636
|
+
function spinnerFrame(frameIndex) {
|
|
637
|
+
return BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length];
|
|
638
|
+
}
|
|
533
639
|
function createSpinner(text, output = process.stderr) {
|
|
534
640
|
let frameIndex = 0;
|
|
535
641
|
let currentText = text;
|
|
@@ -539,6 +645,11 @@ function createSpinner(text, output = process.stderr) {
|
|
|
539
645
|
const enabled = isTTY();
|
|
540
646
|
function render() {
|
|
541
647
|
if (!enabled) return;
|
|
648
|
+
if (isPlainMode()) {
|
|
649
|
+
output.write(`[running] ${currentText}
|
|
650
|
+
`);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
542
653
|
const frame = isColorEnabled() ? colorize(BRAILLE_FRAMES[frameIndex], brand.lime) : BRAILLE_FRAMES[frameIndex];
|
|
543
654
|
const phaseStr = currentPhase ? dim(` [${currentPhase}]`) : "";
|
|
544
655
|
const line = `${frame} ${currentText}${phaseStr}`;
|
|
@@ -563,8 +674,12 @@ function createSpinner(text, output = process.stderr) {
|
|
|
563
674
|
running = true;
|
|
564
675
|
frameIndex = 0;
|
|
565
676
|
if (enabled) {
|
|
566
|
-
|
|
567
|
-
|
|
677
|
+
if (isPlainMode()) {
|
|
678
|
+
render();
|
|
679
|
+
} else {
|
|
680
|
+
render();
|
|
681
|
+
timer = setInterval(render, FRAME_INTERVAL);
|
|
682
|
+
}
|
|
568
683
|
}
|
|
569
684
|
},
|
|
570
685
|
stop() {
|
|
@@ -583,23 +698,23 @@ function createSpinner(text, output = process.stderr) {
|
|
|
583
698
|
},
|
|
584
699
|
succeed(text2) {
|
|
585
700
|
instance.stop();
|
|
586
|
-
const
|
|
587
|
-
writeFinalLine(
|
|
701
|
+
const icon = isColorEnabled() ? colorize(sym("success"), "#4ADE80") : sym("success");
|
|
702
|
+
writeFinalLine(icon, text2);
|
|
588
703
|
},
|
|
589
704
|
fail(text2) {
|
|
590
705
|
instance.stop();
|
|
591
|
-
const
|
|
592
|
-
writeFinalLine(
|
|
706
|
+
const icon = isColorEnabled() ? colorize(sym("fail"), "#F87171") : sym("fail");
|
|
707
|
+
writeFinalLine(icon, text2);
|
|
593
708
|
},
|
|
594
709
|
warn(text2) {
|
|
595
710
|
instance.stop();
|
|
596
|
-
const
|
|
597
|
-
writeFinalLine(
|
|
711
|
+
const icon = isColorEnabled() ? colorize(sym("warning"), "#FACC15") : sym("warning");
|
|
712
|
+
writeFinalLine(icon, text2);
|
|
598
713
|
},
|
|
599
714
|
info(text2) {
|
|
600
715
|
instance.stop();
|
|
601
|
-
const
|
|
602
|
-
writeFinalLine(
|
|
716
|
+
const icon = isColorEnabled() ? colorize(sym("info"), "#6BCEFF") : sym("info");
|
|
717
|
+
writeFinalLine(icon, text2);
|
|
603
718
|
}
|
|
604
719
|
};
|
|
605
720
|
return instance;
|
|
@@ -617,7 +732,7 @@ function createProgressBar(opts) {
|
|
|
617
732
|
output = process.stderr
|
|
618
733
|
} = opts;
|
|
619
734
|
const enabled = isTTY();
|
|
620
|
-
|
|
735
|
+
const startTime = Date.now();
|
|
621
736
|
function renderBar(current, barWidth) {
|
|
622
737
|
const pct = total > 0 ? Math.min(current / total, 1) : 0;
|
|
623
738
|
const pctStr = `${Math.round(pct * 100)}%`;
|
|
@@ -639,8 +754,8 @@ function createProgressBar(opts) {
|
|
|
639
754
|
if (!enabled) return;
|
|
640
755
|
output.write(screen.clearLine + "\r");
|
|
641
756
|
if (message) {
|
|
642
|
-
const
|
|
643
|
-
output.write(`${
|
|
757
|
+
const sym2 = isColorEnabled() ? colorize("\u2713", "#4ADE80") : "\u2713";
|
|
758
|
+
output.write(`${sym2} ${message}
|
|
644
759
|
`);
|
|
645
760
|
}
|
|
646
761
|
},
|
|
@@ -648,8 +763,8 @@ function createProgressBar(opts) {
|
|
|
648
763
|
if (!enabled) return;
|
|
649
764
|
output.write(screen.clearLine + "\r");
|
|
650
765
|
if (message) {
|
|
651
|
-
const
|
|
652
|
-
output.write(`${
|
|
766
|
+
const sym2 = isColorEnabled() ? colorize("\u2717", "#F87171") : "\u2717";
|
|
767
|
+
output.write(`${sym2} ${message}
|
|
653
768
|
`);
|
|
654
769
|
}
|
|
655
770
|
},
|
|
@@ -856,6 +971,200 @@ function parseDiff(diffText) {
|
|
|
856
971
|
return lines;
|
|
857
972
|
}
|
|
858
973
|
|
|
974
|
+
// src/primitives/error-box.ts
|
|
975
|
+
function buildBoxWidth() {
|
|
976
|
+
return Math.min(getTerminalWidth() - 4, 88);
|
|
977
|
+
}
|
|
978
|
+
function buildErrorContent(opts) {
|
|
979
|
+
const parts = [];
|
|
980
|
+
parts.push(
|
|
981
|
+
`${sym("fail")} Error: ${bold(opts.message)}`
|
|
982
|
+
);
|
|
983
|
+
if (opts.context !== void 0 && opts.context !== "") {
|
|
984
|
+
parts.push("");
|
|
985
|
+
parts.push(dim(opts.context));
|
|
986
|
+
}
|
|
987
|
+
if (opts.suggestion !== void 0 && opts.suggestion !== "") {
|
|
988
|
+
parts.push("");
|
|
989
|
+
parts.push(colorize(`Try: ${opts.suggestion}`, brand.lime));
|
|
990
|
+
}
|
|
991
|
+
if (opts.exitCode !== void 0) {
|
|
992
|
+
parts.push("");
|
|
993
|
+
parts.push(dim(`Exit code: ${opts.exitCode}`));
|
|
994
|
+
}
|
|
995
|
+
return parts.join("\n");
|
|
996
|
+
}
|
|
997
|
+
function buildWarningContent(opts) {
|
|
998
|
+
const parts = [];
|
|
999
|
+
parts.push(
|
|
1000
|
+
`${sym("warning")} Warning: ${bold(opts.message)}`
|
|
1001
|
+
);
|
|
1002
|
+
if (opts.context !== void 0 && opts.context !== "") {
|
|
1003
|
+
parts.push("");
|
|
1004
|
+
parts.push(dim(opts.context));
|
|
1005
|
+
}
|
|
1006
|
+
if (opts.suggestion !== void 0 && opts.suggestion !== "") {
|
|
1007
|
+
parts.push("");
|
|
1008
|
+
parts.push(colorize(`Try: ${opts.suggestion}`, brand.lime));
|
|
1009
|
+
}
|
|
1010
|
+
return parts.join("\n");
|
|
1011
|
+
}
|
|
1012
|
+
function renderError(opts) {
|
|
1013
|
+
const content = buildErrorContent(opts);
|
|
1014
|
+
return box(content, {
|
|
1015
|
+
border: "rounded",
|
|
1016
|
+
borderColor: tokens.error,
|
|
1017
|
+
padding: 1,
|
|
1018
|
+
width: buildBoxWidth()
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
function renderWarning(opts) {
|
|
1022
|
+
const content = buildWarningContent(opts);
|
|
1023
|
+
return box(content, {
|
|
1024
|
+
border: "rounded",
|
|
1025
|
+
borderColor: tokens.warning,
|
|
1026
|
+
padding: 1,
|
|
1027
|
+
width: buildBoxWidth()
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// src/layout/step-list.ts
|
|
1032
|
+
function stepGlyph(state, frameIndex) {
|
|
1033
|
+
switch (state.status) {
|
|
1034
|
+
case "running":
|
|
1035
|
+
return colorize(spinnerFrame(frameIndex), tokens.success);
|
|
1036
|
+
case "done":
|
|
1037
|
+
return colorize(sym("success"), tokens.success);
|
|
1038
|
+
case "failed":
|
|
1039
|
+
return colorize(sym("fail"), tokens.error);
|
|
1040
|
+
case "warning":
|
|
1041
|
+
return colorize(sym("warning"), tokens.warning);
|
|
1042
|
+
case "skipped":
|
|
1043
|
+
return dim("\u2014");
|
|
1044
|
+
default:
|
|
1045
|
+
return dim(sym("pending"));
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
function stepText(state) {
|
|
1049
|
+
switch (state.status) {
|
|
1050
|
+
case "done":
|
|
1051
|
+
return state.summaryText;
|
|
1052
|
+
case "failed":
|
|
1053
|
+
return state.failReason ? `${state.actionText} \u2014 ${state.failReason}` : state.actionText;
|
|
1054
|
+
case "skipped":
|
|
1055
|
+
return dim(state.actionText);
|
|
1056
|
+
default:
|
|
1057
|
+
return state.actionText;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
function stepDuration(state) {
|
|
1061
|
+
if (state.durationMs === void 0) return "";
|
|
1062
|
+
const secs = state.durationMs / 1e3;
|
|
1063
|
+
return `${secs.toFixed(1)}s`;
|
|
1064
|
+
}
|
|
1065
|
+
function renderStep(state, frameIndex, indent, termWidth) {
|
|
1066
|
+
if (isPlainMode()) {
|
|
1067
|
+
return renderStepPlain(state, indent);
|
|
1068
|
+
}
|
|
1069
|
+
const glyph = stepGlyph(state, frameIndex);
|
|
1070
|
+
const text = stepText(state);
|
|
1071
|
+
const duration = stepDuration(state);
|
|
1072
|
+
const glyphVisible = visibleLength(glyph);
|
|
1073
|
+
const textVisible = visibleLength(text);
|
|
1074
|
+
const durationVisible = visibleLength(duration);
|
|
1075
|
+
const indentLen = indent.length;
|
|
1076
|
+
const usedWidth = indentLen + glyphVisible + 1 + textVisible + durationVisible;
|
|
1077
|
+
const gap = Math.max(1, termWidth - usedWidth);
|
|
1078
|
+
let line;
|
|
1079
|
+
if (duration) {
|
|
1080
|
+
line = `${indent}${glyph} ${text}${" ".repeat(gap)}${dim(duration)}`;
|
|
1081
|
+
} else {
|
|
1082
|
+
line = `${indent}${glyph} ${text}`;
|
|
1083
|
+
}
|
|
1084
|
+
const lines = [line];
|
|
1085
|
+
if (state.subSteps && state.subSteps.length > 0) {
|
|
1086
|
+
const subIndent = indent + " | ";
|
|
1087
|
+
for (const sub of state.subSteps) {
|
|
1088
|
+
lines.push(renderStep(sub, frameIndex, subIndent, termWidth));
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return lines.join("\n");
|
|
1092
|
+
}
|
|
1093
|
+
function renderStepPlain(state, indent) {
|
|
1094
|
+
const text = stepText(state);
|
|
1095
|
+
const duration = stepDuration(state);
|
|
1096
|
+
const durationStr = duration ? ` (${duration})` : "";
|
|
1097
|
+
const line = `${indent}[${state.status}] ${text}${durationStr}`;
|
|
1098
|
+
const lines = [line];
|
|
1099
|
+
if (state.subSteps && state.subSteps.length > 0) {
|
|
1100
|
+
for (const sub of state.subSteps) {
|
|
1101
|
+
lines.push(renderStepPlain(sub, indent + " | "));
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return lines.join("\n");
|
|
1105
|
+
}
|
|
1106
|
+
function renderStepList(steps, frameIndex, termWidth = 80) {
|
|
1107
|
+
const lines = steps.map((step) => renderStep(step, frameIndex, "", termWidth));
|
|
1108
|
+
return lines.join("\n");
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/layout/run-steps.ts
|
|
1112
|
+
function defToState(def) {
|
|
1113
|
+
return {
|
|
1114
|
+
id: def.id,
|
|
1115
|
+
actionText: def.actionText,
|
|
1116
|
+
summaryText: def.summaryText,
|
|
1117
|
+
status: "pending",
|
|
1118
|
+
startedAt: void 0,
|
|
1119
|
+
finishedAt: void 0,
|
|
1120
|
+
durationMs: void 0,
|
|
1121
|
+
failReason: void 0,
|
|
1122
|
+
subSteps: def.subSteps ? def.subSteps.map(defToState) : void 0
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
async function runSteps(defs, opts = {}) {
|
|
1126
|
+
const failFast = opts.failFast ?? (isCI() || !isTTY());
|
|
1127
|
+
const { onStateChange } = opts;
|
|
1128
|
+
const states = defs.map(defToState);
|
|
1129
|
+
let anyFailed = false;
|
|
1130
|
+
const notify = () => {
|
|
1131
|
+
onStateChange?.(states);
|
|
1132
|
+
};
|
|
1133
|
+
for (let i = 0; i < defs.length; i++) {
|
|
1134
|
+
const def = defs[i];
|
|
1135
|
+
const state = states[i];
|
|
1136
|
+
state.status = "running";
|
|
1137
|
+
state.startedAt = Date.now();
|
|
1138
|
+
notify();
|
|
1139
|
+
try {
|
|
1140
|
+
await def.run();
|
|
1141
|
+
state.finishedAt = Date.now();
|
|
1142
|
+
state.durationMs = state.finishedAt - (state.startedAt ?? state.finishedAt);
|
|
1143
|
+
state.status = "done";
|
|
1144
|
+
notify();
|
|
1145
|
+
} catch (err) {
|
|
1146
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
1147
|
+
state.finishedAt = Date.now();
|
|
1148
|
+
state.durationMs = state.finishedAt - (state.startedAt ?? state.finishedAt);
|
|
1149
|
+
state.failReason = reason;
|
|
1150
|
+
anyFailed = true;
|
|
1151
|
+
if (failFast) {
|
|
1152
|
+
state.status = "failed";
|
|
1153
|
+
notify();
|
|
1154
|
+
for (let j = i + 1; j < states.length; j++) {
|
|
1155
|
+
states[j].status = "skipped";
|
|
1156
|
+
}
|
|
1157
|
+
notify();
|
|
1158
|
+
return { success: false, states };
|
|
1159
|
+
} else {
|
|
1160
|
+
state.status = "warning";
|
|
1161
|
+
notify();
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return { success: !anyFailed, states };
|
|
1166
|
+
}
|
|
1167
|
+
|
|
859
1168
|
// src/dashboard/state.ts
|
|
860
1169
|
var AuditPhase = {
|
|
861
1170
|
Connecting: "Connecting",
|
|
@@ -977,6 +1286,10 @@ var AlternateScreenRenderer = class {
|
|
|
977
1286
|
this.entered = false;
|
|
978
1287
|
}
|
|
979
1288
|
}
|
|
1289
|
+
suspend() {
|
|
1290
|
+
}
|
|
1291
|
+
resume() {
|
|
1292
|
+
}
|
|
980
1293
|
renderSummary(result) {
|
|
981
1294
|
const status = result.passed ? colorize("PASSED", "#4ADE80") : colorize("FAILED", "#F87171");
|
|
982
1295
|
const scoreStr = colorize(String(result.overallScore), result.overallScore >= 70 ? "#4ADE80" : "#F87171");
|
|
@@ -998,6 +1311,132 @@ function formatElapsed2(ms) {
|
|
|
998
1311
|
return `${Math.floor(secs / 60)}m ${secs % 60}s`;
|
|
999
1312
|
}
|
|
1000
1313
|
|
|
1314
|
+
// src/layout/composed.ts
|
|
1315
|
+
var ComposedRenderer = class {
|
|
1316
|
+
output;
|
|
1317
|
+
tickTimer = null;
|
|
1318
|
+
frameIndex = 0;
|
|
1319
|
+
suspended = false;
|
|
1320
|
+
resizeTimer = null;
|
|
1321
|
+
lastState = null;
|
|
1322
|
+
entered = false;
|
|
1323
|
+
constructor(output = process.stderr) {
|
|
1324
|
+
this.output = output;
|
|
1325
|
+
process.stderr.on("resize", this.onResize);
|
|
1326
|
+
}
|
|
1327
|
+
update(state) {
|
|
1328
|
+
if (!this.entered) {
|
|
1329
|
+
this.output.write(screen.altEnter + cursor.hide);
|
|
1330
|
+
this.entered = true;
|
|
1331
|
+
}
|
|
1332
|
+
this.lastState = state;
|
|
1333
|
+
const content = this.buildContent(state, this.frameIndex);
|
|
1334
|
+
const capped = this.capContent(content);
|
|
1335
|
+
this.output.write(cursor.home + screen.clear + capped);
|
|
1336
|
+
if (!this.tickTimer && !this.suspended) {
|
|
1337
|
+
this.startTick();
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
finish(result) {
|
|
1341
|
+
this.stopTick();
|
|
1342
|
+
const content = this.buildFinishContent(result);
|
|
1343
|
+
if (this.entered) {
|
|
1344
|
+
this.output.write(cursor.home + screen.clear + content);
|
|
1345
|
+
}
|
|
1346
|
+
if (this.entered) {
|
|
1347
|
+
this.output.write(cursor.show + screen.altExit);
|
|
1348
|
+
this.entered = false;
|
|
1349
|
+
}
|
|
1350
|
+
this.lastState = null;
|
|
1351
|
+
}
|
|
1352
|
+
dispose() {
|
|
1353
|
+
this.stopTick();
|
|
1354
|
+
if (this.resizeTimer !== null) {
|
|
1355
|
+
clearTimeout(this.resizeTimer);
|
|
1356
|
+
this.resizeTimer = null;
|
|
1357
|
+
}
|
|
1358
|
+
process.stderr.removeListener("resize", this.onResize);
|
|
1359
|
+
if (this.entered) {
|
|
1360
|
+
this.output.write(cursor.show + screen.altExit);
|
|
1361
|
+
this.entered = false;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
suspend() {
|
|
1365
|
+
this.suspended = true;
|
|
1366
|
+
this.stopTick();
|
|
1367
|
+
if (this.entered) {
|
|
1368
|
+
this.output.write(cursor.show + screen.altExit);
|
|
1369
|
+
this.entered = false;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
resume() {
|
|
1373
|
+
this.suspended = false;
|
|
1374
|
+
if (this.lastState) {
|
|
1375
|
+
this.output.write(screen.altEnter + cursor.hide);
|
|
1376
|
+
this.entered = true;
|
|
1377
|
+
this.startTick();
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
// ── Private helpers ──────────────────────────────────────────────
|
|
1381
|
+
startTick() {
|
|
1382
|
+
this.tickTimer = setInterval(() => {
|
|
1383
|
+
this.frameIndex++;
|
|
1384
|
+
if (this.lastState && this.entered) {
|
|
1385
|
+
const content = this.buildContent(this.lastState, this.frameIndex);
|
|
1386
|
+
const capped = this.capContent(content);
|
|
1387
|
+
this.output.write(cursor.home + screen.clear + capped);
|
|
1388
|
+
}
|
|
1389
|
+
}, FRAME_INTERVAL);
|
|
1390
|
+
}
|
|
1391
|
+
stopTick() {
|
|
1392
|
+
if (this.tickTimer !== null) {
|
|
1393
|
+
clearInterval(this.tickTimer);
|
|
1394
|
+
this.tickTimer = null;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
onResize = () => {
|
|
1398
|
+
if (this.resizeTimer !== null) {
|
|
1399
|
+
clearTimeout(this.resizeTimer);
|
|
1400
|
+
}
|
|
1401
|
+
this.resizeTimer = setTimeout(() => {
|
|
1402
|
+
this.resizeTimer = null;
|
|
1403
|
+
if (this.lastState && this.entered) {
|
|
1404
|
+
const content = this.buildContent(this.lastState, this.frameIndex);
|
|
1405
|
+
const capped = this.capContent(content);
|
|
1406
|
+
this.output.write(cursor.home + screen.clear + capped);
|
|
1407
|
+
}
|
|
1408
|
+
}, 100);
|
|
1409
|
+
};
|
|
1410
|
+
capContent(content) {
|
|
1411
|
+
const maxLines = Math.max(1, getTerminalHeight() - 2);
|
|
1412
|
+
const lines = content.split("\n");
|
|
1413
|
+
if (lines.length <= maxLines) return content;
|
|
1414
|
+
const overflow = lines.length - (maxLines - 1);
|
|
1415
|
+
const truncated = lines.slice(0, maxLines - 1);
|
|
1416
|
+
truncated.push(dim(`... ${overflow} more lines`));
|
|
1417
|
+
return truncated.join("\n");
|
|
1418
|
+
}
|
|
1419
|
+
buildContent(state, frame) {
|
|
1420
|
+
if (state.stepStates && state.stepStates.length > 0) {
|
|
1421
|
+
return renderStepList(state.stepStates, frame, getTerminalWidth());
|
|
1422
|
+
}
|
|
1423
|
+
const spinner = spinnerFrame(frame);
|
|
1424
|
+
const progress = state.phaseTotal > 0 ? ` (${state.phaseIndex}/${state.phaseTotal})` : "";
|
|
1425
|
+
return `${spinner} ${state.phase}${dim(progress)}`;
|
|
1426
|
+
}
|
|
1427
|
+
buildFinishContent(result) {
|
|
1428
|
+
if (result.passed) {
|
|
1429
|
+
return `${sym("success")} ${bold("Complete")}${dim(" " + formatElapsed3(result.elapsed))}`;
|
|
1430
|
+
}
|
|
1431
|
+
return `${sym("fail")} ${bold("Failed")}${dim(" " + formatElapsed3(result.elapsed))}`;
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
function formatElapsed3(ms) {
|
|
1435
|
+
const secs = Math.round(ms / 1e3);
|
|
1436
|
+
if (secs < 60) return `(${secs}s)`;
|
|
1437
|
+
return `(${Math.floor(secs / 60)}m ${secs % 60}s)`;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1001
1440
|
// src/layout/inline.ts
|
|
1002
1441
|
var InlineRenderer = class {
|
|
1003
1442
|
output;
|
|
@@ -1019,7 +1458,7 @@ var InlineRenderer = class {
|
|
|
1019
1458
|
finish(result) {
|
|
1020
1459
|
const ts = timestamp();
|
|
1021
1460
|
const status = result.passed ? isColorEnabled() ? colorize("PASSED", "#4ADE80") : "PASSED" : isColorEnabled() ? colorize("FAILED", "#F87171") : "FAILED";
|
|
1022
|
-
const elapsed =
|
|
1461
|
+
const elapsed = formatElapsed4(result.elapsed);
|
|
1023
1462
|
this.output.write(
|
|
1024
1463
|
`${dim(ts)} ${bold("Audit Complete")} ${status} score=${result.overallScore} issues=${result.issueCount} ${dim(elapsed)}
|
|
1025
1464
|
`
|
|
@@ -1027,6 +1466,10 @@ var InlineRenderer = class {
|
|
|
1027
1466
|
}
|
|
1028
1467
|
dispose() {
|
|
1029
1468
|
}
|
|
1469
|
+
suspend() {
|
|
1470
|
+
}
|
|
1471
|
+
resume() {
|
|
1472
|
+
}
|
|
1030
1473
|
};
|
|
1031
1474
|
function timestamp() {
|
|
1032
1475
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1035,23 +1478,248 @@ function timestamp() {
|
|
|
1035
1478
|
function pad2(n) {
|
|
1036
1479
|
return n < 10 ? `0${n}` : String(n);
|
|
1037
1480
|
}
|
|
1038
|
-
function
|
|
1481
|
+
function formatElapsed4(ms) {
|
|
1039
1482
|
const secs = Math.round(ms / 1e3);
|
|
1040
1483
|
if (secs < 60) return `(${secs}s)`;
|
|
1041
1484
|
return `(${Math.floor(secs / 60)}m ${secs % 60}s)`;
|
|
1042
1485
|
}
|
|
1043
1486
|
|
|
1044
1487
|
// src/layout/renderer.ts
|
|
1488
|
+
var _rendererOverride = null;
|
|
1489
|
+
function setRendererOverride(renderer) {
|
|
1490
|
+
_rendererOverride = renderer;
|
|
1491
|
+
}
|
|
1045
1492
|
function createRenderer(mode = "auto", output = process.stderr) {
|
|
1493
|
+
if (_rendererOverride) return _rendererOverride;
|
|
1046
1494
|
if (mode === "auto") {
|
|
1047
|
-
mode = isTTY() && !isCI() ? "
|
|
1495
|
+
mode = isTTY() && !isCI() ? "composed" : "inline";
|
|
1048
1496
|
}
|
|
1049
1497
|
if (mode === "alternate") {
|
|
1050
1498
|
return new AlternateScreenRenderer(output);
|
|
1051
1499
|
}
|
|
1500
|
+
if (mode === "composed") {
|
|
1501
|
+
if (!isTTY()) return new InlineRenderer(output);
|
|
1502
|
+
return new ComposedRenderer(output);
|
|
1503
|
+
}
|
|
1052
1504
|
return new InlineRenderer(output);
|
|
1053
1505
|
}
|
|
1506
|
+
|
|
1507
|
+
// src/layout/physicalRows.ts
|
|
1508
|
+
function physicalRows(content, terminalWidth) {
|
|
1509
|
+
if (terminalWidth <= 0) return 0;
|
|
1510
|
+
const lines = content.split("\n");
|
|
1511
|
+
return lines.reduce((total, line) => {
|
|
1512
|
+
const len = visibleLength(line);
|
|
1513
|
+
return total + Math.max(1, Math.ceil(len / terminalWidth));
|
|
1514
|
+
}, 0);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// src/layout/viewport.ts
|
|
1518
|
+
var KEY_CTRL_C = "";
|
|
1519
|
+
var KEY_UP = "\x1B[A";
|
|
1520
|
+
var KEY_DOWN = "\x1B[B";
|
|
1521
|
+
var KEY_PAGE_UP = "\x1B[5~";
|
|
1522
|
+
var KEY_PAGE_DOWN = "\x1B[6~";
|
|
1523
|
+
var KEY_ENTER_CR = "\r";
|
|
1524
|
+
var KEY_ENTER_LF = "\n";
|
|
1525
|
+
var KEY_ESC = "\x1B";
|
|
1526
|
+
var KEY_J = "j";
|
|
1527
|
+
var KEY_K = "k";
|
|
1528
|
+
function parseKey(data) {
|
|
1529
|
+
const str = data.toString("binary");
|
|
1530
|
+
if (str === KEY_CTRL_C) return "quit";
|
|
1531
|
+
if (str === KEY_UP) return "up";
|
|
1532
|
+
if (str === KEY_DOWN) return "down";
|
|
1533
|
+
if (str === KEY_PAGE_UP) return "pageup";
|
|
1534
|
+
if (str === KEY_PAGE_DOWN) return "pagedown";
|
|
1535
|
+
if (str === KEY_ENTER_CR || str === KEY_ENTER_LF) return "enter";
|
|
1536
|
+
if (str === KEY_ESC) return "escape";
|
|
1537
|
+
if (str === KEY_J) return "down";
|
|
1538
|
+
if (str === KEY_K) return "up";
|
|
1539
|
+
return null;
|
|
1540
|
+
}
|
|
1541
|
+
var ScrollingViewport = class {
|
|
1542
|
+
items;
|
|
1543
|
+
maxRows;
|
|
1544
|
+
output;
|
|
1545
|
+
stdin;
|
|
1546
|
+
/** Index of the currently highlighted item (0-indexed) */
|
|
1547
|
+
cursorIdx = 0;
|
|
1548
|
+
/** Index of first visible item */
|
|
1549
|
+
scrollOffset = 0;
|
|
1550
|
+
/** Index of expanded item (-1 = none) */
|
|
1551
|
+
expandedIdx = -1;
|
|
1552
|
+
/** Calculated visible rows (updated on resize) */
|
|
1553
|
+
visibleRows;
|
|
1554
|
+
lastRows = 0;
|
|
1555
|
+
resizeTimer = null;
|
|
1556
|
+
constructor(options) {
|
|
1557
|
+
this.items = options.items;
|
|
1558
|
+
this.maxRows = options.maxRows ?? 10;
|
|
1559
|
+
this.output = options.output ?? process.stderr;
|
|
1560
|
+
this.stdin = options.stdin ?? process.stdin;
|
|
1561
|
+
this.visibleRows = this.calcVisibleRows();
|
|
1562
|
+
}
|
|
1563
|
+
// ── Public entry point ──────────────────────────────────────────────────────
|
|
1564
|
+
/**
|
|
1565
|
+
* Run the viewport interactively.
|
|
1566
|
+
*
|
|
1567
|
+
* Guard: if stdin is not a TTY or setRawMode is unavailable, returns
|
|
1568
|
+
* immediately (non-interactive fallback).
|
|
1569
|
+
*
|
|
1570
|
+
* Resolves when the user presses Ctrl+C.
|
|
1571
|
+
*/
|
|
1572
|
+
async run() {
|
|
1573
|
+
if (!this.stdin.isTTY || typeof this.stdin.setRawMode !== "function") {
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
return new Promise((resolve) => {
|
|
1577
|
+
this.stdin.setRawMode(true);
|
|
1578
|
+
this.stdin.resume();
|
|
1579
|
+
this.output.write(cursor.hide);
|
|
1580
|
+
this.redraw(this.buildFrame());
|
|
1581
|
+
const onResize = () => {
|
|
1582
|
+
if (this.resizeTimer !== null) clearTimeout(this.resizeTimer);
|
|
1583
|
+
this.resizeTimer = setTimeout(() => {
|
|
1584
|
+
this.resizeTimer = null;
|
|
1585
|
+
this.visibleRows = this.calcVisibleRows();
|
|
1586
|
+
this.clampScrollOffset();
|
|
1587
|
+
this.lastRows = 0;
|
|
1588
|
+
this.redraw(this.buildFrame());
|
|
1589
|
+
}, 100);
|
|
1590
|
+
};
|
|
1591
|
+
const onData = (data) => {
|
|
1592
|
+
const action = parseKey(data);
|
|
1593
|
+
if (action === "quit") {
|
|
1594
|
+
cleanup();
|
|
1595
|
+
resolve();
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
this.handleAction(action);
|
|
1599
|
+
this.redraw(this.buildFrame());
|
|
1600
|
+
};
|
|
1601
|
+
const cleanup = () => {
|
|
1602
|
+
this.stdin.removeListener("data", onData);
|
|
1603
|
+
process.stderr.removeListener("resize", onResize);
|
|
1604
|
+
if (this.resizeTimer !== null) {
|
|
1605
|
+
clearTimeout(this.resizeTimer);
|
|
1606
|
+
this.resizeTimer = null;
|
|
1607
|
+
}
|
|
1608
|
+
try {
|
|
1609
|
+
this.stdin.setRawMode(false);
|
|
1610
|
+
} catch {
|
|
1611
|
+
}
|
|
1612
|
+
this.stdin.pause();
|
|
1613
|
+
this.output.write(cursor.show);
|
|
1614
|
+
};
|
|
1615
|
+
this.stdin.on("data", onData);
|
|
1616
|
+
process.stderr.on("resize", onResize);
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
1620
|
+
calcVisibleRows() {
|
|
1621
|
+
return Math.min(this.maxRows, getTerminalHeight() - 4);
|
|
1622
|
+
}
|
|
1623
|
+
clampScrollOffset() {
|
|
1624
|
+
const maxOffset = Math.max(0, this.items.length - this.visibleRows);
|
|
1625
|
+
this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxOffset));
|
|
1626
|
+
}
|
|
1627
|
+
handleAction(action) {
|
|
1628
|
+
const last = this.items.length - 1;
|
|
1629
|
+
switch (action) {
|
|
1630
|
+
case "up":
|
|
1631
|
+
this.cursorIdx = Math.max(0, this.cursorIdx - 1);
|
|
1632
|
+
break;
|
|
1633
|
+
case "down":
|
|
1634
|
+
this.cursorIdx = Math.min(last, this.cursorIdx + 1);
|
|
1635
|
+
break;
|
|
1636
|
+
case "pageup":
|
|
1637
|
+
this.cursorIdx = Math.max(0, this.cursorIdx - this.visibleRows);
|
|
1638
|
+
break;
|
|
1639
|
+
case "pagedown":
|
|
1640
|
+
this.cursorIdx = Math.min(last, this.cursorIdx + this.visibleRows);
|
|
1641
|
+
break;
|
|
1642
|
+
case "enter":
|
|
1643
|
+
this.expandedIdx = this.expandedIdx === this.cursorIdx ? -1 : this.cursorIdx;
|
|
1644
|
+
break;
|
|
1645
|
+
case "escape":
|
|
1646
|
+
this.expandedIdx = -1;
|
|
1647
|
+
break;
|
|
1648
|
+
}
|
|
1649
|
+
if (this.cursorIdx < this.scrollOffset) {
|
|
1650
|
+
this.scrollOffset = this.cursorIdx;
|
|
1651
|
+
}
|
|
1652
|
+
if (this.cursorIdx >= this.scrollOffset + this.visibleRows) {
|
|
1653
|
+
this.scrollOffset = this.cursorIdx - this.visibleRows + 1;
|
|
1654
|
+
}
|
|
1655
|
+
this.clampScrollOffset();
|
|
1656
|
+
}
|
|
1657
|
+
buildFrame() {
|
|
1658
|
+
const width = getTerminalWidth();
|
|
1659
|
+
const lines = [];
|
|
1660
|
+
const plain = isPlainMode();
|
|
1661
|
+
const colored = isColorEnabled();
|
|
1662
|
+
if (this.scrollOffset > 0) {
|
|
1663
|
+
const count = this.scrollOffset;
|
|
1664
|
+
const arrow = plain ? "^" : "\u25B2";
|
|
1665
|
+
lines.push(dim(` ${arrow} ${count} more`));
|
|
1666
|
+
}
|
|
1667
|
+
const end = Math.min(this.scrollOffset + this.visibleRows, this.items.length);
|
|
1668
|
+
for (let i = this.scrollOffset; i < end; i++) {
|
|
1669
|
+
const item = this.items[i];
|
|
1670
|
+
const isHighlighted = i === this.cursorIdx;
|
|
1671
|
+
const isExpanded = i === this.expandedIdx;
|
|
1672
|
+
const badge = severityColor(item.severity);
|
|
1673
|
+
const badgeVisibleWidth = item.severity.toUpperCase().length;
|
|
1674
|
+
const titleMaxWidth = Math.max(10, width - badgeVisibleWidth - 18);
|
|
1675
|
+
const title = truncate(item.title, titleMaxWidth);
|
|
1676
|
+
const effortTag = dim(`[${item.effort}]`);
|
|
1677
|
+
let row = ` ${badge} ${title} ${effortTag}`;
|
|
1678
|
+
if (isHighlighted) {
|
|
1679
|
+
if (colored && !plain) {
|
|
1680
|
+
row = bgColor(row, brand.teal);
|
|
1681
|
+
} else {
|
|
1682
|
+
row = `\x1B[7m${row}\x1B[0m`;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
lines.push(row);
|
|
1686
|
+
if (isExpanded && item.detail) {
|
|
1687
|
+
const detailLines = item.detail.split("\n");
|
|
1688
|
+
for (const dl of detailLines) {
|
|
1689
|
+
lines.push(` ${dim(truncate(dl, width - 6))}`);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
if (this.scrollOffset + this.visibleRows < this.items.length) {
|
|
1694
|
+
const count = this.items.length - (this.scrollOffset + this.visibleRows);
|
|
1695
|
+
const arrow = plain ? "v" : "\u25BC";
|
|
1696
|
+
lines.push(dim(` ${arrow} ${count} more`));
|
|
1697
|
+
}
|
|
1698
|
+
return lines.join("\n");
|
|
1699
|
+
}
|
|
1700
|
+
redraw(content) {
|
|
1701
|
+
const rows = this.lastRows;
|
|
1702
|
+
let seq = rows > 0 ? cursor.up(rows) + screen.clearDown : "";
|
|
1703
|
+
seq += content;
|
|
1704
|
+
this.output.write(seq);
|
|
1705
|
+
this.lastRows = physicalRows(content, getTerminalWidth());
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
var _isOverrideActive = false;
|
|
1709
|
+
function setKeyboardOverrideActive(active) {
|
|
1710
|
+
_isOverrideActive = active;
|
|
1711
|
+
}
|
|
1054
1712
|
function createKeyboardHandler(stdin = process.stdin) {
|
|
1713
|
+
if (_isOverrideActive) {
|
|
1714
|
+
return {
|
|
1715
|
+
start() {
|
|
1716
|
+
},
|
|
1717
|
+
dispose() {
|
|
1718
|
+
},
|
|
1719
|
+
on() {
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1055
1723
|
const emitter = new EventEmitter();
|
|
1056
1724
|
let started = false;
|
|
1057
1725
|
let wasRawMode = false;
|
|
@@ -1095,6 +1763,6 @@ function createKeyboardHandler(stdin = process.stdin) {
|
|
|
1095
1763
|
};
|
|
1096
1764
|
}
|
|
1097
1765
|
|
|
1098
|
-
export { AlternateScreenRenderer, AuditPhase, InlineRenderer, PHASE_ORDER, applyGradient, bold, boldColor, borders, box, brand, center, colorize, createKeyboardHandler, createMultiProgress, createProgressBar, createRenderer, createSpinner, cursor, dim, getTerminalHeight, getTerminalWidth, gradient, isCI, isColorEnabled, isStdinTTY, isStdoutTTY, isTTY, padEnd, padStart, parseDiff, phaseIndex, phaseTotal, renderDiff, renderFrame, renderGroupedList, renderList, renderTable, renderTree, scoreColor, screen, setColorEnabled, severity, severityLabels, severityOrder, shouldUseColor, stripAnsi, style, supportsUnicode, text_exports as text, tokens, truncate, visibleLength };
|
|
1766
|
+
export { AlternateScreenRenderer, AuditPhase, BRAILLE_FRAMES, ComposedRenderer, FRAME_INTERVAL, InlineRenderer, PHASE_ORDER, ScrollingViewport, applyGradient, bgColor, bold, boldColor, borders, box, brand, center, colorize, createKeyboardHandler, createMultiProgress, createProgressBar, createRenderer, createSpinner, cursor, detectSymbolTier, dim, easeIn, easeInOut, easeOut, getTerminalHeight, getTerminalWidth, gradient, isCI, isColorEnabled, isPlainMode, isStdinTTY, isStdoutTTY, isTTY, lerp, linear, padEnd, padStart, parseDiff, phaseIndex, phaseTotal, physicalRows, renderDiff, renderError, renderFrame, renderGroupedList, renderList, renderStepList, renderTable, renderTree, renderWarning, runSteps, scoreColor, screen, setColorEnabled, setKeyboardOverrideActive, setPlainMode, setRendererOverride, setSymbolTier, severity, severityColor, severityLabels, severityOrder, shouldUseColor, spinnerFrame, stripAnsi, style, supportsUnicode, sym, text_exports as text, toPlainBox, tokens, truncate, visibleLength };
|
|
1099
1767
|
//# sourceMappingURL=index.js.map
|
|
1100
1768
|
//# sourceMappingURL=index.js.map
|