Code Smell: Duplicated Code (Dispensables)
Severity: HIGH
Category: Dispensables > Duplicated Code
Files: cli/src/cmd/exec/commands/mcp.go, cli/src/internal/executor/command_builder.go
Description
The shell argument construction logic is duplicated between two independent implementations:
buildShellArgs() in mcp.go (lines 381-410) — used by MCP handlers
buildCommand() in command_builder.go (lines 31-79) — used by the CLI executor
Both functions contain the same switch-case structure handling bash/sh/zsh, pwsh/powershell, and cmd shells with identical argument patterns. When a new shell is added or argument behavior changes, both locations must be updated independently, risking divergence.
Current divergence example: The MCP version adds -NoProfile for PowerShell but the CLI version does not. This may be intentional, but having two independent implementations makes it unclear whether differences are bugs or features.
Refactoring Recommendation
Extract a shared ShellCommandBuilder in a common package (e.g., internal/shellcmd) that both the CLI executor and MCP handlers can use:
// Package shellcmd builds shell-specific command argument lists.
package shellcmd
type Options struct {
NoProfile bool // Add -NoProfile for PowerShell (used by MCP)
}
func BuildArgs(shell, scriptOrCmd string, isInline bool, extraArgs []string, opts Options) []string {
// Single implementation of shell argument construction
}
This eliminates the duplication and makes shell behavior differences explicit through options rather than implicit through separate implementations.
Impact
- Maintenance burden: Changes to shell handling require updating two files
- Bug risk: Divergent behavior between CLI and MCP code paths is hard to detect
- Testing overhead: Both implementations need independent test coverage for the same logic
Code Smell: Duplicated Code (Dispensables)
Severity: HIGH
Category: Dispensables > Duplicated Code
Files:
cli/src/cmd/exec/commands/mcp.go,cli/src/internal/executor/command_builder.goDescription
The shell argument construction logic is duplicated between two independent implementations:
buildShellArgs()inmcp.go(lines 381-410) — used by MCP handlersbuildCommand()incommand_builder.go(lines 31-79) — used by the CLI executorBoth functions contain the same switch-case structure handling bash/sh/zsh, pwsh/powershell, and cmd shells with identical argument patterns. When a new shell is added or argument behavior changes, both locations must be updated independently, risking divergence.
Current divergence example: The MCP version adds
-NoProfilefor PowerShell but the CLI version does not. This may be intentional, but having two independent implementations makes it unclear whether differences are bugs or features.Refactoring Recommendation
Extract a shared
ShellCommandBuilderin a common package (e.g.,internal/shellcmd) that both the CLI executor and MCP handlers can use:This eliminates the duplication and makes shell behavior differences explicit through options rather than implicit through separate implementations.
Impact