I1: DX floor actor strips the editor hint from the footer line only (from #2971)

The custom-field reply normalization removed 'ctrl+g to edit in <editor>'
from every line, so question text that resembled the menu footer could be
rewritten and still authenticate. Only the last non-empty line is the
footer. Ported from Garry's #2971 with its negative control.
This commit is contained in:
garrytan committed 2026-10-03 22:36:46 +00:00
1 parent 5299cdad0c
commit 76f15815d3
2 files changed
+15 -3

No files matched your search

+4 -3
View File
@@ -120,9 +120,10 @@ export function planFloorDXReplyInput(visible: string, call: NativePlanQuestionC
const first = lines.findIndex(line => /^ 1\. /.test(line));
if (first < 0) return null;
lines[first] = lines[first]!.replace(/^ 1\./, '❯ 1.');
const pane = planFloorDXPane(lines.map(line => line.replace(
/^(Enter to select · ↑\/↓ to navigate · (?:n to add notes · )?)ctrl\+g to edit in [^\x00-\x1f\x7f·]+ · (Esc to cancel)$/,
'$1$2')).join('\n'), call);
// Only the final footer line is presentation; question text that resembles it stays verbatim.
const footer = lines.findLastIndex(line => line.trim().length > 0);
lines[footer] = lines[footer]!.replace(/^[ \t]*(Enter to select · ↑\/↓ to navigate(?: · n to add notes)?) · ctrl\+g to edit in [^\x00-\x1f\x7f·]+( · Esc to cancel)[ \t]*$/, '$1$2');
const pane = planFloorDXPane(lines.join('\n'), call);
if (!pane || compact(pane) !== compact(state.pane)) return null;
return state.stage === 'paste'
? { input: '\x1b[200~' + state.reply + '\x1b[201~', stage: 'submit' }
+11
View File
@@ -146,3 +146,14 @@ test.each(['Vim','Nano','Visual Studio Code'])('custom input with %s hint still
expect(planFloorDXReplyInput(hint(captured.filledViewport).replace('Confirmed review context:','Unapproved context:'),call,state('submit'))).toBeNull();
expect(planFloorDXReplyInput(hint(captured.filledViewport),{...call,answered:true},state('submit'))).toBeNull();
});
test('editor-hint normalization cannot rewrite question content that resembles a footer',()=>{
const footer='Enter to select · ↑/↓ to navigate · Esc to cancel';
const short=structuredClone(call);short.questions[0]!.question='Review the documented controls:\n'+footer;
const pane='☐ Empathy\n'+short.questions[0]!.question+'\n'+captured.questionViewport.slice(captured.questionViewport.indexOf('❯ 1.'));
const reply:PlanFloorDXReply={call:short,pane,reply:captured.reply,stage:'focus'};
expect(planFloorDXReplyInput(pane,short,reply)).toEqual({input:'4',stage:'paste'});
const focused=pane.replace('❯ 1.',' 1.').replace(' 4. Type something.','❯ 4. Type something.');
const changed=focused.replaceAll(footer,footer.replace(' · Esc to cancel',' · ctrl+g to edit in Vim · Esc to cancel'));
expect(planFloorDXReplyInput(changed,short,{...reply,stage:'paste'})).toBeNull();
});