diff --git a/packages/cli/src/ui/components/AskUserDialog.test.tsx b/packages/cli/src/ui/components/AskUserDialog.test.tsx
index a30fb9b4af..63cf901235 100644
--- a/packages/cli/src/ui/components/AskUserDialog.test.tsx
+++ b/packages/cli/src/ui/components/AskUserDialog.test.tsx
@@ -1008,4 +1008,71 @@ describe('AskUserDialog', () => {
// Should contain the full long question (or at least its parts)
expect(lastFrame()).toContain('This is a very long question');
});
+
+ describe('Choice question placeholder', () => {
+ it('uses placeholder for "Other" option when provided', async () => {
+ const questions: Question[] = [
+ {
+ question: 'Select your preferred language:',
+ header: 'Language',
+ options: [
+ { label: 'TypeScript', description: '' },
+ { label: 'JavaScript', description: '' },
+ ],
+ placeholder: 'Type another language...',
+ multiSelect: false,
+ },
+ ];
+
+ const { stdin, lastFrame } = renderWithProviders(
+ ,
+ { width: 80 },
+ );
+
+ // Navigate to the "Other" option
+ writeKey(stdin, '\x1b[B'); // Down
+ writeKey(stdin, '\x1b[B'); // Down to Other
+
+ await waitFor(() => {
+ expect(lastFrame()).toMatchSnapshot();
+ });
+ });
+
+ it('uses default placeholder when not provided', async () => {
+ const questions: Question[] = [
+ {
+ question: 'Select your preferred language:',
+ header: 'Language',
+ options: [
+ { label: 'TypeScript', description: '' },
+ { label: 'JavaScript', description: '' },
+ ],
+ multiSelect: false,
+ },
+ ];
+
+ const { stdin, lastFrame } = renderWithProviders(
+ ,
+ { width: 80 },
+ );
+
+ // Navigate to the "Other" option
+ writeKey(stdin, '\x1b[B'); // Down
+ writeKey(stdin, '\x1b[B'); // Down to Other
+
+ await waitFor(() => {
+ expect(lastFrame()).toMatchSnapshot();
+ });
+ });
+ });
});
diff --git a/packages/cli/src/ui/components/AskUserDialog.tsx b/packages/cli/src/ui/components/AskUserDialog.tsx
index ba4c14510f..4c45b356fc 100644
--- a/packages/cli/src/ui/components/AskUserDialog.tsx
+++ b/packages/cli/src/ui/components/AskUserDialog.tsx
@@ -780,7 +780,7 @@ const ChoiceQuestionView: React.FC = ({
// Render inline text input for custom option
if (optionItem.type === 'other') {
- const placeholder = 'Enter a custom value';
+ const placeholder = question.placeholder || 'Enter a custom value';
return (
{showCheck && (
diff --git a/packages/cli/src/ui/components/__snapshots__/AskUserDialog.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AskUserDialog.test.tsx.snap
index 7f5d630bc1..e33d946d88 100644
--- a/packages/cli/src/ui/components/__snapshots__/AskUserDialog.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/AskUserDialog.test.tsx.snap
@@ -1,5 +1,25 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+exports[`AskUserDialog > Choice question placeholder > uses default placeholder when not provided 1`] = `
+"Select your preferred language:
+
+ 1. TypeScript
+ 2. JavaScript
+● 3. Enter a custom value
+
+Enter to submit · Esc to cancel"
+`;
+
+exports[`AskUserDialog > Choice question placeholder > uses placeholder for "Other" option when provided 1`] = `
+"Select your preferred language:
+
+ 1. TypeScript
+ 2. JavaScript
+● 3. Type another language...
+
+Enter to submit · Esc to cancel"
+`;
+
exports[`AskUserDialog > Scroll Arrows (useAlternateBuffer: false) > shows scroll arrows correctly when useAlternateBuffer is false 1`] = `
"Choose an option
diff --git a/packages/core/src/confirmation-bus/types.ts b/packages/core/src/confirmation-bus/types.ts
index fcdd600f3c..7debbb85da 100644
--- a/packages/core/src/confirmation-bus/types.ts
+++ b/packages/core/src/confirmation-bus/types.ts
@@ -148,7 +148,7 @@ export interface Question {
options?: QuestionOption[];
/** Allow multiple selections. Only applies when type='choice'. */
multiSelect?: boolean;
- /** Placeholder hint text. Only applies when type='text'. */
+ /** Placeholder hint text. For type='text', shown in the input field. For type='choice', shown in the "Other" custom input. */
placeholder?: string;
}
diff --git a/packages/core/src/tools/ask-user.test.ts b/packages/core/src/tools/ask-user.test.ts
index da41ff45f2..d747ed1d16 100644
--- a/packages/core/src/tools/ask-user.test.ts
+++ b/packages/core/src/tools/ask-user.test.ts
@@ -177,6 +177,24 @@ describe('AskUserTool', () => {
expect(result).toBeNull();
});
+ it('should accept placeholder for choice type', () => {
+ const result = tool.validateToolParams({
+ questions: [
+ {
+ question: 'Which language?',
+ header: 'Language',
+ type: QuestionType.CHOICE,
+ options: [
+ { label: 'TypeScript', description: 'Typed JavaScript' },
+ { label: 'JavaScript', description: 'Dynamic language' },
+ ],
+ placeholder: 'Type another language...',
+ },
+ ],
+ });
+ expect(result).toBeNull();
+ });
+
it('should return error if option has empty label', () => {
const result = tool.validateToolParams({
questions: [
diff --git a/packages/core/src/tools/ask-user.ts b/packages/core/src/tools/ask-user.ts
index c155dec4e9..601d80178b 100644
--- a/packages/core/src/tools/ask-user.ts
+++ b/packages/core/src/tools/ask-user.ts
@@ -90,7 +90,7 @@ export class AskUserTool extends BaseDeclarativeTool<
placeholder: {
type: 'string',
description:
- "Only applies when type='text'. Hint text shown in the input field.",
+ "Hint text shown in the input field. For type='text', shown in the main input. For type='choice', shown in the 'Other' custom input.",
},
},
},