diff --git a/.changeset/fix-multi-select-other-deselect.md b/.changeset/fix-multi-select-other-deselect.md new file mode 100644 index 000000000..6db9703fe --- /dev/null +++ b/.changeset/fix-multi-select-other-deselect.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Fix multi-select "Other" options so they can be deselected after being committed. diff --git a/apps/kimi-code/src/tui/components/dialogs/question-dialog.ts b/apps/kimi-code/src/tui/components/dialogs/question-dialog.ts index 6764b88d8..68187349c 100644 --- a/apps/kimi-code/src/tui/components/dialogs/question-dialog.ts +++ b/apps/kimi-code/src/tui/components/dialogs/question-dialog.ts @@ -299,6 +299,12 @@ export class QuestionDialogComponent extends Container implements Focusable { this.reviewMessage = undefined; if (this.isOtherOption(questionIdx, optionIdx)) { + if (question.multi_select && this.multiSelections[questionIdx]?.has(optionIdx)) { + this.multiSelections[questionIdx].delete(optionIdx); + this.lastAnswerMethod = method; + this.updateAnswer(questionIdx); + return; + } this.enterOtherInput(questionIdx); return; } diff --git a/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts b/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts index 812ac0d94..322d10e91 100644 --- a/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts +++ b/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts @@ -394,6 +394,42 @@ describe('QuestionDialogComponent', () => { expect(out).toContain('Mushroom'); }); + it('multi-select Other can be toggled off after it is committed', () => { + const pending = makePending([ + { + question: 'Pick toppings?', + multi_select: true, + options: [{ label: 'Cheese' }, { label: 'Pepperoni' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + // Select Other and commit a custom value. + dialog.handleInput('3'); + dialog.handleInput('M'); + dialog.handleInput('u'); + dialog.handleInput('s'); + dialog.handleInput('h'); + dialog.handleInput('r'); + dialog.handleInput('o'); + dialog.handleInput('o'); + dialog.handleInput('m'); + dialog.handleInput('\r'); + + // Toggle it off using the same key. + dialog.handleInput('3'); + // Select a preset option to confirm the answer still builds correctly. + dialog.handleInput('1'); + dialog.handleInput('\t'); + + const review = strip(dialog.render(80).join('\n')); + expect(review).toContain('Cheese'); + expect(review).not.toContain('Mushroom'); + + dialog.handleInput('1'); + expect(collected).toEqual([['Cheese']]); + }); + it('escape dismisses with empty answers array', () => { const pending = makePending([ {