# summer-bonfire CLI command framework module for [SummerCMS](https://git.golem15.com/golem15/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](https://github.com/alexarchambault/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 ```scala 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](https://git.golem15.com/golem15/ssu)'s terminal UX. ```scala // 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): ```scala 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 ```bash # sbt sbt compile sbt test # scala-cli scala-cli compile . scala-cli test . ``` Requires JDK 21+ and sbt 1.10+. ## Roadmap See [PLAN.md](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.