diff --git a/VERSION b/VERSION index faa640e..850e742 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.13.13 +1.14.0 diff --git a/VERSIONS.md b/VERSIONS.md index 1d53cdd..b1e03e0 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre | Tag | Date (UTC) | Notes | |-----|------------|--------| +| **v1.14.0** | 2026-07-19 | **Feature:** SUMMARY box rows are **colour-distinct** (per-severity badge + tinted background + bold counts; verdict-coloured header); HTML mon pages style `sum-ok` / `sum-warn` / `sum-err` / … panels the same way. | | **v1.13.13** | 2026-07-19 | **Bugfix:** progress estimate for **devtesting** / fake-franken is 8 (happy-path numbered checks), not 10 — avoids mid-run 42/48 then end snap 46/46. | | **v1.13.12** | 2026-07-19 | **Bugfix:** SUMMARY chrome (`[ WARN ] 2`, `warnings only`, OK/ERROR counts without `#NNN`) is **meta**, not warn/error — sticky counts + warn filter no longer double SUMMARY rows; filter context skips blank lines. | | **v1.13.11** | 2026-07-19 | **Bugfix:** sticky error/warn filter keeps **±3 dimmed context lines** around each match (gray/grayscale) so phase/group context stays readable; dashed gap between distant clusters. | diff --git a/lib.sh b/lib.sh index 560216c..358e6a6 100755 --- a/lib.sh +++ b/lib.sh @@ -894,56 +894,94 @@ section() { } # Print SUMMARY totals box for given counts (phase-local or global). +# Each severity row is colour-distinct: badge + full-line bg tint + bold count (v1.14.0). # $1=pass $2=fail $3=warn $4=info $5=block _summary_totals_box() { local pass_n="$1" fail_n="$2" warn_n="$3" info_n="$4" blk_n="$5" - if [ "${BOX:-0}" = "1" ]; then - printf -- '\n%s┌ %s ┐%s\n' "$BG_SEC" "$(i18n_tag SUMMARY)" "$N" - _sum_badge() { # $1=bg $2=tag $3=fg $4=n - local _tg - _tg=$(i18n_tag "$2") - printf -- ' %s┌ %-5s┐%s %s%4d%s\n' "$1" "$_tg" "$N" "$3" "$4" "$N" - } - _sum_badge "$BG_OK" "OK" "$G" "$pass_n" - [ "$fail_n" -gt 0 ] && _sum_badge "$BG_ERR" "ERROR" "$R" "$fail_n" - [ "$warn_n" -gt 0 ] && _sum_badge "$BG_WARN" "WARN" "$Y" "$warn_n" - [ "$info_n" -gt 0 ] && _sum_badge "$BG_INFO" "INFO" "$C" "$info_n" - [ "$blk_n" -gt 0 ] && _sum_badge "$BG_BLK" "BLOCK" "$M" "$blk_n" + local hdr_bg hdr_fg _sum_lbl + _sum_lbl=$(i18n_tag SUMMARY) + # Header colour follows overall verdict + if [ "$fail_n" -gt 0 ] || [ "$blk_n" -gt 0 ]; then + hdr_bg="${BG_ERR}" + hdr_fg="${R}" + elif [ "$warn_n" -gt 0 ]; then + hdr_bg="${BG_WARN}" + hdr_fg="${Y}" else - printf -- '\n[ %s ]\n' "$(i18n_tag SUMMARY)" - printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag OK)" "$G" "$pass_n" "$N" - [ "$fail_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag ERROR)" "$R" "$fail_n" "$N" - [ "$warn_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag WARN)" "$Y" "$warn_n" "$N" - [ "$info_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag INFO)" "$C" "$info_n" "$N" - [ "$blk_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag BLOCK)" "$M" "$blk_n" "$N" + hdr_bg="${BG_OK}" + hdr_fg="${G}" fi - # one-line rollup (bold label, severity-coloured counts) - printf -- ' %stotals:%s %s%d OK%s' "$B" "$N" "$G" "$pass_n" "$N" - [ "$fail_n" -gt 0 ] && printf -- ' · %s%d ERROR%s' "$R" "$fail_n" "$N" - [ "$warn_n" -gt 0 ] && printf -- ' · %s%d WARN%s' "$Y" "$warn_n" "$N" - [ "$info_n" -gt 0 ] && printf -- ' · %s%d INFO%s' "$C" "$info_n" "$N" - [ "$blk_n" -gt 0 ] && printf -- ' · %s%d BLOCKER%s' "$M" "$blk_n" "$N" - printf '\n' - # overall verdict + + if [ "${BOX:-0}" = "1" ]; then + # Dim full-line tints (bold fg on soft bg) — distinct per severity + local ROW_OK=$'\e[1;32;48;5;22m' # bold green on dark green + local ROW_ERR=$'\e[1;97;48;5;52m' # bold white on dark red + local ROW_WARN=$'\e[1;30;48;5;178m' # bold black on gold + local ROW_INFO=$'\e[1;97;48;5;24m' # bold white on dark blue + local ROW_BLK=$'\e[1;97;48;5;53m' # bold white on dark magenta + local ROW_TOT=$'\e[1;37;48;5;236m' # bold white on dark gray + + printf -- '\n%s╔══════════════════════════════════════╗%s\n' "$hdr_bg" "$N" + printf -- '%s║ %-34s ║%s\n' "$hdr_bg" "$_sum_lbl" "$N" + printf -- '%s╚══════════════════════════════════════╝%s\n' "$hdr_bg" "$N" + + # $1=row_bg $2=badge_bg $3=tag $4=n $5=label_fg — full-width-ish row + _sum_row() { + local row_bg="$1" badge="$2" tag="$3" n="$4" fg="$5" _tg pad + _tg=$(i18n_tag "$tag") + pad=$(printf '%-5s' "$_tg") + printf -- ' %s┌ %s┐%s %s %s%6d%s %s%-12s%s\n' \ + "$badge" "$pad" "$N" \ + "$row_bg" "$B" "$n" "$N" \ + "$fg$B" "$_tg" "$N" + } + _sum_row "$ROW_OK" "$BG_OK" "OK" "$pass_n" "$G" + [ "$fail_n" -gt 0 ] && _sum_row "$ROW_ERR" "$BG_ERR" "ERROR" "$fail_n" "$R" + [ "$warn_n" -gt 0 ] && _sum_row "$ROW_WARN" "$BG_WARN" "WARN" "$warn_n" "$Y" + [ "$info_n" -gt 0 ] && _sum_row "$ROW_INFO" "$BG_INFO" "INFO" "$info_n" "$C" + [ "$blk_n" -gt 0 ] && _sum_row "$ROW_BLK" "$BG_BLK" "BLOCK" "$blk_n" "$M" + + # totals rollup on tinted bar + printf -- ' %s %s totals: %s%d OK%s' "$ROW_TOT" "$B" "$G$B" "$pass_n" "$N$ROW_TOT" + [ "$fail_n" -gt 0 ] && printf -- ' %s·%s %s%d ERROR%s' "$D" "$N$ROW_TOT" "$R$B" "$fail_n" "$N$ROW_TOT" + [ "$warn_n" -gt 0 ] && printf -- ' %s·%s %s%d WARN%s' "$D" "$N$ROW_TOT" "$Y$B" "$warn_n" "$N$ROW_TOT" + [ "$info_n" -gt 0 ] && printf -- ' %s·%s %s%d INFO%s' "$D" "$N$ROW_TOT" "$C$B" "$info_n" "$N$ROW_TOT" + [ "$blk_n" -gt 0 ] && printf -- ' %s·%s %s%d BLOCKER%s' "$D" "$N$ROW_TOT" "$M$B" "$blk_n" "$N$ROW_TOT" + printf -- ' %s\n' "$N" + else + printf -- '\n[ %s ]\n' "$_sum_lbl" + printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag OK)" "$G$B" "$pass_n" "$N" + [ "$fail_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag ERROR)" "$R$B" "$fail_n" "$N" + [ "$warn_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag WARN)" "$Y$B" "$warn_n" "$N" + [ "$info_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag INFO)" "$C$B" "$info_n" "$N" + [ "$blk_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag BLOCK)" "$M$B" "$blk_n" "$N" + printf -- ' %stotals:%s %s%d OK%s' "$B" "$N" "$G$B" "$pass_n" "$N" + [ "$fail_n" -gt 0 ] && printf -- ' · %s%d ERROR%s' "$R$B" "$fail_n" "$N" + [ "$warn_n" -gt 0 ] && printf -- ' · %s%d WARN%s' "$Y$B" "$warn_n" "$N" + [ "$info_n" -gt 0 ] && printf -- ' · %s%d INFO%s' "$C$B" "$info_n" "$N" + [ "$blk_n" -gt 0 ] && printf -- ' · %s%d BLOCKER%s' "$M$B" "$blk_n" "$N" + printf '\n' + fi + # overall verdict — bold label, filled badge if [ "$fail_n" -eq 0 ] && [ "$blk_n" -eq 0 ] && [ "$warn_n" -eq 0 ]; then if [ "${BOX:-0}" = "1" ]; then - printf -- ' %s┌ OK ┐%s %sall clear%s\n' "$BG_OK" "$N" "$G" "$N" + printf -- ' %s┌ OK ┐%s %s%sall clear%s\n' "$BG_OK" "$N" "$G" "$B" "$N" else - printf -- ' %s[ OK ] all clear%s\n' "$G" "$N" + printf -- ' %s[ OK ] %sall clear%s\n' "$G" "$B" "$N" fi elif [ "$fail_n" -eq 0 ] && [ "$blk_n" -eq 0 ]; then if [ "${BOX:-0}" = "1" ]; then - printf -- ' %s┌ WARN ┐%s %swarnings only (no hard fail)%s\n' "$BG_WARN" "$N" "$Y" "$N" + printf -- ' %s┌ WARN ┐%s %s%swarnings only (no hard fail)%s\n' "$BG_WARN" "$N" "$Y" "$B" "$N" else - printf -- ' %s[ WARN ] warnings only (no hard fail)%s\n' "$Y" "$N" + printf -- ' %s[ WARN ] %swarnings only (no hard fail)%s\n' "$Y" "$B" "$N" fi else local _fail_msg _fail_msg=$(i18n_text 'failed — see list above') if [ "${BOX:-0}" = "1" ]; then - printf -- ' %s┌ ERROR ┐%s %s%s%s\n' "$BG_ERR" "$N" "$R" "$_fail_msg" "$N" + printf -- ' %s┌ ERROR ┐%s %s%s%s%s\n' "$BG_ERR" "$N" "$R" "$B" "$_fail_msg" "$N" else - printf -- ' %s[ ERROR ] %s%s\n' "$R" "$_fail_msg" "$N" + printf -- ' %s[ ERROR ] %s%s%s\n' "$R" "$B" "$_fail_msg" "$N" fi fi } diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index 0cccb98..6633f87 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -278,13 +278,31 @@ def classify(line: str) -> str: u = line.upper() low = line.lower() # section / summary headers before badge matching (they contain the word ERROR) - if "SUMMARY" in u or "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u: + if re.search(r"[╔═║╚]|SUMMARY", u) and ( + "SUMMARY" in u or "═══" in line or "╔" in line or "╚" in line + ): + if "SUMMARY" in u or ("╔" in line and "═" in line) or ("╚" in line and "═" in line): + if "SUMMARY" in u or (not is_numbered_check_line(line) and ("╔" in line or "╚" in line or "║" in line)): + if "SUMMARY" in u or re.match(r"^\s*[╔╚║]", line): + if "SUMMARY" in u: + return "sum-header" + if re.match(r"^\s*[╔╚]", line) and "═" in line: + return "sum-header" + if re.match(r"^\s*║", line) and not is_numbered_check_line(line): + return "sum-header" + if "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u: return "meta" - if "numbered checks" in low or "totals:" in low: - return "meta" - # SUMMARY verdict chrome (not a check) - if "warnings only" in low or "all clear" in low or "failed — see" in low or "failed - see" in low: + if "numbered checks" in low: return "meta" + if "totals:" in low: + return "sum-totals" + # SUMMARY verdict chrome (not a check) — keep distinct for HTML boxes + if "warnings only" in low: + return "sum-verdict-warn" + if "all clear" in low: + return "sum-verdict-ok" + if "failed — see" in low or "failed - see" in low: + return "sum-verdict-err" # host-agent tees converter "wrote … (errors=N …)" into the same log if line.lstrip().lower().startswith("wrote ") and "errors=" in low: return "meta" @@ -296,30 +314,32 @@ def classify(line: str) -> str: if not is_numbered_check_line(line) and re.search( r"[\[┌]\s*BLOCK(?:ER)?\s*[\]┐]", u ): - return "meta" + return "sum-block" return "blocker" # Only real check badges (not free-text "ERROR" inside commit messages, # and not SUMMARY count rows like " [ ERROR ] 3") if re.search(r"┌\s*ERROR\b|\[\s*ERROR\b", u): if not is_numbered_check_line(line): - return "meta" + return "sum-err" return "error" if re.search(r"\bERROR monpages\b", line, re.I): return "error" if re.search(r"┌\s*WARN\b|\[\s*WARN\b", u): if not is_numbered_check_line(line): - return "meta" + return "sum-warn" return "warn" if re.search(r"┌\s*INFO\b|\[\s*INFO\b", u): if not is_numbered_check_line(line): - return "meta" + return "sum-info" return "info" if re.search(r"┌\s*OK\b|\[\s*OK\b", u) or ( (" OK" in u or u.strip().startswith("OK")) and is_numbered_check_line(line) ): if re.search(r"┌\s*OK\b|\[\s*OK\b", u) and not is_numbered_check_line(line): - return "meta" + return "sum-ok" return "ok" + if re.search(r"[\[┌]\s*BLOCK\b", u) and not is_numbered_check_line(line): + return "sum-block" if u.strip().startswith("-- ") or u.strip().startswith("=="): return "section" return "plain" @@ -1866,6 +1886,57 @@ main {{ padding: 12px 14px 48px; max-width: 1200px; }} .line.section {{ color: var(--sec); margin-top: 8px; font-weight: 600; }} .line.meta {{ color: var(--dim); }} .line.plain {{ color: var(--fg); }} +/* v1.14.0: SUMMARY box rows — distinct bg + bold per severity */ +.line.sum-header {{ + color: #fff; font-weight: 800; letter-spacing: 0.04em; + background: linear-gradient(90deg, #1a3a1a 0%, #0a1a0a 100%); + border-left: 4px solid var(--ok); padding: 4px 8px; margin-top: 10px; +}} +.line.sum-ok {{ + color: #b8f0b8; font-weight: 700; + background: #0d1f0d; border-left: 4px solid var(--ok); + padding: 3px 8px; margin: 2px 0; +}} +.line.sum-err {{ + color: #ffc9c9; font-weight: 700; + background: #2a0a0a; border-left: 4px solid var(--err); + padding: 3px 8px; margin: 2px 0; +}} +.line.sum-warn {{ + color: #1a1400; font-weight: 800; + background: #c9a227; border-left: 4px solid #8a7010; + padding: 3px 8px; margin: 2px 0; +}} +.line.sum-info {{ + color: #c8e7ff; font-weight: 700; + background: #0a1520; border-left: 4px solid var(--info); + padding: 3px 8px; margin: 2px 0; +}} +.line.sum-block {{ + color: #f5d0ff; font-weight: 700; + background: #1a0a1a; border-left: 4px solid var(--blocker); + padding: 3px 8px; margin: 2px 0; +}} +.line.sum-totals {{ + color: #eee; font-weight: 700; + background: #1a1a1a; border-left: 4px solid #666; + padding: 4px 8px; margin: 4px 0 2px; +}} +.line.sum-verdict-ok {{ + color: #b8f0b8; font-weight: 800; + background: #0d1f0d; border: 1px solid #2a5a2a; + padding: 4px 8px; margin: 4px 0 8px; +}} +.line.sum-verdict-warn {{ + color: #1a1400; font-weight: 800; + background: #c9a227; border: 1px solid #8a7010; + padding: 4px 8px; margin: 4px 0 8px; +}} +.line.sum-verdict-err {{ + color: #ffc9c9; font-weight: 800; + background: #2a0a0a; border: 1px solid #622; + padding: 4px 8px; margin: 4px 0 8px; +}} a.jump {{ color: inherit; text-decoration: underline dotted; }} footer {{ margin-top: 18px; color: var(--dim); font-size: 12px;