diff --git a/cmd/gocmd/cmd_commands.go b/cmd/gocmd/cmd_commands.go index 44b6fb3..5b2943a 100644 --- a/cmd/gocmd/cmd_commands.go +++ b/cmd/gocmd/cmd_commands.go @@ -13,9 +13,3 @@ // // Sets MACOSX_DEPLOYMENT_TARGET to suppress linker warnings on macOS. package gocmd - -import "forge.lthn.ai/core/go/pkg/cli" - -func init() { - cli.RegisterCommands(AddGoCommands) -} diff --git a/pkg/cli/app.go b/pkg/cli/app.go index 7d2d4e2..c02cc16 100644 --- a/pkg/cli/app.go +++ b/pkg/cli/app.go @@ -48,9 +48,16 @@ func SemVer() string { } // Main initialises and runs the CLI application. -// This is the main entry point for the CLI. +// Pass command services via WithCommands to register CLI commands +// through the Core framework lifecycle. +// +// cli.Main( +// cli.WithCommands("config", config.AddConfigCommands), +// cli.WithCommands("doctor", doctor.AddDoctorCommands), +// ) +// // Exits with code 1 on error or panic. -func Main() { +func Main(commands ...framework.Option) { // Recovery from panics defer func() { if r := recover(); r != nil { @@ -60,17 +67,21 @@ func Main() { } }() + // Core services load first, then command services + services := []framework.Option{ + framework.WithName("i18n", NewI18nService(I18nOptions{})), + framework.WithName("log", NewLogService(log.Options{ + Level: log.LevelInfo, + })), + framework.WithName("workspace", workspace.New), + } + services = append(services, commands...) + // Initialise CLI runtime with services if err := Init(Options{ - AppName: AppName, - Version: SemVer(), - Services: []framework.Option{ - framework.WithName("i18n", NewI18nService(I18nOptions{})), - framework.WithName("log", NewLogService(log.Options{ - Level: log.LevelInfo, - })), - framework.WithName("workspace", workspace.New), - }, + AppName: AppName, + Version: SemVer(), + Services: services, }); err != nil { Error(err.Error()) os.Exit(1) diff --git a/pkg/cli/commands.go b/pkg/cli/commands.go index 20ea2da..f481974 100644 --- a/pkg/cli/commands.go +++ b/pkg/cli/commands.go @@ -2,49 +2,34 @@ package cli import ( - "sync" + "context" + "forge.lthn.ai/core/go/pkg/framework" "github.com/spf13/cobra" ) -// CommandRegistration is a function that adds commands to the root. -type CommandRegistration func(root *cobra.Command) - -var ( - registeredCommands []CommandRegistration - registeredCommandsMu sync.Mutex - commandsAttached bool -) - -// RegisterCommands registers a function that adds commands to the CLI. -// Call this in your package's init() to register commands. +// WithCommands creates a framework Option that registers a command group. +// The register function receives the root command during service startup, +// allowing commands to participate in the Core lifecycle. // -// func init() { -// cli.RegisterCommands(AddCommands) -// } -// -// func AddCommands(root *cobra.Command) { -// root.AddCommand(myCmd) -// } -func RegisterCommands(fn CommandRegistration) { - registeredCommandsMu.Lock() - defer registeredCommandsMu.Unlock() - registeredCommands = append(registeredCommands, fn) - - // If commands already attached (CLI already running), attach immediately - if commandsAttached && instance != nil && instance.root != nil { - fn(instance.root) - } +// cli.Main( +// cli.WithCommands("config", config.AddConfigCommands), +// cli.WithCommands("doctor", doctor.AddDoctorCommands), +// ) +func WithCommands(name string, register func(root *Command)) framework.Option { + return framework.WithName("cmd."+name, func(c *framework.Core) (any, error) { + return &commandService{core: c, register: register}, nil + }) } -// attachRegisteredCommands calls all registered command functions. -// Called by Init() after creating the root command. -func attachRegisteredCommands(root *cobra.Command) { - registeredCommandsMu.Lock() - defer registeredCommandsMu.Unlock() - - for _, fn := range registeredCommands { - fn(root) - } - commandsAttached = true +type commandService struct { + core *framework.Core + register func(root *Command) +} + +func (s *commandService) OnStartup(_ context.Context) error { + if root, ok := s.core.App.(*cobra.Command); ok { + s.register(root) + } + return nil } diff --git a/pkg/cli/runtime.go b/pkg/cli/runtime.go index 08636f1..c0dd383 100644 --- a/pkg/cli/runtime.go +++ b/pkg/cli/runtime.go @@ -63,9 +63,6 @@ func Init(opts Options) error { SilenceUsage: true, } - // Attach all registered commands - attachRegisteredCommands(rootCmd) - // Build signal service options var signalOpts []SignalOption if opts.OnReload != nil {