Repository navigation
Description
Summary
On Windows, squad triage --execute (watch/Ralph execute mode) dispatches a Copilot session that gets only the first line of the prompt. cmd.exe ends the command at the first newline, so the agent sees:
You are an AI agent on a software development team.
It answers that no task was given, exits 0 after about 8 seconds, and the round reports success. No issue ever gets worked, and each round still costs a Copilot request.
Environment
- Squad CLI 0.13.0, WinGet package
bradygaster.Squad(squad-win32-x64). The 0.13.1 release notes don't mention a fix. - Windows 11 Pro 10.0.26200
- GitHub Copilot CLI 1.0.88 (npm global,
copilot.cmdshim) - Default execute settings:
agentCmddefault (copilot),--yolo
Repro
- Open one issue labelled
squadwith no assignee. - Run
squad triage --execute --verboseon Windows. - Verbose shows
Execute: 1 total issues, 1 eligible/→ #N …, then the round completes in about 10 to 15 s. - Open that Copilot session's
~/.copilot/session-state/<id>/events.jsonl. The firstuser.messageis only"You are an AI agent on a software development team.", and the assistant replies that no task was included.
It happened on every execute round we ran; all three sessions show the same truncated prompt.
Root cause
dist/cli/commands/watch/agent-spawn.js: spawnAgent() / spawnWithTimeout() use execFile(cmd, escapeArgs(args), { shell: IS_WINDOWS }). escapeForCmd() double-quotes arguments, but inside cmd.exe /d /s /c "…" a newline still ends the command, even inside quotes. The prompt from buildAgentPrompt() (charter prefix plus the issue list) is multi-line, so everything after the first line is lost.
There's a second limit waiting behind it: cmd.exe's 8,191-character command-line maximum. Collapsing the newlines to spaces would hit that once the charter and issue list grow.
Suggested fix
Keep the prompt off the cmd.exe command line on Windows. For example, write multi-line prompts to a temp file and pass a one-line -p that points at it, or avoid shell: true by resolving the copilot shim to its node entry point (e.g. cross-spawn). A local patch we're running now, in escapeArgs() on win32:
return args.map(spillMultiline).map(escapeForCmd);
function spillMultiline(arg) {
if (typeof arg !== 'string' || !/[\r\n]/.test(arg)) return arg;
const dir = join(tmpdir(), 'squad-prompts');
mkdirSync(dir, { recursive: true });
const file = join(dir, `prompt-${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 8)}.md`);
writeFileSync(file, arg, 'utf8');
return `Your complete instructions are in the file ${file} - read that whole file first and follow it exactly as if it were this prompt.`;
}Related: the round summary hides dispatches
watch/index.js reads execResult.data['executed'] for the 🚀 Executed: line, but ExecuteCapability.execute() returns data: { dispatched, success }. The summary therefore never shows that an agent was dispatched, only 🟡 Assigned: N, which made this failure look like "nothing eligible" until run with --verbose.
Activity
fix(cli): prevent Windows cmd.exe multiline prompt truncation in watc…
fix(cli): prevent Windows cmd.exe multiline prompt truncation in watc…
fix(cli): prevent Windows cmd.exe multiline prompt truncation in watc…