takt: ワークフロー選択時にescキーをおしたらキャンセルにしてほしい。
This commit is contained in:
parent
4ebee4f5af
commit
e8a8044c9f
@ -315,5 +315,30 @@ describe('prompt', () => {
|
|||||||
const result = await selectOptionWithDefault('Test:', [], 'fallback');
|
const result = await selectOptionWithDefault('Test:', [], 'fallback');
|
||||||
expect(result).toBe('fallback');
|
expect(result).toBe('fallback');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should have return type that allows null (cancel)', async () => {
|
||||||
|
const { selectOptionWithDefault } = await import('../prompt/index.js');
|
||||||
|
// When options are empty, default is returned (not null)
|
||||||
|
const result: string | null = await selectOptionWithDefault('Test:', [], 'fallback');
|
||||||
|
expect(result).toBe('fallback');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectOptionWithDefault cancel behavior', () => {
|
||||||
|
it('handleKeyInput should return cancel with optionCount when hasCancelOption is true', () => {
|
||||||
|
// Simulates ESC key press with cancel option enabled (as selectOptionWithDefault now does)
|
||||||
|
const result = handleKeyInput('\x1B', 0, 4, true, 3);
|
||||||
|
expect(result).toEqual({ action: 'cancel', cancelIndex: 3 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handleKeyInput should support navigating to Cancel item', () => {
|
||||||
|
// With 3 options + cancel, totalItems = 4, cancel is at index 3
|
||||||
|
const downResult = handleKeyInput('\x1B[B', 2, 4, true, 3);
|
||||||
|
expect(downResult).toEqual({ action: 'move', newIndex: 3 });
|
||||||
|
|
||||||
|
// Confirming on cancel index (3) should return confirm with selectedIndex 3
|
||||||
|
const confirmResult = handleKeyInput('\r', 3, 4, true, 3);
|
||||||
|
expect(confirmResult).toEqual({ action: 'confirm', selectedIndex: 3 });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -163,11 +163,18 @@ program
|
|||||||
? DEFAULT_WORKFLOW_NAME
|
? DEFAULT_WORKFLOW_NAME
|
||||||
: availableWorkflows[0] || DEFAULT_WORKFLOW_NAME);
|
: availableWorkflows[0] || DEFAULT_WORKFLOW_NAME);
|
||||||
|
|
||||||
selectedWorkflow = await selectOptionWithDefault(
|
const selected = await selectOptionWithDefault(
|
||||||
'Select workflow:',
|
'Select workflow:',
|
||||||
options,
|
options,
|
||||||
defaultWorkflow
|
defaultWorkflow
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (selected === null) {
|
||||||
|
info('Cancelled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedWorkflow = selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('Starting task execution', { task, workflow: selectedWorkflow });
|
log.info('Starting task execution', { task, workflow: selectedWorkflow });
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export function needsLanguageSetup(): boolean {
|
|||||||
/**
|
/**
|
||||||
* Prompt user to select language for resources.
|
* Prompt user to select language for resources.
|
||||||
* Returns 'en' for English (default), 'ja' for Japanese.
|
* Returns 'en' for English (default), 'ja' for Japanese.
|
||||||
|
* Exits process if cancelled (initial setup is required).
|
||||||
*/
|
*/
|
||||||
export async function promptLanguageSelection(): Promise<Language> {
|
export async function promptLanguageSelection(): Promise<Language> {
|
||||||
const options: { label: string; value: Language }[] = [
|
const options: { label: string; value: Language }[] = [
|
||||||
@ -44,15 +45,22 @@ export async function promptLanguageSelection(): Promise<Language> {
|
|||||||
{ label: '日本語 (Japanese)', value: 'ja' },
|
{ label: '日本語 (Japanese)', value: 'ja' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return await selectOptionWithDefault(
|
const result = await selectOptionWithDefault(
|
||||||
'Select language for default agents and workflows / デフォルトのエージェントとワークフローの言語を選択してください:',
|
'Select language for default agents and workflows / デフォルトのエージェントとワークフローの言語を選択してください:',
|
||||||
options,
|
options,
|
||||||
DEFAULT_LANGUAGE
|
DEFAULT_LANGUAGE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompt user to select provider for resources.
|
* Prompt user to select provider for resources.
|
||||||
|
* Exits process if cancelled (initial setup is required).
|
||||||
*/
|
*/
|
||||||
export async function promptProviderSelection(): Promise<'claude' | 'codex'> {
|
export async function promptProviderSelection(): Promise<'claude' | 'codex'> {
|
||||||
const options: { label: string; value: 'claude' | 'codex' }[] = [
|
const options: { label: string; value: 'claude' | 'codex' }[] = [
|
||||||
@ -60,11 +68,17 @@ export async function promptProviderSelection(): Promise<'claude' | 'codex'> {
|
|||||||
{ label: 'Codex', value: 'codex' },
|
{ label: 'Codex', value: 'codex' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return await selectOptionWithDefault(
|
const result = await selectOptionWithDefault(
|
||||||
'Select provider (Claude Code or Codex) / プロバイダーを選択してください:',
|
'Select provider (Claude Code or Codex) / プロバイダーを選択してください:',
|
||||||
options,
|
options,
|
||||||
'claude'
|
'claude'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -275,13 +275,13 @@ export async function promptInput(message: string): Promise<string | null> {
|
|||||||
/**
|
/**
|
||||||
* Prompt user to select from a list of options with a default value.
|
* Prompt user to select from a list of options with a default value.
|
||||||
* Uses cursor navigation. Enter immediately selects the default.
|
* Uses cursor navigation. Enter immediately selects the default.
|
||||||
* @returns Selected option value
|
* @returns Selected option value, or null if cancelled (ESC pressed)
|
||||||
*/
|
*/
|
||||||
export async function selectOptionWithDefault<T extends string>(
|
export async function selectOptionWithDefault<T extends string>(
|
||||||
message: string,
|
message: string,
|
||||||
options: { label: string; value: T }[],
|
options: { label: string; value: T }[],
|
||||||
defaultValue: T
|
defaultValue: T
|
||||||
): Promise<T> {
|
): Promise<T | null> {
|
||||||
if (options.length === 0) return defaultValue;
|
if (options.length === 0) return defaultValue;
|
||||||
|
|
||||||
// Find default index
|
// Find default index
|
||||||
@ -294,12 +294,11 @@ export async function selectOptionWithDefault<T extends string>(
|
|||||||
label: opt.value === defaultValue ? `${opt.label} ${chalk.green('(default)')}` : opt.label,
|
label: opt.value === defaultValue ? `${opt.label} ${chalk.green('(default)')}` : opt.label,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const selectedIndex = await interactiveSelect(message, decoratedOptions, initialIndex, false);
|
const selectedIndex = await interactiveSelect(message, decoratedOptions, initialIndex, true);
|
||||||
|
|
||||||
// Escape pressed - use default
|
// Cancel selected (last item) or Escape pressed
|
||||||
if (selectedIndex === -1) {
|
if (selectedIndex === options.length || selectedIndex === -1) {
|
||||||
console.log(chalk.gray(` Using default: ${defaultValue}`));
|
return null;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const selected = options[selectedIndex];
|
const selected = options[selectedIndex];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user