リトライ時でタスクにつめるようにする

This commit is contained in:
nrslib 2026-03-04 16:20:37 +09:00
parent 8ffe0592ef
commit 9fc8ab73fd
2 changed files with 38 additions and 12 deletions

View File

@ -2,7 +2,7 @@
* Tests for /retry slash command in the conversation loop.
*
* Verifies:
* - /retry with previousOrderContent returns execute action with order content
* - /retry with previousOrderContent uses post-summary action selection
* - /retry without previousOrderContent shows error and continues loop
* - /retry in retry mode with order.md context in system prompt
*/
@ -18,6 +18,7 @@ import {
createMockProvider,
type MockProviderCapture,
} from './helpers/stdinSimulator.js';
import { selectOption } from '../shared/prompt/index.js';
// --- Mocks (infrastructure only) ---
@ -147,7 +148,8 @@ describe('/retry slash command', () => {
rmSync(tmpDir, { recursive: true, force: true });
});
it('should execute with previous order content when /retry is used', async () => {
it('should route previous order content through action selection when /retry is used', async () => {
vi.mocked(selectOption).mockResolvedValueOnce('save_task');
const orderContent = '# Task Order\n\nImplement feature X with tests.';
setupRawStdin(toRawInputs(['/retry']));
setupProvider([]);
@ -155,7 +157,7 @@ describe('/retry slash command', () => {
const retryContext = buildRetryContext({ previousOrderContent: orderContent });
const result = await runRetryMode(tmpDir, retryContext, orderContent);
expect(result.action).toBe('execute');
expect(result.action).toBe('save_task');
expect(result.task).toBe(orderContent);
});
@ -170,6 +172,18 @@ describe('/retry slash command', () => {
expect(result.action).toBe('cancel');
});
it('should continue when /retry is selected with continue action', async () => {
vi.mocked(selectOption).mockResolvedValueOnce('continue');
setupRawStdin(toRawInputs(['/retry', '/cancel']));
setupProvider([]);
const orderContent = '# Task Order\n\nImplement feature X with tests.';
const retryContext = buildRetryContext({ previousOrderContent: orderContent });
const result = await runRetryMode(tmpDir, retryContext, orderContent);
expect(result.action).toBe('cancel');
});
it('should inject order.md content into retry system prompt', async () => {
const orderContent = '# Build login page\n\nWith OAuth2 support.';
setupRawStdin(toRawInputs(['check the order', '/cancel']));

View File

@ -144,6 +144,18 @@ export async function runConversationLoop(
}
}
async function handleSummaryAction(task: string): Promise<InteractiveModeResult | null> {
const selectedAction = strategy.selectAction
? await strategy.selectAction(task, ctx.lang)
: await selectPostSummaryAction(task, ui.proposed, ui);
if (selectedAction === 'continue' || selectedAction === null) {
info(ui.continuePrompt);
return null;
}
log.info('Conversation action selected', { action: selectedAction, messageCount: history.length });
return { action: selectedAction, task };
}
while (true) {
const input = await readMultilineInput(chalk.green('> '));
@ -203,8 +215,12 @@ export async function runConversationLoop(
info(ui.retryNoOrder);
continue;
}
log.info('Retry command — resubmitting previous order.md');
return { action: 'execute', task: strategy.previousOrderContent };
log.info('Retry command — using previous order.md');
const selectedAction = await handleSummaryAction(strategy.previousOrderContent);
if (selectedAction === null) {
continue;
}
return selectedAction;
}
case SlashCommand.Go: {
@ -234,15 +250,11 @@ export async function runConversationLoop(
return { action: 'cancel', task: '' };
}
const task = summaryResult.content.trim();
const selectedAction = strategy.selectAction
? await strategy.selectAction(task, ctx.lang)
: await selectPostSummaryAction(task, ui.proposed, ui);
if (selectedAction === 'continue' || selectedAction === null) {
info(ui.continuePrompt);
const selectedAction = await handleSummaryAction(task);
if (selectedAction === null) {
continue;
}
log.info('Conversation action selected', { action: selectedAction, messageCount: history.length });
return { action: selectedAction, task };
return selectedAction;
}
case SlashCommand.Replay: {