From 7193f96c77e92c9d067ef9cd3a0d4537c5576ee5 Mon Sep 17 00:00:00 2001 From: kyungseopk1m Date: Tue, 10 Nov 2026 23:04:34 +0900 Subject: [PATCH 1/3] fix(prompts): restore the formatInstructionFooter signature from 1.8 --- .changeset/instruction-footer-output-last.md | 5 ++++ packages/prompts/src/common.ts | 4 +-- packages/prompts/src/group-multi-select.ts | 2 +- packages/prompts/src/multi-select.ts | 2 +- packages/prompts/src/select.ts | 2 +- .../prompts/test/instruction-footer.test.ts | 26 +++++++++++++++++++ 6 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 .changeset/instruction-footer-output-last.md create mode 100644 packages/prompts/test/instruction-footer.test.ts diff --git a/.changeset/instruction-footer-output-last.md b/.changeset/instruction-footer-output-last.md new file mode 100644 index 00000000..a081494e --- /dev/null +++ b/.changeset/instruction-footer-output-last.md @@ -0,0 +1,5 @@ +--- +"@clack/prompts": patch +--- + +Restore the `formatInstructionFooter(instructions, hasGuide)` signature from 1.8. The `output` stream added in 1.9.0 is now an optional third argument instead of the first, so existing two-argument calls work again. diff --git a/packages/prompts/src/common.ts b/packages/prompts/src/common.ts index 730c448d..e5f791fd 100644 --- a/packages/prompts/src/common.ts +++ b/packages/prompts/src/common.ts @@ -79,9 +79,9 @@ export interface CommonOptions { } export function formatInstructionFooter( - output: Writable | undefined, instructions: string[], - hasGuide: boolean + hasGuide: boolean, + output?: Writable ): string[] { const guidePrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : ''; const footerLines = wrapTextWithPrefix(output, instructions.join(' • '), guidePrefix).split('\n'); diff --git a/packages/prompts/src/group-multi-select.ts b/packages/prompts/src/group-multi-select.ts index e53bc97f..2e5cbeb5 100644 --- a/packages/prompts/src/group-multi-select.ts +++ b/packages/prompts/src/group-multi-select.ts @@ -297,7 +297,7 @@ export const groupMultiselect = (opts: GroupMultiSelectOptions) => const guidePrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : ''; const titleLineCount = title.split('\n').length; const footerLines = showInstructions - ? formatInstructionFooter(opts.output, MULTISELECT_INSTRUCTIONS, hasGuide) + ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, hasGuide, opts.output) : hasGuide ? [styleText('cyan', S_BAR_END)] : []; diff --git a/packages/prompts/src/multi-select.ts b/packages/prompts/src/multi-select.ts index b20209af..68d73c31 100644 --- a/packages/prompts/src/multi-select.ts +++ b/packages/prompts/src/multi-select.ts @@ -187,7 +187,7 @@ export const multiselect = (opts: MultiSelectOptions) => { const prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : ''; const titleLineCount = title.split('\n').length; const footerLines = showInstructions - ? formatInstructionFooter(opts.output, MULTISELECT_INSTRUCTIONS, hasGuide) + ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, hasGuide, opts.output) : hasGuide ? [styleText('cyan', S_BAR_END)] : []; diff --git a/packages/prompts/src/select.ts b/packages/prompts/src/select.ts index 804e5817..e4a012d5 100644 --- a/packages/prompts/src/select.ts +++ b/packages/prompts/src/select.ts @@ -164,7 +164,7 @@ export const select = (opts: SelectOptions) => { const prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : ''; const titleLineCount = title.split('\n').length; const footerLines = showInstructions - ? formatInstructionFooter(opts.output, SELECT_INSTRUCTIONS, hasGuide) + ? formatInstructionFooter(SELECT_INSTRUCTIONS, hasGuide, opts.output) : hasGuide ? [styleText('cyan', S_BAR_END)] : []; diff --git a/packages/prompts/test/instruction-footer.test.ts b/packages/prompts/test/instruction-footer.test.ts new file mode 100644 index 00000000..8b4eedb4 --- /dev/null +++ b/packages/prompts/test/instruction-footer.test.ts @@ -0,0 +1,26 @@ +import { styleText } from 'node:util'; +import { describe, expect, test } from 'vitest'; +import { formatInstructionFooter, S_BAR, S_BAR_END } from '../src/index.js'; +import { MockWritable } from './test-utils.js'; + +describe('formatInstructionFooter', () => { + test('accepts the two-argument form', () => { + expect(formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], true)).toEqual([ + `${styleText('cyan', S_BAR)} ↑/↓ navigate • Enter confirm`, + styleText('cyan', S_BAR_END), + ]); + }); + + test('omits the guide lines without a guide', () => { + expect(formatInstructionFooter(['Enter confirm'], false)).toEqual(['Enter confirm']); + }); + + test('wraps to the width of the given output', () => { + const output = new MockWritable(); + output.columns = 20; + const lines = formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], false, output); + expect(lines.length).toBeGreaterThan(1); + for (const line of lines) expect(line.trimEnd().length).toBeLessThanOrEqual(20); + expect(lines.join('')).toBe('↑/↓ navigate • Enter confirm'); + }); +}); From 5b825fee8710a338cb16dca4ffdb88405d44787d Mon Sep 17 00:00:00 2001 From: kyungseopk1m Date: Wed, 11 Nov 2026 11:08:44 +0900 Subject: [PATCH 2/3] test(prompts): move formatInstructionFooter tests into select.test.ts --- .../test/__snapshots__/select.test.ts.snap | 14 ++++++++++ .../prompts/test/instruction-footer.test.ts | 26 ------------------- packages/prompts/test/select.test.ts | 16 ++++++++++++ 3 files changed, 30 insertions(+), 26 deletions(-) delete mode 100644 packages/prompts/test/instruction-footer.test.ts diff --git a/packages/prompts/test/__snapshots__/select.test.ts.snap b/packages/prompts/test/__snapshots__/select.test.ts.snap index 6506b973..ae143c88 100644 --- a/packages/prompts/test/__snapshots__/select.test.ts.snap +++ b/packages/prompts/test/__snapshots__/select.test.ts.snap @@ -1,5 +1,19 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`formatInstructionFooter > accepts the two-argument form 1`] = ` +[ + "│ ↑/↓ navigate • Enter confirm", + "└", +] +`; + +exports[`formatInstructionFooter > wraps to the width of the given output 1`] = ` +[ + "↑/↓ navigate • Enter", + " confirm", +] +`; + exports[`select (isCI = false) > can be aborted by a signal 1`] = ` [ "", diff --git a/packages/prompts/test/instruction-footer.test.ts b/packages/prompts/test/instruction-footer.test.ts deleted file mode 100644 index 8b4eedb4..00000000 --- a/packages/prompts/test/instruction-footer.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { styleText } from 'node:util'; -import { describe, expect, test } from 'vitest'; -import { formatInstructionFooter, S_BAR, S_BAR_END } from '../src/index.js'; -import { MockWritable } from './test-utils.js'; - -describe('formatInstructionFooter', () => { - test('accepts the two-argument form', () => { - expect(formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], true)).toEqual([ - `${styleText('cyan', S_BAR)} ↑/↓ navigate • Enter confirm`, - styleText('cyan', S_BAR_END), - ]); - }); - - test('omits the guide lines without a guide', () => { - expect(formatInstructionFooter(['Enter confirm'], false)).toEqual(['Enter confirm']); - }); - - test('wraps to the width of the given output', () => { - const output = new MockWritable(); - output.columns = 20; - const lines = formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], false, output); - expect(lines.length).toBeGreaterThan(1); - for (const line of lines) expect(line.trimEnd().length).toBeLessThanOrEqual(20); - expect(lines.join('')).toBe('↑/↓ navigate • Enter confirm'); - }); -}); diff --git a/packages/prompts/test/select.test.ts b/packages/prompts/test/select.test.ts index fc3a1751..b5490cc5 100644 --- a/packages/prompts/test/select.test.ts +++ b/packages/prompts/test/select.test.ts @@ -418,3 +418,19 @@ describe.each(['true', 'false'])('select (isCI = %s)', (isCI) => { expect(output.buffer).toMatchSnapshot(); }); }); + +describe('formatInstructionFooter', () => { + test('accepts the two-argument form', () => { + expect( + prompts.formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], true) + ).toMatchSnapshot(); + }); + + test('wraps to the width of the given output', () => { + const output = new MockWritable(); + output.columns = 20; + expect( + prompts.formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], false, output) + ).toMatchSnapshot(); + }); +}); From 70f092e2bed85bdf20e78114f27de7f41c7bbacd Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Wed, 11 Nov 2026 10:04:05 +0000 Subject: [PATCH 3/3] test: unnecessary tests dropped This test is purely testing that the argument order changed, which makes no sense when this isn't a question of backwards compat of any kind. Agents going off on one as per. --- .../test/__snapshots__/select.test.ts.snap | 14 -------------- packages/prompts/test/select.test.ts | 16 ---------------- 2 files changed, 30 deletions(-) diff --git a/packages/prompts/test/__snapshots__/select.test.ts.snap b/packages/prompts/test/__snapshots__/select.test.ts.snap index ae143c88..6506b973 100644 --- a/packages/prompts/test/__snapshots__/select.test.ts.snap +++ b/packages/prompts/test/__snapshots__/select.test.ts.snap @@ -1,19 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`formatInstructionFooter > accepts the two-argument form 1`] = ` -[ - "│ ↑/↓ navigate • Enter confirm", - "└", -] -`; - -exports[`formatInstructionFooter > wraps to the width of the given output 1`] = ` -[ - "↑/↓ navigate • Enter", - " confirm", -] -`; - exports[`select (isCI = false) > can be aborted by a signal 1`] = ` [ "", diff --git a/packages/prompts/test/select.test.ts b/packages/prompts/test/select.test.ts index b5490cc5..fc3a1751 100644 --- a/packages/prompts/test/select.test.ts +++ b/packages/prompts/test/select.test.ts @@ -418,19 +418,3 @@ describe.each(['true', 'false'])('select (isCI = %s)', (isCI) => { expect(output.buffer).toMatchSnapshot(); }); }); - -describe('formatInstructionFooter', () => { - test('accepts the two-argument form', () => { - expect( - prompts.formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], true) - ).toMatchSnapshot(); - }); - - test('wraps to the width of the given output', () => { - const output = new MockWritable(); - output.columns = 20; - expect( - prompts.formatInstructionFooter(['↑/↓ navigate', 'Enter confirm'], false, output) - ).toMatchSnapshot(); - }); -});