Skip to content

hook: the rewritten Bash command goes through two shell parses, which breaks quoting and compound commands #3

Description

@idrmn

Summary

secondwind hook prefixes the agent's Bash command with secondwind exec . exec then joins its argv with spaces and runs the result through sh -c. The command therefore passes two shell parses. Quoted metacharacters lose their quotes, and a compound command splits, so only its first segment reaches the optimizer.

Environment

  • secondwind 0.3.2, built from git ab3888a with cargo install --git
  • Claude Code 2.1.220, Arch Linux, fish 4.x as the user shell
  • Hook installed with secondwind setup --hook

Repro 1: the quotes are lost

The agent runs this Bash command:

echo 'a|b'

Result:

sh: line 1: b: command not found

Expected output: a|b.

The outer shell parses secondwind exec echo 'a|b' and passes a|b as one argv item. exec rebuilds the string echo a|b and gives it to sh -c, where | is a pipe again.

Repro 2: a compound command splits

cd /tmp && pwd

Result: the original working directory, not /tmp.

The shell reads this as (secondwind exec cd /tmp) && pwd. The cd runs in the child process of secondwind and is lost. A variable assignment before ; is lost the same way. In a pipeline such as fd . | head -400, only fd is wrapped, so the recorded token count is the output before head, not the output the agent receives.

Impact

A Bash command with a quoted metacharacter fails. A command that depends on cd, on an assignment, or on a pipeline returns a wrong result, and the hook still reports success. The agent sees a shell error or wrong data, so the cause is hard to attribute to secondwind.

Code

  • crates/cli/src/main.rs:869: format!("secondwind exec {command}")
  • crates/cli/src/main.rs:880-884: command.join(" "), then sh -c
  • crates/cli/src/main.rs:110-113: Exec { command: Vec<String> } with trailing_var_arg

Suggested fix

Keep one shell parse. Emit the command as a single argument from the hook, shell-quoted, and run that argument verbatim in exec with no join. For example secondwind exec --command '<quoted command>', where exec gives the value of --command to sh -c unchanged.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions