diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76c3747..65b97bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+- Fixed the choice dialog (e.g. /model) endlessly flickering and resizing when not all menu items fit on screen
# 1.3.20 (2026-10-04)
- Fixed switching the edit mode (e.g. to Auto Mode) while a prompt was still running sometimes cycling through several modes and landing on the wrong one instead of the one selected
diff --git a/pom.xml b/pom.xml
index 28f763b..55df72d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.nbplugins
netbeans-plugin-claude-code-gui
- 1.3.37-SNAPSHOT
+ 1.3.38-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/controller/ClaudeSessionController.java b/src/main/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionController.java
index 4616523..839c9c6 100644
--- a/src/main/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionController.java
+++ b/src/main/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionController.java
@@ -1438,7 +1438,7 @@ private void applyDetectedChoiceMenu(ChoiceMenuModel newMenu, String logTag) {
model.setActiveChoiceMenu(newMenu);
return;
}
- if (sameMenu(newMenu, current)) {
+ if (sameMenu(newMenu, current) || isShrunkViewOf(newMenu, current)) {
pendingChoiceMenuCandidate = null;
return;
}
@@ -1452,6 +1452,28 @@ private void applyDetectedChoiceMenu(ChoiceMenuModel newMenu, String logTag) {
}
}
+ /**
+ * Returns {@code true} when {@code newMenu} is just a shorter window onto the same
+ * scrolling list as {@code current} (same question, options are a strict prefix).
+ *
+ *
Scrolling pickers such as {@code /model} draw as many items as fit the terminal.
+ * The choice panel shrinks the terminal, which makes Claude draw fewer items, which
+ * shrinks the panel, which grows the terminal again — an endless flicker. Keeping
+ * the larger option list breaks that loop.
+ */
+ static boolean isShrunkViewOf(ChoiceMenuModel newMenu, ChoiceMenuModel current) {
+ List n = newMenu.options();
+ List c = current.options();
+ if (!newMenu.text().equals(current.text()) || n.size() >= c.size()) return false;
+ for (int i = 0; i < n.size(); i++) {
+ if (!n.get(i).display().equals(c.get(i).display())
+ || !n.get(i).response().equals(c.get(i).response())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private static boolean sameMenu(ChoiceMenuModel a, ChoiceMenuModel b) {
return a.text().equals(b.text()) && optionsEqual(a.options(), b.options());
}
diff --git a/src/test/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionControllerTest.java b/src/test/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionControllerTest.java
index b8bffab..b91b6dc 100644
--- a/src/test/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionControllerTest.java
+++ b/src/test/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionControllerTest.java
@@ -38,6 +38,36 @@ void setUp() {
// onClaudeIdle
// -------------------------------------------------------------------------
+ private static ChoiceMenuModel menu(String text, String... displays) {
+ List opts = new java.util.ArrayList<>();
+ for (int i = 0; i < displays.length; i++) {
+ opts.add(new ChoiceMenuModel.Option(displays[i], String.valueOf(i + 1)));
+ }
+ return new ChoiceMenuModel(text, opts, 0);
+ }
+
+ @Test
+ void isShrunkViewOf_prefixOfScrollingList_true() {
+ ChoiceMenuModel full = menu("Select model", "a", "b", "c", "d");
+ ChoiceMenuModel shrunk = menu("Select model", "a", "b", "c");
+ assertTrue(ClaudeSessionController.isShrunkViewOf(shrunk, full));
+ }
+
+ @Test
+ void isShrunkViewOf_sameSizeOrGrown_false() {
+ ChoiceMenuModel three = menu("Select model", "a", "b", "c");
+ ChoiceMenuModel four = menu("Select model", "a", "b", "c", "d");
+ assertFalse(ClaudeSessionController.isShrunkViewOf(three, three));
+ assertFalse(ClaudeSessionController.isShrunkViewOf(four, three));
+ }
+
+ @Test
+ void isShrunkViewOf_differentTextOrOptions_false() {
+ ChoiceMenuModel full = menu("Select model", "a", "b", "c", "d");
+ assertFalse(ClaudeSessionController.isShrunkViewOf(menu("Other", "a", "b", "c"), full));
+ assertFalse(ClaudeSessionController.isShrunkViewOf(menu("Select model", "a", "x", "c"), full));
+ }
+
@Test
void onClaudeIdleSetsLifecycleToReady() {
model.setLifecycle(SessionLifecycle.WORKING);