mirror of
https://github.com/jparkerweb/plan2code.git
synced 2026-07-21 18:33:22 -07:00
feat: add plan2code-bot with --resume capability and state cleanup
Add the autonomous workflow test runner (plan2code-bot) that uses the Claude Agent SDK to run plan2code end-to-end. Includes --resume flag to continue incomplete runs from saved state, and automatic state file cleanup on successful completion.
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createAutoResponder } from './auto-responder.js';
|
||||
import type { BotConfig } from './types.js';
|
||||
|
||||
const config: BotConfig = {
|
||||
workDir: '/tmp/work',
|
||||
projectDir: '/tmp/work/my-app',
|
||||
ideaDescription: 'A test app',
|
||||
ideaName: 'test-app',
|
||||
mode: 'new-project',
|
||||
};
|
||||
|
||||
describe('createAutoResponder', () => {
|
||||
it('returns allow for non-AskUserQuestion tools', async () => {
|
||||
const responder = createAutoResponder(config, 'plan');
|
||||
const result = await responder('Bash', { command: 'ls' });
|
||||
expect(result.behavior).toBe('allow');
|
||||
expect((result as any).updatedInput).toBeUndefined();
|
||||
});
|
||||
|
||||
it('injects answers for AskUserQuestion with approval keywords', async () => {
|
||||
const responder = createAutoResponder(config, 'plan');
|
||||
const result = await responder('AskUserQuestion', {
|
||||
questions: [
|
||||
{
|
||||
question: 'Do you approve this plan?',
|
||||
options: [
|
||||
{ label: 'Yes', description: 'Approve' },
|
||||
{ label: 'No', description: 'Reject' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.behavior).toBe('allow');
|
||||
const updated = (result as any).updatedInput;
|
||||
expect(updated.answers['Do you approve this plan?']).toBe('Yes');
|
||||
});
|
||||
|
||||
it('selects skip/none for testing questions', async () => {
|
||||
const responder = createAutoResponder(config, 'implement');
|
||||
const result = await responder('AskUserQuestion', {
|
||||
questions: [
|
||||
{
|
||||
question: 'How should we run tests?',
|
||||
options: [
|
||||
{ label: 'Full suite', description: 'Run all tests' },
|
||||
{ label: 'Skip', description: 'Skip testing' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.behavior).toBe('allow');
|
||||
const updated = (result as any).updatedInput;
|
||||
expect(updated.answers['How should we run tests?']).toBe('Skip');
|
||||
});
|
||||
|
||||
it('uses project name for plan step name questions', async () => {
|
||||
const responder = createAutoResponder(config, 'plan');
|
||||
const result = await responder('AskUserQuestion', {
|
||||
questions: [
|
||||
{
|
||||
question: 'What is the name of this feature?',
|
||||
options: [
|
||||
{ label: 'Feature A', description: 'First' },
|
||||
{ label: 'Feature B', description: 'Second' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.behavior).toBe('allow');
|
||||
const updated = (result as any).updatedInput;
|
||||
// Plan step + "name" keyword → uses config.ideaName
|
||||
expect(updated.answers['What is the name of this feature?']).toBe('test-app');
|
||||
});
|
||||
|
||||
it('falls back to first option for unknown questions', async () => {
|
||||
const responder = createAutoResponder(config, 'init');
|
||||
const result = await responder('AskUserQuestion', {
|
||||
questions: [
|
||||
{
|
||||
question: 'What color is the sky?',
|
||||
options: [
|
||||
{ label: 'Blue', description: 'The usual' },
|
||||
{ label: 'Red', description: 'Sunset' },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.behavior).toBe('allow');
|
||||
const updated = (result as any).updatedInput;
|
||||
expect(updated.answers['What color is the sky?']).toBe('Blue');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user