Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/fix-copilot-message-flag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@bradygaster/squad-cli': patch
'@bradygaster/squad-sdk': patch
---

Fix obsolete --message flag in watch and loop commands

Replace `--message` with `-p` across all watch capabilities and loop command.
Use `copilot` directly on Windows to avoid .cmd console window issues,
fall back to `gh copilot` on other platforms. Fix TOKEN_PATH typo in
comms-teams.ts (pre-existing bug from #906).
18 changes: 9 additions & 9 deletions packages/squad-cli/src/cli/commands/loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ function buildLoopAgentCommand(
): { cmd: string; args: string[] } {
if (options.agentCmd) {
const parts = options.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (options.copilotFlags) {
args.push(...options.copilotFlags.trim().split(/\s+/));
}
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

// ── Capability Phase Runner ──────────────────────────────────────
Expand Down Expand Up @@ -244,10 +244,10 @@ function createNoopAdapter(): ReturnType<typeof createPlatformAdapter> {

// ── gh Copilot Preflight ─────────────────────────────────────────

/** Verify `gh` CLI with copilot extension is available. */
async function checkGhCopilot(): Promise<void> {
/** Verify the copilot CLI is available. */
async function checkCopilotCli(): Promise<void> {
return new Promise<void>((resolve, reject) => {
execFile('gh', ['copilot', '--version'], (err) => {
execFile('copilot', ['--version'], (err) => {
if (err) reject(err);
else resolve();
});
Expand Down Expand Up @@ -313,12 +313,12 @@ export async function runLoop(dest: string, options: LoopConfig): Promise<void>
fatal('timeout must be a positive number of minutes');
}

// Preflight: verify gh copilot is available (skip if user overrides the agent command)
// Preflight: verify copilot CLI is available (skip if user overrides the agent command)
if (!options.agentCmd) {
try {
await checkGhCopilot();
await checkCopilotCli();
} catch {
fatal('gh CLI with copilot extension required. Install from https://cli.github.com/ and run `gh extension install github/gh-copilot`');
fatal('Copilot CLI required. Install from https://cli.github.com/ and run `gh extension install github/gh-copilot`');
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ const storage = new FSStorageProvider();
function buildAgentCommand(prompt: string, context: WatchContext): { cmd: string; args: string[] } {
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) args.push(...context.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

function spawnWithTimeout(cmd: string, args: string[], cwd: string, timeoutMs: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ function buildAgentCommand(
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
const cmd = parts[0]!;
const args = [...parts.slice(1), '--message', prompt];
const args = [...parts.slice(1), '-p', prompt];
return { cmd, args };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) {
args.push(...context.copilotFlags.trim().split(/\s+/));
}
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

/** Labels that indicate an issue should not be auto-executed. */
Expand Down Expand Up @@ -202,7 +202,7 @@ export class ExecuteCapability implements WatchCapability {
try {
const timeout = ((context.config['timeout'] as number) ?? 30) * 60_000;

vlog.log(`Execute: agentCmd=${context.agentCmd ?? 'gh copilot'}, timeout=${timeout / 60_000}m`);
vlog.log(`Execute: agentCmd=${context.agentCmd ?? 'copilot'}, timeout=${timeout / 60_000}m`);

// Fetch open issues with squad label
const sdkItems = await context.adapter.listWorkItems({ tags: ['squad'], state: 'open', limit: 50 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import type { WatchCapability, WatchContext, PreflightResult, CapabilityResult }
function buildAgentCommand(prompt: string, context: WatchContext): { cmd: string; args: string[] } {
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) args.push(...context.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

function spawnWithTimeout(cmd: string, args: string[], cwd: string, timeoutMs: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import type { WatchCapability, WatchContext, PreflightResult, CapabilityResult }
function buildAgentCommand(prompt: string, context: WatchContext): { cmd: string; args: string[] } {
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) args.push(...context.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

function spawnWithTimeout(cmd: string, args: string[], cwd: string, timeoutMs: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ const storage = new FSStorageProvider();
function buildAgentCommand(prompt: string, context: WatchContext): { cmd: string; args: string[] } {
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) args.push(...context.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

function spawnWithTimeout(cmd: string, args: string[], cwd: string, timeoutMs: number): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ function parseSubTasks(body: string | undefined): SubTask[] {
function buildAgentCommand(prompt: string, context: WatchContext): { cmd: string; args: string[] } {
if (context.agentCmd) {
const parts = context.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (context.copilotFlags) args.push(...context.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

function executeSubTask(
Expand Down
6 changes: 3 additions & 3 deletions packages/squad-cli/src/cli/commands/watch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,11 +609,11 @@ export function buildAgentCommand(
const prompt = `Work on issue #${issue.number}: ${issue.title}. Read the issue body for full details.`;
if (options.agentCmd) {
const parts = options.agentCmd.trim().split(/\s+/);
return { cmd: parts[0]!, args: [...parts.slice(1), '--message', prompt] };
return { cmd: parts[0]!, args: [...parts.slice(1), '-p', prompt] };
}
const args = ['copilot', '--message', prompt];
const args = ['-p', prompt];
if (options.copilotFlags) args.push(...options.copilotFlags.trim().split(/\s+/));
return { cmd: 'gh', args };
return { cmd: 'copilot', args };
}

export async function selfPull(teamRoot: string): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/squad-sdk/src/platform/comms-teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function saveTokens(tenantId: string, clientId: string, tokens: StoredTokens): v

// Ensure permissions are correct even if file already existed
if (platform() === 'win32') {
execFile('icacls', [TOKEN_PATH, '/inheritance:r', '/grant:r', `${process.env.USERNAME ?? 'CURRENT_USER'}:(R,W)`], (err) => {
execFile('icacls', [tokenPath, '/inheritance:r', '/grant:r', `${process.env.USERNAME ?? 'CURRENT_USER'}:(R,W)`], (err) => {
if (err) console.warn('⚠️ Could not restrict token file permissions:', err.message);
});
} else {
Expand Down
2 changes: 1 addition & 1 deletion test/cli/watch-capabilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ describe('Watch Capabilities', () => {
await cap.execute(ctx);
expect(mockExecFile).toHaveBeenCalledWith(
'my-agent',
expect.arrayContaining(['--flag', '--message']),
expect.arrayContaining(['--flag', '-p']),
expect.any(Object),
expect.any(Function),
);
Expand Down
9 changes: 4 additions & 5 deletions test/cli/watch-execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ describe('CLI: watch execute mode', () => {

const { cmd, args } = buildAgentCommand(issue, teamRoot, options);

expect(cmd).toBe('gh');
expect(args).toContain('copilot');
expect(args).toContain('--message');
expect(cmd).toBe('copilot');
expect(args).toContain('-p');
expect(args.some((a) => a.includes('issue #42'))).toBe(true);
});

Expand All @@ -45,7 +44,7 @@ describe('CLI: watch execute mode', () => {

const { cmd, args } = buildAgentCommand(issue, teamRoot, options);

expect(cmd).toBe('gh');
expect(cmd).toBe('copilot');
expect(args).toContain('--model');
expect(args).toContain('gpt-4');
expect(args).toContain('--yolo');
Expand All @@ -67,7 +66,7 @@ describe('CLI: watch execute mode', () => {
expect(cmd).toBe('custom-agent');
expect(args).toContain('--flag');
expect(args).toContain('value');
expect(args).toContain('--message');
expect(args).toContain('-p');
});
});

Expand Down