Command(path, Command{Action: handler}) — typed struct input, Result output.
Command fields exported: Name, Description, Path, Action, Lifecycle, Flags, Hidden.
i18n.SetLanguage returns Result instead of error.
All public methods across core/go now return Result where applicable.
231 tests, 76.5% coverage.
Co-Authored-By: Virgil <virgil@lethean.io>
Service is now a proper struct with OnStart/OnStop/OnReload lifecycle
functions — not a registry wrapping any. Packages create Service{} with
typed fields, same pattern as Command and Option.
Result drops generics — Value is any. The struct is the container,
Value is the generic. No more Result[T] ceremony.
Service(name, Service{}) to register, Service(name) to get — both
return Result. ServiceFactory returns Result not (any, error).
NewWithFactories/NewRuntime return Result.
232 tests, 77.8% coverage.
Co-Authored-By: Virgil <virgil@lethean.io>
Command is now a DTO with no root/child awareness:
- Path-based registration: c.Command("deploy/to/homelab", handler)
- Description is an i18n key derived from path: cmd.deploy.to.homelab.description
- Lifecycle: Run(), Start(), Stop(), Restart(), Reload(), Signal()
- All return core.Result — errors flow through Core internally
- Parent commands auto-created from path segments
Cli is now a surface layer that reads from Core's command registry:
- Resolves os.Args to command path
- Parses flags into Options (--port=8080 → Option{K:"port", V:"8080"})
- Calls command action with parsed Options
- Banner and help use i18n
Old Clir code preserved in tests/testdata/cli_clir.go.bak for reference.
211 tests, 77.5% coverage.
Co-Authored-By: Virgil <virgil@lethean.io>