--worktreeで対話スキップ --create-worktreeで対話スキップ
This commit is contained in:
parent
22e35be168
commit
d9786c11fb
@ -200,5 +200,25 @@ describe('confirmAndCreateWorktree', () => {
|
|||||||
// Then
|
// Then
|
||||||
expect(mockInfo).toHaveBeenCalledWith('Generating branch name...');
|
expect(mockInfo).toHaveBeenCalledWith('Generating branch name...');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip prompt when override is false', async () => {
|
||||||
|
const result = await confirmAndCreateWorktree('/project', 'task', false);
|
||||||
|
|
||||||
|
expect(result.execCwd).toBe('/project');
|
||||||
|
expect(result.isWorktree).toBe(false);
|
||||||
|
expect(mockConfirm).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip prompt when override is true and still create clone', async () => {
|
||||||
|
mockSummarizeTaskName.mockResolvedValue('task');
|
||||||
|
mockCreateSharedClone.mockReturnValue({
|
||||||
|
path: '/project/../20260128T0504-task',
|
||||||
|
branch: 'takt/20260128T0504-task',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await confirmAndCreateWorktree('/project', 'task', true);
|
||||||
|
|
||||||
|
expect(mockConfirm).not.toHaveBeenCalled();
|
||||||
|
expect(result.isWorktree).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
74
src/cli.ts
74
src/cli.ts
@ -107,20 +107,31 @@ async function selectWorkflow(cwd: string): Promise<string | null> {
|
|||||||
* Execute a task with workflow selection, optional worktree, and auto-commit.
|
* Execute a task with workflow selection, optional worktree, and auto-commit.
|
||||||
* Shared by direct task execution and interactive mode.
|
* Shared by direct task execution and interactive mode.
|
||||||
*/
|
*/
|
||||||
|
export interface SelectAndExecuteOptions {
|
||||||
|
autoPr?: boolean;
|
||||||
|
repo?: string;
|
||||||
|
workflow?: string;
|
||||||
|
createWorktree?: boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
async function selectAndExecuteTask(
|
async function selectAndExecuteTask(
|
||||||
cwd: string,
|
cwd: string,
|
||||||
task: string,
|
task: string,
|
||||||
options?: { autoPr?: boolean; repo?: string },
|
options?: SelectAndExecuteOptions,
|
||||||
agentOverrides?: TaskExecutionOptions,
|
agentOverrides?: TaskExecutionOptions,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const selectedWorkflow = await selectWorkflow(cwd);
|
const selectedWorkflow = await determineWorkflow(cwd, options?.workflow);
|
||||||
|
|
||||||
if (selectedWorkflow === null) {
|
if (selectedWorkflow === null) {
|
||||||
info('Cancelled');
|
info('Cancelled');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { execCwd, isWorktree, branch } = await confirmAndCreateWorktree(cwd, task);
|
const { execCwd, isWorktree, branch } = await confirmAndCreateWorktree(
|
||||||
|
cwd,
|
||||||
|
task,
|
||||||
|
options?.createWorktree,
|
||||||
|
);
|
||||||
|
|
||||||
log.info('Starting task execution', { workflow: selectedWorkflow, worktree: isWorktree });
|
log.info('Starting task execution', { workflow: selectedWorkflow, worktree: isWorktree });
|
||||||
const taskSuccess = await executeTask(task, execCwd, selectedWorkflow, cwd, agentOverrides);
|
const taskSuccess = await executeTask(task, execCwd, selectedWorkflow, cwd, agentOverrides);
|
||||||
@ -164,11 +175,28 @@ async function selectAndExecuteTask(
|
|||||||
* Returns the execution directory and whether a clone was created.
|
* Returns the execution directory and whether a clone was created.
|
||||||
* Task name is summarized to English by AI for use in branch/clone names.
|
* Task name is summarized to English by AI for use in branch/clone names.
|
||||||
*/
|
*/
|
||||||
|
async function determineWorkflow(cwd: string, override?: string): Promise<string | null> {
|
||||||
|
if (override) {
|
||||||
|
const availableWorkflows = listWorkflows();
|
||||||
|
const knownWorkflows = availableWorkflows.length === 0 ? [DEFAULT_WORKFLOW_NAME] : availableWorkflows;
|
||||||
|
if (!knownWorkflows.includes(override)) {
|
||||||
|
error(`Workflow not found: ${override}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return override;
|
||||||
|
}
|
||||||
|
return selectWorkflow(cwd);
|
||||||
|
}
|
||||||
|
|
||||||
export async function confirmAndCreateWorktree(
|
export async function confirmAndCreateWorktree(
|
||||||
cwd: string,
|
cwd: string,
|
||||||
task: string,
|
task: string,
|
||||||
|
createWorktreeOverride?: boolean | undefined,
|
||||||
): Promise<WorktreeConfirmationResult> {
|
): Promise<WorktreeConfirmationResult> {
|
||||||
const useWorktree = await confirm('Create worktree?', true);
|
const useWorktree =
|
||||||
|
typeof createWorktreeOverride === 'boolean'
|
||||||
|
? createWorktreeOverride
|
||||||
|
: await confirm('Create worktree?', true);
|
||||||
|
|
||||||
if (!useWorktree) {
|
if (!useWorktree) {
|
||||||
return { execCwd: cwd, isWorktree: false };
|
return { execCwd: cwd, isWorktree: false };
|
||||||
@ -201,6 +229,23 @@ function resolveAgentOverrides(): TaskExecutionOptions | undefined {
|
|||||||
return { provider, model };
|
return { provider, model };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseCreateWorktreeOption(value?: string): boolean | undefined {
|
||||||
|
if (!value) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = value.toLowerCase();
|
||||||
|
if (normalized === 'yes' || normalized === 'true') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (normalized === 'no' || normalized === 'false') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
error('Invalid value for --create-worktree. Use yes or no.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
program
|
program
|
||||||
.name('takt')
|
.name('takt')
|
||||||
.description('TAKT: Task Agent Koordination Tool')
|
.description('TAKT: Task Agent Koordination Tool')
|
||||||
@ -216,7 +261,8 @@ program
|
|||||||
.option('--provider <name>', 'Override agent provider (claude|codex|mock)')
|
.option('--provider <name>', 'Override agent provider (claude|codex|mock)')
|
||||||
.option('--model <name>', 'Override agent model')
|
.option('--model <name>', 'Override agent model')
|
||||||
.option('-t, --task <string>', 'Task content (triggers pipeline/non-interactive mode)')
|
.option('-t, --task <string>', 'Task content (triggers pipeline/non-interactive mode)')
|
||||||
.option('--skip-git', 'Skip branch creation, commit, and push (pipeline mode)');
|
.option('--skip-git', 'Skip branch creation, commit, and push (pipeline mode)')
|
||||||
|
.option('--create-worktree <yes|no>', 'Skip the worktree prompt by explicitly specifying yes or no');
|
||||||
|
|
||||||
// Common initialization for all commands
|
// Common initialization for all commands
|
||||||
program.hook('preAction', async () => {
|
program.hook('preAction', async () => {
|
||||||
@ -336,6 +382,13 @@ program
|
|||||||
.action(async (task?: string) => {
|
.action(async (task?: string) => {
|
||||||
const opts = program.opts();
|
const opts = program.opts();
|
||||||
const agentOverrides = resolveAgentOverrides();
|
const agentOverrides = resolveAgentOverrides();
|
||||||
|
const createWorktreeOverride = parseCreateWorktreeOption(opts.createWorktree as string | undefined);
|
||||||
|
const selectOptions: SelectAndExecuteOptions = {
|
||||||
|
autoPr: opts.autoPr === true,
|
||||||
|
repo: opts.repo as string | undefined,
|
||||||
|
workflow: opts.workflow as string | undefined,
|
||||||
|
createWorktree: createWorktreeOverride,
|
||||||
|
};
|
||||||
|
|
||||||
// --- Pipeline mode (non-interactive): triggered by --task ---
|
// --- Pipeline mode (non-interactive): triggered by --task ---
|
||||||
if (pipelineMode) {
|
if (pipelineMode) {
|
||||||
@ -360,17 +413,12 @@ program
|
|||||||
|
|
||||||
// --- Normal (interactive) mode ---
|
// --- Normal (interactive) mode ---
|
||||||
|
|
||||||
const prOptions = {
|
|
||||||
autoPr: opts.autoPr === true,
|
|
||||||
repo: opts.repo as string | undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resolve --issue N to task text (same as #N)
|
// Resolve --issue N to task text (same as #N)
|
||||||
const issueFromOption = opts.issue as number | undefined;
|
const issueFromOption = opts.issue as number | undefined;
|
||||||
if (issueFromOption) {
|
if (issueFromOption) {
|
||||||
try {
|
try {
|
||||||
const resolvedTask = resolveIssueTask(`#${issueFromOption}`);
|
const resolvedTask = resolveIssueTask(`#${issueFromOption}`);
|
||||||
await selectAndExecuteTask(resolvedCwd, resolvedTask, prOptions, agentOverrides);
|
await selectAndExecuteTask(resolvedCwd, resolvedTask, selectOptions, agentOverrides);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error(e instanceof Error ? e.message : String(e));
|
error(e instanceof Error ? e.message : String(e));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -391,7 +439,7 @@ program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await selectAndExecuteTask(resolvedCwd, resolvedTask, prOptions, agentOverrides);
|
await selectAndExecuteTask(resolvedCwd, resolvedTask, selectOptions, agentOverrides);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +450,7 @@ program
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await selectAndExecuteTask(resolvedCwd, result.task, prOptions, agentOverrides);
|
await selectAndExecuteTask(resolvedCwd, result.task, selectOptions, agentOverrides);
|
||||||
});
|
});
|
||||||
|
|
||||||
program.parse();
|
program.parse();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user