Code Smell: Shotgun Surgery (Change Preventers)
Severity: HIGH
Category: Change Preventers > Shotgun Surgery
Files: cli/src/internal/executor/command_builder.go, cli/src/cmd/exec/commands/mcp.go
Description
The list of supported shells is defined independently in three separate locations that must all be updated when adding or removing a shell:
| Location |
File |
Type |
validShells map |
command_builder.go:12-19 |
Validation map for CLI |
buildShellArgs switch |
mcp.go:383-409 |
Command construction for MCP |
handleListShells slice |
mcp.go:242-249 |
Discovery endpoint for MCP clients |
Additionally, buildCommand in command_builder.go has its own switch statement (line 47) that must also match the valid shells.
Adding a new shell (e.g., fish or nushell) requires touching at least 3-4 locations across 2 files. Missing any one of them creates a subtle inconsistency — for example, a shell could be valid for CLI use but not discoverable via MCP, or vice versa.
Refactoring Recommendation
Define a single authoritative shell registry in a shared package:
// Package shellreg provides the canonical list of supported shells.
package shellreg
type Shell struct {
Name string
InlineFlag string // "-c", "-Command", "/c"
FileFlag string // "", "-File", "/c"
ExtraFlags []string // e.g., ["-NoProfile"] for PowerShell
}
var Shells = []Shell{
{Name: "bash", InlineFlag: "-c"},
{Name: "sh", InlineFlag: "-c"},
// ...
}
func IsValid(name string) bool { ... }
func Names() []string { ... }
All consumers (validation, command building, shell listing) would derive from this single source of truth.
Impact
- Shotgun surgery: Every shell change touches 3-4 locations
- Silent inconsistency: Forgetting one location creates hard-to-detect bugs
- Test burden: Each location needs its own tests to verify consistency
Code Smell: Shotgun Surgery (Change Preventers)
Severity: HIGH
Category: Change Preventers > Shotgun Surgery
Files:
cli/src/internal/executor/command_builder.go,cli/src/cmd/exec/commands/mcp.goDescription
The list of supported shells is defined independently in three separate locations that must all be updated when adding or removing a shell:
validShellsmapcommand_builder.go:12-19buildShellArgsswitchmcp.go:383-409handleListShellsslicemcp.go:242-249Additionally,
buildCommandincommand_builder.gohas its own switch statement (line 47) that must also match the valid shells.Adding a new shell (e.g.,
fishornushell) requires touching at least 3-4 locations across 2 files. Missing any one of them creates a subtle inconsistency — for example, a shell could be valid for CLI use but not discoverable via MCP, or vice versa.Refactoring Recommendation
Define a single authoritative shell registry in a shared package:
All consumers (validation, command building, shell listing) would derive from this single source of truth.
Impact