feat(bootstrap): add DisabledCommands option to hide unused commands
Commands listed in DisabledCommands are excluded from global help output and return ErrUnknownCommand when invoked or help is requested for them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
955c96650a
commit
4a7248cfa9
2 changed files with 87 additions and 11 deletions
|
|
@ -52,17 +52,18 @@ type Hooks struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
BinaryName string
|
BinaryName string
|
||||||
Description string
|
Description string
|
||||||
Version string
|
Version string
|
||||||
Aliases map[string][]string
|
Aliases map[string][]string
|
||||||
AliasDescriptions map[string]string
|
AliasDescriptions map[string]string
|
||||||
EnableDoctorAlias bool
|
EnableDoctorAlias bool
|
||||||
Args []string
|
DisabledCommands []string
|
||||||
Stdin io.Reader
|
Args []string
|
||||||
Stdout io.Writer
|
Stdin io.Reader
|
||||||
Stderr io.Writer
|
Stdout io.Writer
|
||||||
Hooks Hooks
|
Stderr io.Writer
|
||||||
|
Hooks Hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
type Invocation struct {
|
type Invocation struct {
|
||||||
|
|
@ -146,6 +147,10 @@ func Run(ctx context.Context, opts Options) error {
|
||||||
return printHelp(normalized, "")
|
return printHelp(normalized, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCommandDisabled(command, normalized.DisabledCommands) {
|
||||||
|
return fmt.Errorf("%w: %s", ErrUnknownCommand, command)
|
||||||
|
}
|
||||||
|
|
||||||
if command == CommandConfig {
|
if command == CommandConfig {
|
||||||
return runConfigCommand(ctx, normalized, commandArgs)
|
return runConfigCommand(ctx, normalized, commandArgs)
|
||||||
}
|
}
|
||||||
|
|
@ -460,6 +465,10 @@ func printHelp(opts Options, command string, args ...[]string) error {
|
||||||
return printConfigHelp(opts, commandArgs)
|
return printConfigHelp(opts, commandArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCommandDisabled(command, opts.DisabledCommands) {
|
||||||
|
return fmt.Errorf("%w: %s", ErrUnknownCommand, command)
|
||||||
|
}
|
||||||
|
|
||||||
for _, def := range commands {
|
for _, def := range commands {
|
||||||
if def.Name != command {
|
if def.Name != command {
|
||||||
continue
|
continue
|
||||||
|
|
@ -535,6 +544,9 @@ func printGlobalHelp(opts Options) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, def := range commands {
|
for _, def := range commands {
|
||||||
|
if isCommandDisabled(def.Name, opts.DisabledCommands) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if _, err := fmt.Fprintf(opts.Stdout, " %-7s %s\n", def.Name, def.Description); err != nil {
|
if _, err := fmt.Fprintf(opts.Stdout, " %-7s %s\n", def.Name, def.Description); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -571,6 +583,15 @@ func printGlobalHelp(opts Options) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isCommandDisabled(command string, disabled []string) bool {
|
||||||
|
for _, d := range disabled {
|
||||||
|
if d == command {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func aliasDescription(descriptions map[string]string, name, target string) string {
|
func aliasDescription(descriptions map[string]string, name, target string) string {
|
||||||
description := strings.TrimSpace(descriptions[name])
|
description := strings.TrimSpace(descriptions[name])
|
||||||
if description == "" {
|
if description == "" {
|
||||||
|
|
|
||||||
|
|
@ -607,3 +607,58 @@ func TestRunAcceptsGlobalDebugFlagAfterCommand(t *testing.T) {
|
||||||
t.Fatalf("MCP_FRAMEWORK_BITWARDEN_DEBUG = %q, want %q", os.Getenv("MCP_FRAMEWORK_BITWARDEN_DEBUG"), "1")
|
t.Fatalf("MCP_FRAMEWORK_BITWARDEN_DEBUG = %q, want %q", os.Getenv("MCP_FRAMEWORK_BITWARDEN_DEBUG"), "1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDisabledCommandReturnsUnknown(t *testing.T) {
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
|
||||||
|
err := Run(context.Background(), Options{
|
||||||
|
BinaryName: "my-mcp",
|
||||||
|
Args: []string{"login"},
|
||||||
|
DisabledCommands: []string{"login"},
|
||||||
|
Stdout: &stdout,
|
||||||
|
Stderr: &stderr,
|
||||||
|
})
|
||||||
|
|
||||||
|
if !errors.Is(err, ErrUnknownCommand) {
|
||||||
|
t.Fatalf("err = %v, want ErrUnknownCommand", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisabledCommandHiddenFromHelp(t *testing.T) {
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
|
||||||
|
err := printGlobalHelp(Options{
|
||||||
|
BinaryName: "my-mcp",
|
||||||
|
DisabledCommands: []string{"login", "setup"},
|
||||||
|
Stdout: &stdout,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("printGlobalHelp error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := stdout.String()
|
||||||
|
if strings.Contains(out, "login") {
|
||||||
|
t.Fatalf("help should not contain disabled command %q, got:\n%s", "login", out)
|
||||||
|
}
|
||||||
|
if strings.Contains(out, "setup") {
|
||||||
|
t.Fatalf("help should not contain disabled command %q, got:\n%s", "setup", out)
|
||||||
|
}
|
||||||
|
if !strings.Contains(out, "mcp") {
|
||||||
|
t.Fatalf("help should contain enabled command %q, got:\n%s", "mcp", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisabledCommandHelpReturnsUnknown(t *testing.T) {
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
|
||||||
|
err := printHelp(Options{
|
||||||
|
BinaryName: "my-mcp",
|
||||||
|
DisabledCommands: []string{"login"},
|
||||||
|
Stdout: &stdout,
|
||||||
|
}, "login")
|
||||||
|
|
||||||
|
if !errors.Is(err, ErrUnknownCommand) {
|
||||||
|
t.Fatalf("err = %v, want ErrUnknownCommand", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue