diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index e7f1d03..081abab 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -205,6 +205,11 @@ func normalize(opts Options) Options { } opts.Aliases = normalizeAliases(opts.Aliases, opts.EnableDoctorAlias) opts.AliasDescriptions = normalizeAliasDescriptions(opts.AliasDescriptions, opts.Aliases, opts.EnableDoctorAlias) + for _, cmd := range autoDisabledCommands(opts) { + if !isCommandDisabled(cmd, opts.DisabledCommands) { + opts.DisabledCommands = append(opts.DisabledCommands, cmd) + } + } return opts } @@ -461,14 +466,14 @@ func printHelp(opts Options, command string, args ...[]string) error { return printGlobalHelp(opts) } - if command == CommandConfig { - return printConfigHelp(opts, commandArgs) - } - if isCommandDisabled(command, opts.DisabledCommands) { return fmt.Errorf("%w: %s", ErrUnknownCommand, command) } + if command == CommandConfig { + return printConfigHelp(opts, commandArgs) + } + for _, def := range commands { if def.Name != command { continue @@ -583,6 +588,30 @@ func printGlobalHelp(opts Options) error { return err } +func autoDisabledCommands(opts Options) []string { + h := opts.Hooks + var disabled []string + if h.Setup == nil { + disabled = append(disabled, CommandSetup) + } + if h.Login == nil { + disabled = append(disabled, CommandLogin) + } + if h.MCP == nil { + disabled = append(disabled, CommandMCP) + } + if h.Config == nil && h.ConfigShow == nil && h.ConfigTest == nil && h.ConfigDelete == nil { + disabled = append(disabled, CommandConfig) + } + if h.Update == nil { + disabled = append(disabled, CommandUpdate) + } + if h.Version == nil && strings.TrimSpace(opts.Version) == "" { + disabled = append(disabled, CommandVersion) + } + return disabled +} + func isCommandDisabled(command string, disabled []string) bool { for _, d := range disabled { if d == command { diff --git a/bootstrap/bootstrap_test.go b/bootstrap/bootstrap_test.go index f0fbbeb..9bd642f 100644 --- a/bootstrap/bootstrap_test.go +++ b/bootstrap/bootstrap_test.go @@ -91,11 +91,13 @@ func TestRunReturnsCommandNotConfigured(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigShow: noop}, }) if !errors.Is(err, ErrSubcommandRequired) { t.Fatalf("Run error = %v, want ErrSubcommandRequired", err) @@ -148,7 +150,7 @@ func TestRunVersionHookOverridesDefault(t *testing.T) { } } -func TestRunRequiresVersionWithoutVersionHook(t *testing.T) { +func TestRunVersionAutoHiddenWithoutHookOrVersionString(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer @@ -158,8 +160,8 @@ func TestRunRequiresVersionWithoutVersionHook(t *testing.T) { Stdout: &stdout, Stderr: &stderr, }) - if !errors.Is(err, ErrVersionRequired) { - t.Fatalf("Run error = %v, want ErrVersionRequired", err) + if !errors.Is(err, ErrUnknownCommand) { + t.Fatalf("Run error = %v, want ErrUnknownCommand", err) } } @@ -167,12 +169,15 @@ func TestRunPrintsGlobalHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Description: "Binaire MCP de test.", + Version: "v1.2.3", Args: []string{"help"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{Setup: noop, MCP: noop, ConfigShow: noop, Update: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -197,12 +202,15 @@ func TestRunPrintsGlobalHelpWhenNoArgs(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Description: "Binaire MCP de test.", + Version: "v1.2.3", Args: []string{}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{Setup: noop, MCP: noop, ConfigShow: noop, Update: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -227,11 +235,13 @@ func TestRunPrintsCommandHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "update"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{Update: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -250,11 +260,13 @@ func TestRunPrintsLoginCommandHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "login"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{Login: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -273,11 +285,13 @@ func TestRunPrintsConfigHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "config"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigShow: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -299,11 +313,13 @@ func TestRunPrintsConfigSubcommandHelp(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"help", "config", "show"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigShow: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -349,11 +365,13 @@ func TestRunConfigShowReturnsCommandNotConfigured(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config", "show"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigTest: noop}, }) if !errors.Is(err, ErrCommandNotConfigured) { t.Fatalf("Run error = %v, want ErrCommandNotConfigured", err) @@ -364,11 +382,13 @@ func TestRunConfigReturnsUnknownSubcommand(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Args: []string{"config", "sync"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigShow: noop}, }) if !errors.Is(err, ErrUnknownSubcommand) { t.Fatalf("Run error = %v, want ErrUnknownSubcommand", err) @@ -412,6 +432,7 @@ func TestRunPrintsAliasHelpFromHelpCommand(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Aliases: map[string][]string{ @@ -420,6 +441,7 @@ func TestRunPrintsAliasHelpFromHelpCommand(t *testing.T) { Args: []string{"help", "doctor"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigTest: noop}, }) if err != nil { t.Fatalf("Run error = %v", err) @@ -435,6 +457,7 @@ func TestRunPrintsAliasHelpFromTrailingHelpFlag(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer + noop := func(_ context.Context, _ Invocation) error { return nil } err := Run(context.Background(), Options{ BinaryName: "my-mcp", Aliases: map[string][]string{ @@ -443,6 +466,7 @@ func TestRunPrintsAliasHelpFromTrailingHelpFlag(t *testing.T) { Args: []string{"doctor", "--help"}, Stdout: &stdout, Stderr: &stderr, + Hooks: Hooks{ConfigTest: noop}, }) if err != nil { t.Fatalf("Run error = %v", err)