Skip to content

(shell) - Adopt Explicit Shell Invocation and Prioritize PowerShell on Windows #6413

Description

@abhipatel12

Summary

Our current shell execution architecture (ShellExecutionService.ts) relies on spawn({ shell: true }) on Windows. This approach is unpredictable, typically defaults to the legacy cmd.exe (even when PowerShell is available), and prevents us from managing PowerShell Execution Policies (we cannot inject -ExecutionPolicy Bypass).

We should refactor the architecture to use Explicit Shell Invocation (shell: false).

Motivation

  1. Reliability: Ensure scripts run reliably by injecting -ExecutionPolicy Bypass and -NonInteractive.
  2. Capability: Prioritize PowerShell (pwsh.exe or powershell.exe) over cmd.exe on Windows, as LLMs are more proficient with modern PowerShell syntax.
  3. Predictability: Remove reliance on the ambiguous shell: true behavior.

Implementation Plan

This requires coordinated changes across several modules.

1. Configuration (shell-utils.ts)

  • Install the which dependency.
  • Refactor getShellConfiguration() to proactively search the PATH (using which).
  • Prioritization on Windows: pwsh.exe > powershell.exe > cmd.exe.
  • Ensure PowerShell configurations include the required automation flags: ['-ExecutionPolicy', 'Bypass', '-NonInteractive', '-NoProfile', '-Command'].

2. Execution (ShellExecutionService.ts)

  • Import and use getShellConfiguration().
  • Change the spawn call to use explicit invocation:
    const shellConfig = getShellConfiguration();
    const args = [...shellConfig.argsPrefix, commandToExecute];
    spawn(shellConfig.executable, args, { shell: false, /* ... other options ... */ });
  • Ensure platform checks use a centralized isWindows() utility rather than os.platform().

3. Consumers (shell.ts, shellCommandProcessor.ts)

  • shell.ts (Agent Tool):
    • Dynamic Advertisement: Update getShellToolDescription to dynamically inform the LLM which shell (Bash, PowerShell, or CMD) is active. This prevents syntax mismatches.
    • Logic Compatibility: The pgrep wrapper is Bash-specific. This logic must be conditionalized based on the detected shell (if (shellConfig.shell === 'bash')), not just the OS.
  • shellCommandProcessor.ts (User Shell Mode):
    • Logic Compatibility: The pwd > file wrapper is Bash-specific. This logic must also be conditionalized based on the detected shell. (We should also implement the PowerShell equivalent: (Get-Location).Path).

NOTE: We should also check the system instructions in prompts.ts to ensure we are not providing misleading examples or instructions

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stalearea/agentIssues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Qualityarea/coreIssues related to User Interface, OS Support, Core Functionality🔒 maintainer only⛔ Do not contribute. Internal roadmap item.

    Type

    Projects

    Status
    Closed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions