Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.
This repository was archived by the owner on May 18, 2026. It is now read-only.

refactor: extract shared shell argument builder to eliminate duplication #100

@jongio

Description

@jongio

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:

  1. buildShellArgs() in mcp.go (lines 381-410) — used by MCP handlers
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    automatedCreated by automationsmellsCode smell detection

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions