Console IO & prompts
All Kona terminal CLIs share one Termwind-inspired console style: brand colors (Mocha #6F4E37 / deep espresso #3D2914), success/info/warn/error markers, boxes, two-column lists, tables, and progress bars.
| API | Module | Role |
|---|---|---|
org.konaframework.support.console.ConsoleIO |
kona-support |
Canonical implementation |
org.konaframework.grind.GrindIO |
kona-grind |
Wraps ConsoleIO with quiet / verbose filtering |
Helpers on ConsoleCommand |
kona-grind |
info, success, warn, error, table, progress, … |
org.konaframework.grind.Prompts |
kona-grind |
Interactive ask / confirm / choice |
Do not print user-facing output with raw println / unstyled System.out in commands; use these APIs.
Color environment
Section titled “Color environment”ConsoleIO.detectColor (also used by GrindIO.detectColor):
| Env | Effect |
|---|---|
NO_COLOR |
Disable ANSI (any value present) |
FORCE_COLOR=1 (any non-0) |
Force ANSI even when TERM=dumb |
FORCE_COLOR=0 |
Keep color off |
TERM=dumb or missing TERM |
Color off unless forced |
Verbosity (GrindIO)
Section titled “Verbosity (GrindIO)”enum class Verbosity { QUIET, NORMAL, VERBOSE }GrindIO.fromOptions(options) sets verbosity from CLI flags:
| Flags | Verbosity |
|---|---|
--quiet / -q |
QUIET |
--verbose / -v |
VERBOSE |
| neither | NORMAL |
Quiet wins if both quiet and verbose keys appear (checked first).
| Method | Quiet | Normal | Verbose |
|---|---|---|---|
writeln / write / line / info / success / warn / title / subtitle / twoColumn / box / progress / table |
suppressed | prints | prints |
error |
always prints (stderr) | prints | prints |
verbose |
suppressed | suppressed | prints (dim) |
ConsoleIO surface
Section titled “ConsoleIO surface”Construct with optional PrintStream out/err and a color boolean:
val console = ConsoleIO()console.info("Working…")console.success("Done")console.warn("Slow path")console.error("Could not connect")console.title("Report")console.subtitle("Section")console.twoColumn("serve", "Run the HTTP server")console.box("grind", listOf("Kona app CLI"))console.progress(3, 10, "users")console.table( listOf("id", "email"), listOf(listOf("1", "ada@example.com"), listOf("2", "bea@example.com")),)| Method | Behavior |
|---|---|
writeln / write / line |
Raw stdout (still subject to GrindIO quiet when wrapped) |
info |
Cyan ℹ marker + message |
success |
Green ✓ |
warn |
Yellow ! |
error |
Red ✗ on stderr |
title |
Bold primary heading + dim underline (max 48) |
subtitle |
Accent-colored line |
twoColumn(left, right, width=22) |
Primary bold left column + dim right |
box(title, lines) |
Framed block; content width clamped roughly 24–56 |
progress(current, total, label="") |
28-cell bar + percent; total must be > 0; current clamped to [0, total] |
table(headers, rows) |
Aligned columns by plain text width (ANSI stripped); headers non-empty; each row must match header width |
paint(codes, text) |
Apply ANSI when color is on |
plainLength(text) |
Length with ANSI sequences removed |
Public ANSI constants on ConsoleIO: RESET, BOLD, DIM, RED, GREEN, YELLOW, CYAN, PRIMARY, ACCENT.
GrindIO surface
Section titled “GrindIO surface”Same high-level helpers as above, plus:
val io = GrindIO.fromOptions(mapOf("verbose" to "true"))io.verbose("only with -v")io.subtitle("Detail")io.twoColumn("left", "right")io.box("Title", listOf("line"))Inside a ConsoleCommand, prefer the bound helpers (they use the runner’s GrindIO):
info("Working…")success("Done")warn("Slow path")error("Could not connect")title("Report")line()line("plain")table( listOf("id", "email"), listOf(listOf("1", "ada@example.com"), listOf("2", "bea@example.com")),)progress(3, 10)progress(3, 10, "users")verbose("only with -v")ConsoleCommand.progress has overloads with and without a label. There is no box / twoColumn / subtitle helper on ConsoleCommand itself — use io.box(...) / io.twoColumn(...) / io.subtitle(...) when you need them.
Prompts
Section titled “Prompts”Use Prompts for interactive input. Injectable streams keep tests non-interactive:
val prompts = Prompts()val name = prompts.ask("Name", default = "Kona")val ok = prompts.confirm("Continue?", default = false)val pick = prompts.choice("Driver", listOf("array", "redis"), defaultIndex = 0)Prompts prompts = new Prompts();String name = prompts.ask("Name", "Kona");boolean ok = prompts.confirm("Continue?", false);String pick = prompts.choice("Driver", List.of("array", "redis"), 0);| Method | Behavior |
|---|---|
ask(question, default=null) |
Free text; empty line uses default when set; otherwise returns empty string |
confirm(question, default=false) |
Hint Y/n or y/N; empty → default; y / yes → true |
choice(question, options, defaultIndex=0) |
Numbered list; empty → default; accepts 1-based index or case-insensitive label; invalid input → default |
choice requires a non-empty options list and a defaultIndex in range. Styling uses ConsoleIO primary/accent/dim paints on the prompt streams you inject (default: System.in / System.out).
Built-ins such as serve (port conflict) and key:generate (production overwrite) use Prompts internally.
Exit codes
Section titled “Exit codes”| Code | Constant | Meaning |
|---|---|---|
0 |
ConsoleCommand.SUCCESS |
Success (also when --isolated skips a busy command) |
1 |
ConsoleCommand.FAILURE |
Usage errors, missing projects, failed generators, unbound services, unknown commands |
Scripts and CI should treat any non-zero exit as failure. Built-ins typically return 0/1 the same way; uncaught GrindException / CadenceException in GrindApplication become error lines and exit 1.
Testing output
Section titled “Testing output”ConsoleTester captures stdout only while running GrindApplication — see HTTP & console tests. Assertions:
| Method | Behavior |
|---|---|
assertOk() |
Exit code 0 |
assertExit(code) |
Exact exit code |
assertSee(text) |
Stdout contains substring |
assertDontSee(text) |
Stdout does not contain substring |
Because error(...) writes to stderr, failed error messages may not appear in ConsoleResult.output. Assert on exit codes for failure paths, or inject streams when testing Prompts / ConsoleIO directly (as the module tests do).
Pitfalls
Section titled “Pitfalls”- Quiet hides progress and tables — do not rely on progress bars in
-qCI logs. tablerow width — mismatched column counts throw; normalize rows first.progresstotal — must be positive orConsoleIOthrows.- Color in pipes — honor
NO_COLORin automation; do not assume ANSI in captured test output. - Global
System.outswap —Grind.callSilentlyandConsoleTesterreplace stdout; avoid nested concurrent calls that depend on the real stream.