class

Hwaro::Logger

Inherits Reference / Object

Constants

GLYPHS = {:ok => {"✓", "[ok]", Role::Success}, :warn => {"⚠", "[warn]", Role::Warn}, :err => {"✗", "[err]", Role::Error}, :info => {"ℹ", "[info]", Role::Dim}, :result => {"✦", "*", Role::Accent}, :prompt => {"◇", ">", Role::Accent}, :watch => {"↻", "~", Role::Accent}, :bullet => {"·", "-", Role::Dim}, :arrow => {"→", "->", Role::Dim}, :tree_mid => {"├─", "|-", Role::Dim}, :tree_last => {"└─", "`-", Role::Dim}}

Glyph registry: {unicode, ascii-fallback, role}. The ASCII fallback is used whenever color/unicode is disabled — the same gate the rest of the CLI uses — so plain output never emits a stray multibyte glyph.

Class methods

action(label : String | Symbol, message : String, role : Role = Role::Success)

Cargo-style verbose action line: a 12-column right-justified label and a message. Callers name a semantic Role (never a raw color) so the label picks up the truecolor tier and theme awareness like everything else. The plain form (" create path") is unchanged.

Source
bar(value : Number, max : Number, width : Int32 = 20) : String

A static proportion bar for report bodies (stats charts). Accent fill on a dim track when color is on; a plain "#" run when color is off, keeping piped output free of multibyte glyphs. Distinct from progress, which is the animated \r bar for long-running operations and is frozen.

Source
color256?

True when the terminal advertises at least 256 colors (and color is otherwise enabled) but not truecolor — the common case for macOS Terminal.app, which never sets COLORTERM. Without this tier those terminals would fall all the way down to the raw 16-color ANSI names, which is where the palette used to look dated.

Source
color_enabled=(value : Bool | Nil)

Explicit override. Pass nil to restore auto-detection.

Source
color_enabled?

Auto-detect unless explicitly set. Disabled when NO_COLOR env var is set to any non-empty value, or when STDOUT is not a TTY.

Source
dark?

Background brightness for the ember accent. Not auto-detected (terminals don't report it reliably); default to the dark-bg ember and let users override with HWARO_THEME=light.

Source
debug(message : String)
Source
dur(ms : Float64) : String

Humanized duration: ">= 1s" renders as seconds with two decimals ("1.18s"), below a second as whole milliseconds ("842ms"). Replaces the scattered .round(2)}ms so timings read consistently everywhere.

Source
err_io
Source
err_io=(io : IO)
Source
error(message : String)

TTY form leads with the crimson ✗ glyph so errors scan apart from the message body; plain form stays the bare message (no escapes, no glyph) for pipes / CI.

Source
glyph(key : Symbol) : String

Resolve a glyph by key: colorized unicode when color is on, else the plain ASCII fallback.

Source
heading(kind : String, title : String | Nil = nil) : Nil

Print a command heading followed by a blank line — the breathing room the flat layout leans on. No-ops in quiet; degrades to a single "hwaro: kind title" line when color is off (no blank line; middots flattened like the other plain forms).

Source
heading_str(kind : String, title : String | Nil = nil) : String

TTY form of a command heading: "hwaro build title" at column 0 — the ember-bold wordmark, the bold command word, and an optional dim title. No glyph and no trailing rule: the flat layout structures output with whitespace and alignment alone. Used by heading and by Receipt.

Source
info(message : String)
Source
io=(io : IO)

Setting io also redirects error/warn output to the same IO, which keeps existing test helpers (that capture a single IO) working and makes manual redirection straightforward. Use err_io= afterwards to split streams explicitly.

Source
item(message : String, glyph glyph_key : Symbol = :bullet, indent : Int32 = 2) : Nil

A single body line inside a command's report: a glyph and a message on the 2-space grid (4 spaces for continuation detail under an item). The glyph names the item's severity (:ok/:warn/:err/:info) or shape (:bullet for neutral lists, :arrow for from→to detail). This is the one way findings render, so doctor / validate / check-links agree.

Source
level
Source
level=(level : Level)
Source
outcome(verb : String, value : String, glyph : Symbol = :result, ms : Float64 | Nil = nil) : Nil

Print a standalone outcome line — the one warm ember beat a command ends on (✦ created path). The glyph signals severity (:result spark, :warn/:err for problems) while the verb is always ember.

Source
outcome_str(verb : String, value : String, glyph : Symbol, ms : Float64 | Nil, plain : Bool) : String

Build the single outcome line: "✦ verb value · dur" at column 0. Plain form is "verb: value[ in dur]" with the middot separators flattened to commas.

Source
paint(text : String, role : Role, bold : Bool = false) : String

Paint text in a semantic role. Returns raw text (no escapes) when color is disabled, so scripts / CI / pipes stay clean. Prefers truecolor, then the 256-color approximation, then the 16-color name, then plain.

Source
progress(current : Int32, total : Int32, prefix : String = "")

Progress indicator for long operations. In TTY mode: animated \r-overwriting bar. In non-TTY mode (pipes, CI, agent capture, redirected files): suppress the per-step animation — \r doesn't return to column 0 there, so every step concatenates into one giant smeared line. Emit only a final &quot;<prefix>done (current/total)&quot; line so logs stay readable.

Source
quiet=(value : Bool)
Source
quiet?
Source
section(label : String, note : String | Nil = nil) : Nil

A dim lowercase label that groups the items below it, with an optional · note suffix (tags · top 15). Plain form is &quot;label:&quot; / &quot;label: note&quot; so piped output stays grep-friendly.

Source
status_finish

Stop and tear down the active status region. Idempotent.

Source
status_phase(label : String) : Nil

Update the active status label (e.g. &quot;render&quot;). No-op when inactive.

Source
status_start(verbose : Bool = false) : Nil

Begin a live status region for a unit of work. No-ops (and spawns no fiber) unless output is an interactive, colored, non-quiet TTY. verbose disables it too, since verbose mode streams its own per-file lines that would fight the spinner.

Source
success(message : String)
Source
timed(message : String, &)

Performance timing helper

Source
truecolor?

True only when the terminal advertises 24-bit color and color is otherwise enabled. Gates the truecolor tier; everything degrades to the 16-color named fallback below it, then to raw text.

Source
warn(message : String)

TTY form leads with the amber ⚠ glyph; plain form keeps the historical &quot;[WARN] &quot; prefix so scripts that grep for it keep working.

Source

Nested types