/review に instruct アクションを追加
worktree レビュー時に追加指示を出せる機能を追加。 - 「Instruct」を選択 → 指示入力 → ワークフロー選択 → 実行 → 自動コミット - selectWorkflowForInstruction() でワークフロー選択 - instructWorktree() でタスク実行と自動コミットを処理
This commit is contained in:
parent
277d490eeb
commit
42ae981b65
@ -170,9 +170,10 @@ describe('buildReviewItems', () => {
|
||||
});
|
||||
|
||||
describe('ReviewAction type', () => {
|
||||
it('should include try, merge, delete (no skip)', () => {
|
||||
const actions: ReviewAction[] = ['try', 'merge', 'delete'];
|
||||
expect(actions).toHaveLength(3);
|
||||
it('should include instruct, try, merge, delete (no skip)', () => {
|
||||
const actions: ReviewAction[] = ['instruct', 'try', 'merge', 'delete'];
|
||||
expect(actions).toHaveLength(4);
|
||||
expect(actions).toContain('instruct');
|
||||
expect(actions).toContain('try');
|
||||
expect(actions).not.toContain('skip');
|
||||
});
|
||||
|
||||
@ -14,14 +14,19 @@ import {
|
||||
buildReviewItems,
|
||||
type WorktreeReviewItem,
|
||||
} from '../task/worktree.js';
|
||||
import { selectOption, confirm } from '../prompt/index.js';
|
||||
import { selectOption, confirm, promptInput } from '../prompt/index.js';
|
||||
import { info, success, error as logError, warn } from '../utils/ui.js';
|
||||
import { createLogger } from '../utils/debug.js';
|
||||
import { executeTask } from './taskExecution.js';
|
||||
import { autoCommitWorktree } from '../task/autoCommit.js';
|
||||
import { listWorkflows } from '../config/workflowLoader.js';
|
||||
import { getCurrentWorkflow } from '../config/paths.js';
|
||||
import { DEFAULT_WORKFLOW_NAME } from '../constants.js';
|
||||
|
||||
const log = createLogger('review-tasks');
|
||||
|
||||
/** Actions available for a reviewed worktree */
|
||||
export type ReviewAction = 'try' | 'merge' | 'delete';
|
||||
export type ReviewAction = 'try' | 'merge' | 'delete' | 'instruct';
|
||||
|
||||
/**
|
||||
* Check if a branch has already been merged into HEAD.
|
||||
@ -66,6 +71,7 @@ async function showDiffAndPromptAction(
|
||||
const action = await selectOption<ReviewAction>(
|
||||
`Action for ${item.info.branch}:`,
|
||||
[
|
||||
{ label: 'Instruct', value: 'instruct', description: 'Give additional instructions to modify this worktree' },
|
||||
{ label: 'Try merge', value: 'try', description: 'Merge without cleanup (keep worktree & branch)' },
|
||||
{ label: 'Merge & cleanup', value: 'merge', description: 'Merge (if needed) and remove worktree & branch' },
|
||||
{ label: 'Delete', value: 'delete', description: 'Discard changes, remove worktree and branch' },
|
||||
@ -176,6 +182,80 @@ export function deleteWorktreeBranch(projectDir: string, item: WorktreeReviewIte
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the workflow to use for instruction.
|
||||
* If multiple workflows available, prompt user to select.
|
||||
*/
|
||||
async function selectWorkflowForInstruction(projectDir: string): Promise<string | null> {
|
||||
const availableWorkflows = listWorkflows();
|
||||
const currentWorkflow = getCurrentWorkflow(projectDir);
|
||||
|
||||
if (availableWorkflows.length === 0) {
|
||||
return DEFAULT_WORKFLOW_NAME;
|
||||
}
|
||||
|
||||
if (availableWorkflows.length === 1 && availableWorkflows[0]) {
|
||||
return availableWorkflows[0];
|
||||
}
|
||||
|
||||
// Multiple workflows: let user select
|
||||
const options = availableWorkflows.map((name) => ({
|
||||
label: name === currentWorkflow ? `${name} (current)` : name,
|
||||
value: name,
|
||||
}));
|
||||
|
||||
return await selectOption('Select workflow:', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct worktree: give additional instructions to modify the worktree.
|
||||
* Executes a task on the worktree and auto-commits if successful.
|
||||
*/
|
||||
export async function instructWorktree(
|
||||
projectDir: string,
|
||||
item: WorktreeReviewItem,
|
||||
): Promise<boolean> {
|
||||
const { branch } = item.info;
|
||||
const worktreePath = item.info.path;
|
||||
|
||||
// 1. Prompt for instruction
|
||||
const instruction = await promptInput('Enter instruction');
|
||||
if (!instruction) {
|
||||
info('Cancelled');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Select workflow
|
||||
const selectedWorkflow = await selectWorkflowForInstruction(projectDir);
|
||||
if (!selectedWorkflow) {
|
||||
info('Cancelled');
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info('Instructing worktree', { branch, worktreePath, workflow: selectedWorkflow });
|
||||
info(`Running instruction on ${branch}...`);
|
||||
|
||||
// 3. Execute task on worktree
|
||||
const taskSuccess = await executeTask(instruction, worktreePath, selectedWorkflow, projectDir);
|
||||
|
||||
// 4. Auto-commit if successful
|
||||
if (taskSuccess) {
|
||||
const commitResult = autoCommitWorktree(worktreePath, item.taskSlug);
|
||||
if (commitResult.success && commitResult.commitHash) {
|
||||
info(`Auto-committed: ${commitResult.commitHash}`);
|
||||
} else if (!commitResult.success) {
|
||||
warn(`Auto-commit skipped: ${commitResult.message}`);
|
||||
}
|
||||
success(`Instruction completed on ${branch}`);
|
||||
log.info('Instruction completed', { branch });
|
||||
} else {
|
||||
logError(`Instruction failed on ${branch}`);
|
||||
log.error('Instruction failed', { branch });
|
||||
}
|
||||
|
||||
return taskSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point: review worktree tasks interactively.
|
||||
*/
|
||||
@ -219,6 +299,9 @@ export async function reviewTasks(cwd: string): Promise<void> {
|
||||
if (action === null) continue;
|
||||
|
||||
switch (action) {
|
||||
case 'instruct':
|
||||
await instructWorktree(cwd, item);
|
||||
break;
|
||||
case 'try':
|
||||
tryMergeWorktreeBranch(cwd, item);
|
||||
break;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user