123 lines
3.6 KiB
Markdown
123 lines
3.6 KiB
Markdown
# 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.
|