fix(ssh): skip adding prompt to args when using stdin for SSH

When sendPromptViaStdin or sendPromptViaStdinRaw is set, the prompt
will be sent via stdin as stream-json data. The ChildProcessSpawner
was incorrectly ALSO adding the prompt to the command line args,
causing shell escaping issues with zsh on remote hosts.

This fix skips adding the prompt to args when it will be sent via
stdin, preventing:
- "zsh:35: parse error near 'do'" from multi-line prompts
- "zsh:3: no matches found: **Summary:**" from glob-like patterns

The prompt still gets sent correctly via stdin in the isStreamJsonMode
block at line 389+.
This commit is contained in:
Pedram Amini
2026-01-31 21:47:16 -05:00
parent 93e9d9f8ec
commit ec3a5b528f

View File

@@ -63,19 +63,26 @@ export class ChildProcessSpawner {
contextWindow,
customEnvVars,
noPromptSeparator,
sendPromptViaStdin,
sendPromptViaStdinRaw,
} = config;
const isWindows = process.platform === 'win32';
const hasImages = images && images.length > 0;
const capabilities = getAgentCapabilities(toolType);
// Check if prompt will be sent via stdin instead of command line
// This is critical for SSH remote execution to avoid shell escaping issues
const promptViaStdin = sendPromptViaStdin || sendPromptViaStdinRaw;
// Build final args based on batch mode and images
let finalArgs: string[];
let tempImageFiles: string[] = [];
if (hasImages && prompt && capabilities.supportsStreamJsonInput) {
// For agents that support stream-json input (like Claude Code)
finalArgs = [...args, '--input-format', 'stream-json'];
// When using stdin, --input-format stream-json should already be in args from the caller
finalArgs = promptViaStdin ? [...args] : [...args, '--input-format', 'stream-json'];
} else if (hasImages && prompt && imageArgs) {
// For agents that use file-based image args (like Codex, OpenCode)
finalArgs = [...args];
@@ -88,20 +95,25 @@ export class ChildProcessSpawner {
}
}
// Add the prompt using promptArgs if available, otherwise as positional arg
if (promptArgs) {
finalArgs = [...finalArgs, ...promptArgs(prompt)];
} else if (noPromptSeparator) {
finalArgs = [...finalArgs, prompt];
} else {
finalArgs = [...finalArgs, '--', prompt];
// SKIP this when prompt is sent via stdin to avoid shell escaping issues
if (!promptViaStdin) {
if (promptArgs) {
finalArgs = [...finalArgs, ...promptArgs(prompt)];
} else if (noPromptSeparator) {
finalArgs = [...finalArgs, prompt];
} else {
finalArgs = [...finalArgs, '--', prompt];
}
}
logger.debug('[ProcessManager] Using file-based image args', 'ProcessManager', {
sessionId,
imageCount: images.length,
tempFiles: tempImageFiles,
promptViaStdin,
});
} else if (prompt) {
} else if (prompt && !promptViaStdin) {
// Regular batch mode - prompt as CLI arg
// SKIP this when prompt is sent via stdin to avoid shell escaping issues
if (promptArgs) {
finalArgs = [...args, ...promptArgs(prompt)];
} else if (noPromptSeparator) {