2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00
2026-02-24 00:43:22 +01:00

summer-bonfire

CLI command framework module for SummerCMS. Provides command registration, dispatch, and rich terminal output — the Scala 3 equivalent of Laravel's Illuminate\Console.

Bonfire is not a CLI argument parser. case-app handles argument parsing and help generation. Bonfire is the CMS command framework on top: how commands are registered, discovered via plugins, dispatched, and how they produce rich terminal output (spinners, progress bars, tables, interactive prompts).

Quick start

import summer.bonfire.*

// Define a command
object GreetCommand extends Command:
  val name = "greet"
  val description = "Greet a user"

  def run(input: Input, output: Output): ExitCode =
    val name = input.argument("name").getOrElse("World")
    output.success(s"Hello, $name!")
    ExitCode.Success

// Register and run
val runner = CommandRunner()
runner.register(GreetCommand)
runner.dispatch(args)

Rich terminal output

All widgets are custom-built in Scala 3 — no external TUI framework. Inspired by SSU's terminal UX.

// Spinner with braille animation (virtual thread powered)
output.withSpinner("Compiling plugin...") {
  compilePlugin()
}

// Progress bar with 256-color gradient
output.withProgress(files.size) { bar =>
  files.foreach { file =>
    processFile(file)
    bar.advance()
  }
}

// Box-drawing table
output.table(
  headers = Seq("Plugin", "Version", "Status"),
  rows = Seq(
    Seq("golem15.blog", "1.2.0", "active"),
    Seq("golem15.pages", "1.0.3", "active"),
  )
)

// Interactive prompts (via JLine)
val name = output.ask("Plugin name?")
val confirm = output.confirm("Create plugin?")
val choice = output.choice("Select database:", Seq("postgres", "mysql", "sqlite"))

Plugin command discovery

Plugins register commands via CommandProvider (ServiceLoader SPI):

class BlogCommandProvider extends CommandProvider:
  def commands: Seq[Command] = Seq(
    BlogSeedCommand,
    BlogImportCommand,
  )

Commands are auto-discovered at boot from all plugins on the classpath.

Non-TTY graceful degradation

All widgets detect terminal capabilities and degrade gracefully:

  • Spinners become [...] message static lines
  • Progress bars become [N/M] percentage% text updates
  • Colors stripped when NO_COLOR is set or TERM=dumb
  • Interactive prompts fall back to line-by-line stdin

Dependencies

Dependency Version Purpose
com.github.alexarchambault:case-app 2.1.0-M29 CLI argument parsing, auto-generated help
com.lihaoyi:fansi 0.5.1 ANSI colors/styles, visible-width-aware strings
org.jline:jline 3.28.0 Terminal raw mode, readline, key events, terminal detection
org.scalameta:munit 1.0.3 Testing (test scope only)

No effect systems. No Cats, no ZIO. Pure direct-style Scala 3 on JDK 21.

Building

# sbt
sbt compile
sbt test

# scala-cli
scala-cli compile .
scala-cli test .

Requires JDK 21+ and sbt 1.10+.

Roadmap

See PLAN.md for the full module architecture and implementation phases.

  • Phase 1 — Core types and output abstractions
  • Phase 2 — Command framework with case-app and ServiceLoader SPI
  • Phase 3 — Rich output widgets (table, spinner, progress bar)
  • Phase 4 — Interactive prompts via JLine
  • Phase 5 — GeneratorCommand base for summer create:* scaffolding
  • Phase 6 — Polish: shell completion, multiselect, non-TTY tests

License

Part of SummerCMS.

Description
No description provided
Readme 38 KiB
Languages
Scala 100%