-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Describe the bug
The CLI doesn't respect quotes when parsing extension commands with spaces. Both goose session --with-extension and goose configure (Add Extension) use the add_extension() function which uses .split_whitespace(), breaking paths like /Applications/IntelliJ IDEA.app/... even when quoted.
Note: The Desktop UI version of this issue is #6417, which is being fixed in #6430.
To Reproduce
Method 1: --with-extension flag
goose session --with-extension '"/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java" -classpath "/path/with spaces/lib.jar" com.example.Main'Method 2: goose configure
- Run
goose configure - Select "Add Extension" → "Command-line Extension"
- Enter command:
"/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java" -classpath "/path/with spaces/lib.jar" com.example.Main - Complete the prompts
Result in both cases:
- Extension fails to start with:
Failed to start extension: IO error: No such file or directory (os error 2) - Config file shows malformed YAML with quotes embedded incorrectly:
cmd: '"/Applications/IntelliJ'
args:
- IDEA.app/Contents/jbr/Contents/Home/bin/java"
- -classpath
- '"/Applications/IntelliJ'Expected behavior
Quoted strings should be preserved as single arguments. The CLI already uses shlex::split for other command parsing (e.g., /prompt commands in parse_prompts_command()) - the add_extension() function should use the same approach.
Please provide the following information
- OS & Arch: macOS
- Interface: CLI
- Version: v1.19.1
- Extensions enabled: N/A (occurs during extension setup)
- Provider & Model: N/A (configuration issue)
Additional context
Current code (crates/goose-cli/src/session/mod.rs):
pub async fn add_extension(&mut self, extension_command: String) -> Result<()> {
let mut parts: Vec<&str> = extension_command.split_whitespace().collect(); // ← breaks on all whitespace
let mut envs = HashMap::new();
while let Some(part) = parts.first() {
if !part.contains('=') {
break;
}
let env_part = parts.remove(0);
let (key, value) = env_part.split_once('=').unwrap();
envs.insert(key.to_string(), value.to_string());
}
if parts.is_empty() {
return Err(anyhow::anyhow!("No command provided in extension string"));
}
let cmd = parts.remove(0).to_string();
// ... rest of function
}Suggested fix:
pub async fn add_extension(&mut self, extension_command: String) -> Result<()> {
// Use shlex to properly handle quoted strings with spaces
let mut parts: Vec<String> = shlex::split(&extension_command)
.ok_or_else(|| anyhow::anyhow!("Failed to parse extension command"))?;
let mut envs = HashMap::new();
while let Some(part) = parts.first() {
if !part.contains('=') {
break;
}
let env_part = parts.remove(0);
let (key, value) = env_part.split_once('=').unwrap();
envs.insert(key.to_string(), value.to_string());
}
if parts.is_empty() {
return Err(anyhow::anyhow!("No command provided in extension string"));
}
let cmd = parts.remove(0);
// ... rest of function (args is already Vec<String>)
}Workarounds:
- Manually edit
~/.config/goose/config.yamlwith proper YAML structure:
jb2:
enabled: true
cmd: /Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java
args:
- -classpath
- /Applications/IntelliJ IDEA.app/Contents/plugins/mcpserver/lib/mcpserver-frontend.jar:/Applications/IntelliJ IDEA.app/Contents/lib/util-8.jar
- com.intellij.mcpserver.stdio.McpStdioRunnerKt
envs:
IJ_MCP_SERVER_PORT: "64342"
env_keys:
- IJ_MCP_SERVER_PORT- Create symlinks without spaces (e.g.,
/Applications/IntelliJIDEA.app) - Use wrapper scripts
Related: