fix: use buildRetryCommand in spawn list footer to avoid truncated prompts (#819)

The "Rerun last" hint in `spawn list` was truncating prompts at 30
characters and appending "...", producing broken copy-paste commands.
Now delegates to the existing buildRetryCommand helper which properly
handles long prompts by suggesting --prompt-file instead of truncating.

Agent: ux-engineer

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
A 2026-02-12 23:52:08 -08:00 committed by GitHub
parent 3f28d5f29f
commit 5169350feb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 42 deletions

View file

@ -171,7 +171,8 @@ function suggestFilterCorrection(
return { suggested: false };
}
// ── Replica of showListFooter logic (commands.ts:799-817) ──────────────────
// ── Replica of showListFooter logic (commands.ts) ──────────────────────────
// Now delegates to buildRetryCommand for the rerun hint to avoid truncated prompts.
interface SpawnRecord {
agent: string;
@ -186,6 +187,16 @@ interface FooterOutput {
countInfo: string;
}
// Replica of buildRetryCommand (commands.ts)
function buildRetryCommand(agent: string, cloud: string, prompt?: string): string {
if (!prompt) return `spawn ${agent} ${cloud}`;
if (prompt.length <= 80) {
const safe = prompt.replace(/"/g, '\\"');
return `spawn ${agent} ${cloud} --prompt "${safe}"`;
}
return `spawn ${agent} ${cloud} --prompt-file <your-prompt-file>`;
}
function buildFooter(
records: SpawnRecord[],
totalRecords: number,
@ -193,13 +204,7 @@ function buildFooter(
cloudFilter?: string,
): FooterOutput {
const latest = records[0];
let rerunHint: string;
if (latest.prompt) {
const shortPrompt = latest.prompt.length > 30 ? latest.prompt.slice(0, 30) + "..." : latest.prompt;
rerunHint = `spawn ${latest.agent} ${latest.cloud} --prompt "${shortPrompt}"`;
} else {
rerunHint = `spawn ${latest.agent} ${latest.cloud}`;
}
const rerunHint = buildRetryCommand(latest.agent, latest.cloud, latest.prompt);
let filterInfo: string;
let countInfo: string;
@ -470,7 +475,7 @@ describe("showListFooter logic", () => {
});
describe("rerun hint with prompt", () => {
it("should include prompt in rerun hint", () => {
it("should include prompt in rerun hint for short prompts", () => {
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: "Fix the bug" },
];
@ -479,46 +484,45 @@ describe("showListFooter logic", () => {
expect(footer.rerunHint).toContain("Fix the bug");
});
it("should truncate long prompts at 30 characters", () => {
const longPrompt = "This is a very long prompt that exceeds thirty characters by a lot";
it("should suggest --prompt-file for long prompts instead of truncating", () => {
const longPrompt = "This is a very long prompt that exceeds eighty characters by a lot and keeps going on and on";
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: longPrompt },
];
const footer = buildFooter(records, 1);
expect(footer.rerunHint).toContain("...");
// Should contain the first 30 characters
expect(footer.rerunHint).toContain(longPrompt.slice(0, 30));
// Should NOT contain the full prompt
expect(footer.rerunHint).not.toContain(longPrompt);
});
it("should not truncate short prompts", () => {
const shortPrompt = "Fix the bug";
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: shortPrompt },
];
const footer = buildFooter(records, 1);
expect(footer.rerunHint).toContain(shortPrompt);
expect(footer.rerunHint).toContain("--prompt-file");
// Should NOT contain truncated prompt text with "..."
expect(footer.rerunHint).not.toContain("...");
// Should NOT contain the prompt content
expect(footer.rerunHint).not.toContain("This is a very long");
});
it("should not truncate prompt exactly 30 characters long", () => {
const exactPrompt = "123456789012345678901234567890"; // exactly 30 chars
it("should include full prompt up to 80 characters", () => {
const prompt80 = "B".repeat(80);
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: exactPrompt },
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: prompt80 },
];
const footer = buildFooter(records, 1);
expect(footer.rerunHint).toContain(exactPrompt);
expect(footer.rerunHint).not.toContain("...");
expect(footer.rerunHint).toContain(prompt80);
expect(footer.rerunHint).not.toContain("prompt-file");
});
it("should truncate prompt of 31 characters", () => {
const prompt31 = "1234567890123456789012345678901"; // 31 chars
it("should suggest --prompt-file for prompts over 80 characters", () => {
const prompt81 = "C".repeat(81);
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: prompt31 },
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: prompt81 },
];
const footer = buildFooter(records, 1);
expect(footer.rerunHint).toContain("...");
expect(footer.rerunHint).toContain("--prompt-file");
expect(footer.rerunHint).not.toContain("C".repeat(81));
});
it("should escape double quotes in prompt", () => {
const records: SpawnRecord[] = [
{ agent: "claude", cloud: "sprite", timestamp: "2026-02-11T10:00:00Z", prompt: 'Fix "all" bugs' },
];
const footer = buildFooter(records, 1);
expect(footer.rerunHint).toBe('spawn claude sprite --prompt "Fix \\"all\\" bugs"');
});
});

View file

@ -941,14 +941,7 @@ async function showEmptyListMessage(agentFilter?: string, cloudFilter?: string):
function showListFooter(records: SpawnRecord[], agentFilter?: string, cloudFilter?: string): void {
const latest = records[0];
if (latest.prompt) {
const shortPrompt = latest.prompt.length > 30 ? latest.prompt.slice(0, 30) + "..." : latest.prompt;
// Escape double quotes so the suggested command is valid shell
const safePrompt = shortPrompt.replace(/"/g, '\\"');
console.log(`Rerun last: ${pc.cyan(`spawn ${latest.agent} ${latest.cloud} --prompt "${safePrompt}"`)}`);
} else {
console.log(`Rerun last: ${pc.cyan(`spawn ${latest.agent} ${latest.cloud}`)}`);
}
console.log(`Rerun last: ${pc.cyan(buildRetryCommand(latest.agent, latest.cloud, latest.prompt))}`);
if (agentFilter || cloudFilter) {
const totalRecords = filterHistory();