From 73ec6d0204dac0c41ee8744950b3e753e93725e7 Mon Sep 17 00:00:00 2001 From: Oleg Samarin Date: Wed, 30 Sep 2026 17:01:01 +0300 Subject: [PATCH] Fixed unnumbered choice prompts (e.g. trust-folder dialog) showing every line as a bogus option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit detectUnnumberedChoiceMenu skipped blank lines unconditionally while scanning upward for options, so it swept an entire dialog's blank-separated prose into the options list once no box-drawing boundary was present. It also unconditionally merged any two adjacent non-blank lines into one option, fusing the real "Yes" choice into the "No" option's description. Now the upward scan stops on the first blank line encountered after at least one option block has been collected, and two lines are only merged into one (main, desc) option when the lower line carries the "·" metadata separator used by real 2-line entries (e.g. the /resume picker). Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + pom.xml | 2 +- .../process/ScreenContentDetector.java | 30 ++++++++++++++----- .../trust-folder-prompt.expectedRes.json | 8 +++++ .../trust-folder-prompt.src.txt | 21 +++++++++++++ 5 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.expectedRes.json create mode 100644 src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.src.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 51005576..9319dc6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Fixed an unnumbered choice prompt (e.g. the "trust this folder" dialog) showing every line of the surrounding text as a bogus selectable option instead of just the real choices, and losing the "Yes" option entirely by merging it into the "No" option's description - Fixed ChatGPT Subscription token refresh hanging indefinitely (freezing the session) when a profile's custom HTTPS/HTTP proxy hostname was slow or unreachable to resolve via DNS - Fixed a choice-dialog prompt (e.g. a Bash-command permission prompt) flickering and repeatedly resizing when Claude's response text re-wrapped to a slightly different width after the dialog first appeared diff --git a/pom.xml b/pom.xml index 98a0e36c..cf0d2edd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.nbplugins netbeans-plugin-claude-code-gui - 1.3.33-SNAPSHOT + 1.3.34-SNAPSHOT nbm Netbeans Plugin Claude Code GUI NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE. diff --git a/src/main/java/io/github/nbplugins/claudecodegui/process/ScreenContentDetector.java b/src/main/java/io/github/nbplugins/claudecodegui/process/ScreenContentDetector.java index 658a8ca0..0b078d99 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/process/ScreenContentDetector.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/process/ScreenContentDetector.java @@ -330,10 +330,20 @@ Optional detectUnnumberedChoiceMenu(List screenLines) { int stopRow = -1; // row where we stopped (first non-option line above options) int i = footerRow - 1; + boolean firstBlock = true; while (i >= 0) { - // Skip blank lines between blocks - while (i >= 0 && screenLines.get(i).isBlank()) i--; - if (i < 0) break; + if (screenLines.get(i).isBlank()) { + if (!firstBlock) { + // A blank line after at least one option block was already collected marks + // the end of the option list (real menu items are never blank-separated from + // each other) — stop here instead of skipping through unrelated prose above. + stopRow = i; + break; + } + // Allow a single blank gap between the footer and the first (bottom-most) option. + while (i >= 0 && screenLines.get(i).isBlank()) i--; + if (i < 0) break; + } String raw = screenLines.get(i); String trimmed = raw.trim(); @@ -360,12 +370,16 @@ Optional detectUnnumberedChoiceMenu(List screenLines) { break; } - // Collect this block: desc = current line, main = line above (if non-blank) + // Collect this block: desc = current line, main = line above (if non-blank). + // Only pair the two lines when the lower one carries the metadata separator "·" + // (e.g. "23 hours ago · bugfix/new-kafka · 1MB") — the shape real 2-line unnumbered + // entries use. Without that marker, treat the line as its own single-line option so + // two genuinely separate options (e.g. "No, exit" / "Yes, I trust this folder") don't + // get fused into one. String desc = trimmed; - i--; String main = null; - if (i >= 0 && !screenLines.get(i).isBlank()) { - String raw2 = screenLines.get(i); + if (desc.indexOf('·') >= 0 && i - 1 >= 0 && !screenLines.get(i - 1).isBlank()) { + String raw2 = screenLines.get(i - 1); String trimmed2 = raw2.trim(); if (!isSeparatorLine(trimmed2) && !OPTION_LINE.matcher(trimmed2).matches() && !isBoxDrawingLine(trimmed2) && !trimmed2.contains("\u2315") @@ -374,6 +388,7 @@ Optional detectUnnumberedChoiceMenu(List screenLines) { i--; } } + i--; if (main == null) { // Single-line block — treat as main with no description main = desc; @@ -381,6 +396,7 @@ Optional detectUnnumberedChoiceMenu(List screenLines) { } blockMainLines.add(0, main); blockDescLines.add(0, desc); + firstBlock = false; } if (blockMainLines.size() < 2) return Optional.empty(); diff --git a/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.expectedRes.json b/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.expectedRes.json new file mode 100644 index 00000000..c2d19aef --- /dev/null +++ b/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.expectedRes.json @@ -0,0 +1,8 @@ +{ + "text": "Security guide", + "options": [ + {"display": "No, exit", "response": "ARROW:0"}, + {"display": "Yes, I trust this folder", "response": "ARROW:1"} + ], + "defaultOptionIndex": 0 +} diff --git a/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.src.txt b/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.src.txt new file mode 100644 index 00000000..fdd88c0a --- /dev/null +++ b/src/test/resources/io/github/nbplugins/claudecodegui/process/screen-content-detector/detect-choice-menu/trust-folder-prompt.src.txt @@ -0,0 +1,21 @@ +───────────────────────────────────────────────────────────────────────────────────────────────────────── + Accessing workspace: + + /home/oleg/git/sigma/SigmaOperationStorage + + Quick safety check: Is this a project you created or one you trust? (Like your own code, a well-known + open source project, or work from your team). If not, take a moment to review what's in this folder + first. + + Claude Code'll be able to read, edit, and execute files here. + + ⚠ This folder pre-approves 2 tool permissions in .claude/settings.local.json: + mcp__netbeans__show_markdown and mcp__netbeans__show_markdown_file + These will apply without asking. Only proceed if you trust this configuration. + + Security guide + + ❯ No, exit + Yes, I trust this folder + + Enter to confirm · Esc to cancel