This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 7ece2ccd99aa camel-jbang-tui: Add confirm setting for destructive 
actions
7ece2ccd99aa is described below

commit 7ece2ccd99aa462bb7d24356ad6deda2a24b5ad7
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jul 28 22:41:20 2026 +0200

    camel-jbang-tui: Add confirm setting for destructive actions
    
    camel-jbang-tui: Add gruvbox-light theme and polish confirm dialogs
    
    camel-jbang-tui: Default confirm to on, add help and docs
    
    camel-jbang-tui: Fix SettingsPopup tests for confirm row shift
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../modules/ROOT/pages/camel-jbang-tui.adoc        |  7 +-
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  | 19 +++++-
 .../jbang/core/commands/tui/MonitorContext.java    |  1 +
 .../dsl/jbang/core/commands/tui/OverviewTab.java   | 39 +++++++++++-
 .../dsl/jbang/core/commands/tui/PopupManager.java  | 74 +++++++++++++++++++++-
 .../dsl/jbang/core/commands/tui/SettingsPopup.java | 39 +++++++++---
 .../dsl/jbang/core/commands/tui/TuiSettings.java   | 16 +++++
 .../main/resources/tui/themes/gruvbox-light.tcss   | 10 +--
 .../jbang/core/commands/tui/SettingsPopupTest.java | 20 +++---
 9 files changed, 194 insertions(+), 31 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui.adoc
index 076d2375ad64..f6cfc12cae74 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui.adoc
@@ -475,6 +475,9 @@ Open the *F2* actions menu and choose *Settings...* to 
change TUI preferences in
   chosen. Defaults to *Overview*.
 * *Select Tab* -- the tab to switch to when selecting an integration from the 
Overview tab.
   Defaults to *Log*.
+* *Confirm* -- whether destructive actions (quit, stop, restart, stop/start 
routes) show a
+  confirmation dialog before executing. Defaults to *on*. Kill (*X*) always 
confirms regardless
+  of this setting.
 * *Default Folder* -- the folder pre-filled in *Run from Folder*. The most 
recently used folder
   still takes precedence; this default is used only when there is no 
remembered folder.
 
@@ -482,8 +485,8 @@ Use *↑*/*↓* to move between rows, *Space* (or *←*/*→*) to 
cycle the them
 edit the default folder, *Enter* to save, and *Esc* to cancel.
 
 Settings are stored under `camel.tui.*` keys (`camel.tui.theme`, 
`camel.tui.startTab`,
-`camel.tui.selectTab`, `camel.tui.defaultFolder`, `camel.tui.shell.history`,
-`camel.tui.ai.promptHistory`) in the Camel CLI configuration file. Each key is 
read from and
+`camel.tui.selectTab`, `camel.tui.confirmActions`, `camel.tui.defaultFolder`,
+`camel.tui.shell.history`, `camel.tui.ai.promptHistory`) in the Camel CLI 
configuration file. Each key is read from and
 written back to the file where it currently lives: a key present in the local
 `./camel-cli.properties` is treated as a project-level override and stays 
local, while every
 other key defaults to the global `~/.camel-cli.properties`. This means a 
project can
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index cf2eee2e78ca..a0d395a7f24a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -418,6 +418,11 @@ public class CamelMonitor extends CamelCommand {
             public void openFilesPopup() {
                 CamelMonitor.this.openFilesPopup();
             }
+
+            @Override
+            public void showConfirm(String title, String message, Runnable 
onConfirm) {
+                popupManager.showConfirm(title, message, onConfirm);
+            }
         });
 
         // Initial data load (synchronous before TUI starts)
@@ -533,6 +538,7 @@ public class CamelMonitor extends CamelCommand {
             applyStartingTab();
             applyLogPin();
             applyRatePer();
+            applyConfirmActions();
             // Intercept Ctrl+C: quit the TUI cleanly instead of letting
             // the JVM tear down the classloader while we're still running
             Signal.handle(new Signal("INT"), sig -> tui.quit());
@@ -604,6 +610,10 @@ public class CamelMonitor extends CamelCommand {
         ctx.ratePerMinute = "minutes".equals(ratePer);
     }
 
+    private void applyConfirmActions() {
+        ctx.confirmActions = TuiSettings.load().isConfirmActions();
+    }
+
     // ---- Event Handling ----
 
     private boolean handleEvent(Event event, TuiRunner runner) {
@@ -742,7 +752,11 @@ public class CamelMonitor extends CamelCommand {
                 || beanFilterActive || classpathFilterActive || 
mavenDepsFilterActive || sqlInputActive
                 || catalogFilterActive;
         if (!textEditing && (ke.isCharIgnoreCase('q') || ke.isCtrlC())) {
-            runner.quit();
+            if (!ke.isCtrlC() && ctx.confirmActions) {
+                popupManager.showConfirm("Confirm Quit", " Quit the TUI? ", () 
-> runner.quit());
+            } else {
+                runner.quit();
+            }
             return true;
         }
         if (ke.isCtrlC()) {
@@ -1348,6 +1362,9 @@ public class CamelMonitor extends CamelCommand {
         if (popupManager.isKillConfirmVisible()) {
             popupManager.renderKillConfirm(frame, contentArea);
         }
+        if (popupManager.isConfirmVisible()) {
+            popupManager.renderConfirm(frame, contentArea);
+        }
         actionsPopup.render(frame, contentArea);
         if (captionOverlay.isCaptionVisible()) {
             captionOverlay.render(frame, contentArea);
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
index 2b200b23ddb0..91fbb2b60213 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/MonitorContext.java
@@ -51,6 +51,7 @@ class MonitorContext {
     int logPinPercent;
     boolean logPinVisible;
     boolean ratePerMinute;
+    boolean confirmActions;
     BiConsumer<String, Boolean> notificationCallback;
     BiConsumer<String, String> openMarkdownCallback;
     OpenOptionsCallback openOptionsCallback;
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
index 1379044a2ea5..21dc73241c74 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/OverviewTab.java
@@ -72,6 +72,8 @@ class OverviewTab extends AbstractTab {
         void openDoc(IntegrationInfo info);
 
         void openFilesPopup();
+
+        void showConfirm(String title, String message, Runnable onConfirm);
     }
 
     private static final long VANISH_DURATION_MS = 6000;
@@ -196,12 +198,25 @@ class OverviewTab extends AbstractTab {
                 IntegrationInfo selInfo = ctx.findSelectedIntegration();
                 if (selInfo != null) {
                     String cmd = selInfo.routeStarted > 0 ? "stop" : "start";
-                    actions.sendRouteCommand(ctx.selectedPid, "*", cmd);
+                    if (ctx.confirmActions) {
+                        String label = selInfo.routeStarted > 0 ? "Stop" : 
"Start";
+                        actions.showConfirm("Confirm " + label + " Routes",
+                                " " + label + " all routes for " + 
ctx.selectedName() + "? ",
+                                () -> 
actions.sendRouteCommand(ctx.selectedPid, "*", cmd));
+                    } else {
+                        actions.sendRouteCommand(ctx.selectedPid, "*", cmd);
+                    }
                 }
                 return true;
             }
             if (ke.isChar('x') && ctx.selectedPid != null) {
-                actions.stopSelectedProcess(false);
+                if (ctx.confirmActions) {
+                    actions.showConfirm("Confirm Stop",
+                            " Stop " + ctx.selectedName() + " (PID: " + 
ctx.selectedPid + ")? ",
+                            () -> actions.stopSelectedProcess(false));
+                } else {
+                    actions.stopSelectedProcess(false);
+                }
                 return true;
             }
             if (ke.isChar('X') && ctx.selectedPid != null) {
@@ -209,7 +224,13 @@ class OverviewTab extends AbstractTab {
                 return true;
             }
             if (ke.isChar('r') && ctx.selectedPid != null && 
!ctx.isInfraSelected()) {
-                actions.restartSelectedProcess();
+                if (ctx.confirmActions) {
+                    actions.showConfirm("Confirm Restart",
+                            " Restart " + ctx.selectedName() + " (PID: " + 
ctx.selectedPid + ")? ",
+                            () -> actions.restartSelectedProcess());
+                } else {
+                    actions.restartSelectedProcess();
+                }
                 return true;
             }
             if (ke.isChar('f') && ctx.selectedPid != null && 
!ctx.isInfraSelected()) {
@@ -1374,6 +1395,18 @@ class OverviewTab extends AbstractTab {
                 - `S` — reverse sort order
                 - `F2` — actions menu (includes theme toggle, go to tab, etc.)
                 - `F3` — switch integration
+
+                ## Process Control
+
+                - `p` — stop or start all routes for the selected integration
+                - `x` — stop the selected integration (graceful shutdown)
+                - `X` — kill the selected integration (force terminate, always 
confirms)
+                - `r` — restart the selected integration
+                - `q` — quit the TUI
+
+                By default, these actions show a confirmation dialog before 
executing.
+                You can turn this off in Settings (`F2` → `Settings...` → 
`Confirm`).
+                Kill (`X`) always confirms regardless of this setting.
                 """;
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
index f425cb17aebc..4ea5fad6720d 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/PopupManager.java
@@ -86,6 +86,12 @@ class PopupManager {
     // Kill confirm
     private boolean showKillConfirm;
 
+    // Generic confirm dialog
+    private boolean showConfirm;
+    private String confirmTitle;
+    private String confirmMessage;
+    private Runnable confirmCallback;
+
     // Last rendered popup rects for mouse hit-testing
     private Rect lastMorePopupRect;
     private Rect lastSwitchPopupRect;
@@ -156,7 +162,7 @@ class PopupManager {
     // ---- State queries ----
 
     boolean isAnyPopupVisible() {
-        return showSwitchPopup || showMorePopup || showKillConfirm || 
filesBrowser.isVisible();
+        return showSwitchPopup || showMorePopup || showKillConfirm || 
showConfirm || filesBrowser.isVisible();
     }
 
     boolean isSwitchPopupVisible() {
@@ -171,6 +177,10 @@ class PopupManager {
         return showKillConfirm;
     }
 
+    boolean isConfirmVisible() {
+        return showConfirm;
+    }
+
     int getLastMoreSelection() {
         return lastMoreSelection;
     }
@@ -212,6 +222,8 @@ class PopupManager {
         showMorePopup = false;
         showSwitchPopup = false;
         showKillConfirm = false;
+        showConfirm = false;
+        confirmCallback = null;
         filesBrowser.reset();
     }
 
@@ -223,6 +235,13 @@ class PopupManager {
         showKillConfirm = true;
     }
 
+    void showConfirm(String title, String message, Runnable onConfirm) {
+        this.confirmTitle = title;
+        this.confirmMessage = message;
+        this.confirmCallback = onConfirm;
+        this.showConfirm = true;
+    }
+
     void selectMorePopupEntry(int moreIndex) {
         int visualIndex = moreToVisualIndex(moreIndex);
         morePopupState.select(visualIndex);
@@ -244,6 +263,9 @@ class PopupManager {
         if (showKillConfirm) {
             return handleKillConfirmKeys(ke);
         }
+        if (showConfirm) {
+            return handleConfirmKeys(ke);
+        }
         return false;
     }
 
@@ -398,6 +420,21 @@ class PopupManager {
         return true;
     }
 
+    private boolean handleConfirmKeys(KeyEvent ke) {
+        if (ke.isConfirm()) {
+            showConfirm = false;
+            Runnable cb = confirmCallback;
+            confirmCallback = null;
+            if (cb != null) {
+                cb.run();
+            }
+        } else {
+            showConfirm = false;
+            confirmCallback = null;
+        }
+        return true;
+    }
+
     // ---- Mouse handling ----
 
     boolean handleMouseEvent(MouseEvent me, int selectedTab, int tabLog) {
@@ -663,7 +700,7 @@ class PopupManager {
         int popupW = Math.max(34, msg.length() + 4);
         int popupH = 6;
         int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
-        int y = area.top() + Math.max(0, (area.height() - popupH) / 2);
+        int y = area.top() + Math.max(0, (area.height() - popupH) / 3);
         Rect popup = new Rect(x, y, Math.min(popupW, area.width()), 
Math.min(popupH, area.height()));
 
         frame.renderWidget(Clear.INSTANCE, popup);
@@ -690,6 +727,39 @@ class PopupManager {
                 inner);
     }
 
+    void renderConfirm(Frame frame, Rect area) {
+        String msg = confirmMessage != null ? confirmMessage : "";
+        String title = confirmTitle != null ? " " + confirmTitle + " " : " 
Confirm ";
+        int popupW = Math.max(34, Math.max(msg.length() + 4, title.length() + 
4));
+        int popupH = 6;
+        int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
+        int y = area.top() + Math.max(0, (area.height() - popupH) / 3);
+        Rect popup = new Rect(x, y, Math.min(popupW, area.width()), 
Math.min(popupH, area.height()));
+
+        frame.renderWidget(Clear.INSTANCE, popup);
+        Block block = Block.builder()
+                .borderType(BorderType.ROUNDED).borders(Borders.ALL)
+                .borderStyle(Theme.warning())
+                .title(title)
+                .build();
+        frame.renderWidget(block, popup);
+        Rect inner = block.inner(popup);
+        frame.renderWidget(
+                Paragraph.builder()
+                        .text(Text.from(
+                                Line.from(Span.raw("")),
+                                Line.from(Span.styled(msg, 
Theme.warning().bold())),
+                                Line.from(Span.raw("")),
+                                Line.from(
+                                        Span.raw("  "),
+                                        Span.styled("Enter", 
Style.EMPTY.bold()),
+                                        Span.raw(" confirm  "),
+                                        Span.styled("Esc", Style.EMPTY.bold()),
+                                        Span.raw(" cancel"))))
+                        .build(),
+                inner);
+    }
+
     int[] morePopupShortcut(KeyEvent ke) {
         List<TabRegistry.MoreTab> tabs = moreTabsSupplier.get();
         IntegrationInfo info = ctx.findSelectedIntegration();
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
index bf0bbe231cb9..745c4abd5618 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopup.java
@@ -51,15 +51,16 @@ class SettingsPopup {
     private static final int ROW_SELECT_TAB = 2;
     private static final int ROW_LOG_PIN = 3;
     private static final int ROW_RATE_PER = 4;
-    private static final int ROW_FOLDER = 5;
-    private static final int ROW_PROXY_HOST = 6;
-    private static final int ROW_PROXY_PORT = 7;
-    private static final int ROW_SHELL_HISTORY = 8;
-    private static final int ROW_AI_PROVIDER = 9;
-    private static final int ROW_AI_MODEL = 10;
-    private static final int ROW_AI_URL = 11;
-    private static final int ROW_AI_PROMPT_HISTORY = 12;
-    private static final int ROW_COUNT = 13;
+    private static final int ROW_CONFIRM_ACTIONS = 5;
+    private static final int ROW_FOLDER = 6;
+    private static final int ROW_PROXY_HOST = 7;
+    private static final int ROW_PROXY_PORT = 8;
+    private static final int ROW_SHELL_HISTORY = 9;
+    private static final int ROW_AI_PROVIDER = 10;
+    private static final int ROW_AI_MODEL = 11;
+    private static final int ROW_AI_URL = 12;
+    private static final int ROW_AI_PROMPT_HISTORY = 13;
+    private static final int ROW_COUNT = 14;
 
     private static final String[] LOG_PIN_OPTIONS = { "off", "25", "50", "75" 
};
     private static final String[] RATE_PER_OPTIONS = { "seconds", "minutes" };
@@ -83,6 +84,7 @@ class SettingsPopup {
     private int selectTabIndex;
     private int logPinIndex;
     private int ratePerIndex;
+    private int confirmActionsIndex;
     private int aiProviderIndex;
     private TextInputState folderInput;
     private TextInputState proxyHostInput;
@@ -158,6 +160,8 @@ class SettingsPopup {
         String currentRatePer = settings.getRatePer() != null ? 
settings.getRatePer() : "seconds";
         ratePerIndex = "minutes".equals(currentRatePer) ? 1 : 0;
 
+        confirmActionsIndex = settings.isConfirmActions() ? 1 : 0;
+
         folderInput = new TextInputState(settings.getDefaultFolder() != null ? 
settings.getDefaultFolder() : "");
         proxyHostInput = new TextInputState(settings.getProxyHost() != null ? 
settings.getProxyHost() : "");
         proxyPortInput = new TextInputState(settings.getProxyPort() != null ? 
settings.getProxyPort() : "");
@@ -253,6 +257,12 @@ class SettingsPopup {
             }
             return true;
         }
+        if (selectedRow == ROW_CONFIRM_ACTIONS) {
+            if (ke.isChar(' ') || ke.isRight() || ke.isLeft()) {
+                confirmActionsIndex = confirmActionsIndex == 0 ? 1 : 0;
+            }
+            return true;
+        }
         if (selectedRow == ROW_FOLDER) {
             handleTextInput(ke, folderInput);
             return true;
@@ -309,6 +319,10 @@ class SettingsPopup {
         if (monitorContext != null) {
             monitorContext.ratePerMinute = "minutes".equals(ratePerValue);
         }
+        settings.setConfirmActions(confirmActionsIndex == 1 ? "true" : 
"false");
+        if (monitorContext != null) {
+            monitorContext.confirmActions = confirmActionsIndex == 1;
+        }
         
settings.setDefaultFolder(stripControlChars(folderInput.text().trim()));
         settings.setProxyHost(stripControlChars(proxyHostInput.text().trim()));
         settings.setProxyPort(stripControlChars(proxyPortInput.text().trim()));
@@ -373,6 +387,11 @@ class SettingsPopup {
         renderValue(frame, innerX + labelW, rowY, fieldW, 
RATE_PER_OPTIONS[ratePerIndex], selectedRow == ROW_RATE_PER);
         rowY++;
 
+        renderLabel(frame, innerX, rowY, labelW, "Confirm:", selectedRow == 
ROW_CONFIRM_ACTIONS);
+        renderValue(frame, innerX + labelW, rowY, fieldW, confirmActionsIndex 
== 1 ? "on" : "off",
+                selectedRow == ROW_CONFIRM_ACTIONS);
+        rowY++;
+
         renderLabel(frame, innerX, rowY, labelW, "Default Folder:", 
selectedRow == ROW_FOLDER);
         renderFolder(frame, innerX + labelW, rowY, fieldW, selectedRow == 
ROW_FOLDER);
         rowY++;
@@ -414,7 +433,7 @@ class SettingsPopup {
         hint(spans, TuiIcons.HINT_SCROLL, "navigate");
         if (selectedRow == ROW_THEME || selectedRow == ROW_START_TAB || 
selectedRow == ROW_SELECT_TAB
                 || selectedRow == ROW_LOG_PIN || selectedRow == ROW_RATE_PER
-                || selectedRow == ROW_AI_PROVIDER) {
+                || selectedRow == ROW_CONFIRM_ACTIONS || selectedRow == 
ROW_AI_PROVIDER) {
             hint(spans, "Space", "cycle");
         }
         hint(spans, "Enter", "save");
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
index d586473ce3fc..65ef4e5bc427 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiSettings.java
@@ -43,6 +43,7 @@ final class TuiSettings {
     static final String PROP_PROXY_PORT = "camel.tui.proxyPort";
     static final String PROP_SHELL_HISTORY = "camel.tui.shell.history";
     static final String PROP_AI_PROMPT_HISTORY = "camel.tui.ai.promptHistory";
+    static final String PROP_CONFIRM_ACTIONS = "camel.tui.confirmActions";
 
     private String themeId;
     private String startTab;
@@ -57,6 +58,7 @@ final class TuiSettings {
     private String aiUrl;
     private String shellHistory;
     private String aiPromptHistory;
+    private String confirmActions;
 
     String getThemeId() {
         return themeId;
@@ -170,6 +172,18 @@ final class TuiSettings {
         return TuiHistoryLimits.resolveLimit(aiPromptHistory);
     }
 
+    String getConfirmActions() {
+        return confirmActions;
+    }
+
+    void setConfirmActions(String confirmActions) {
+        this.confirmActions = confirmActions;
+    }
+
+    boolean isConfirmActions() {
+        return !"false".equals(confirmActions);
+    }
+
     /**
      * Loads the current settings, resolving each key with per-key 
local/global precedence via {@link TuiUserConfig}.
      * Unset keys yield {@code null} fields; a read failure yields an object 
with {@code null} fields rather than
@@ -191,6 +205,7 @@ final class TuiSettings {
             settings.aiUrl = trimToNull(TuiUserConfig.read(PROP_AI_URL));
             settings.shellHistory = 
trimToNull(TuiUserConfig.read(PROP_SHELL_HISTORY));
             settings.aiPromptHistory = 
trimToNull(TuiUserConfig.read(PROP_AI_PROMPT_HISTORY));
+            settings.confirmActions = 
trimToNull(TuiUserConfig.read(PROP_CONFIRM_ACTIONS));
         } catch (RuntimeException e) {
             // best-effort: return an object with null fields on read failure
         }
@@ -217,6 +232,7 @@ final class TuiSettings {
             TuiUserConfig.write(PROP_AI_URL, aiUrl);
             TuiUserConfig.write(PROP_SHELL_HISTORY, shellHistory);
             TuiUserConfig.write(PROP_AI_PROMPT_HISTORY, aiPromptHistory);
+            TuiUserConfig.write(PROP_CONFIRM_ACTIONS, confirmActions);
         } catch (RuntimeException e) {
             // best-effort: a save failure must not disrupt the TUI
         }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/themes/gruvbox-light.tcss
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/themes/gruvbox-light.tcss
index e8902dead615..8cf77b57ad8e 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/themes/gruvbox-light.tcss
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/resources/tui/themes/gruvbox-light.tcss
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/* Camel TUI Gruvbox Light theme. Warm sepia-toned light palette with earthy 
colors. */
+/* Camel TUI Gruvbox Light theme. Retro groove palette on a warm light base. */
 
 $brand: #AF3A03;
 $gruvbox-bg: #FBF1C7;
@@ -28,19 +28,19 @@ $gruvbox-fg: #3C3836;
 #title          { color: $brand; text-style: bold; }
 #success        { color: #79740E; }
 #warning        { color: #B57614; }
-#error          { color: #CC241D; }
+#error          { color: #9D0006; }
 #muted          { color: #928374; }
-#selection      { color: white; background: #D65D0E; text-style: bold; }
+#selection      { color: white; background: #AF3A03; text-style: bold; }
 #info           { color: #076678; }
 #notice         { color: #8F3F71; }
-#row-alt        { background: #F2E5BC; }
+#row-alt        { background: #EBDBB2; }
 #base-bg        { background: $gruvbox-bg; }
 #base-fg        { color: $gruvbox-fg; }
 
 /* Content tokens — labels, change indicators, search highlight */
 #label          { color: #B57614; }
 #change         { color: #B57614; }
-#search-match   { color: $gruvbox-fg; background: #B57614; }
+#search-match   { color: #3C3836; background: #B57614; }
 #mnemonic       { color: #B57614; text-style: bold underline; }
 
 /* Diagram tokens */
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
index f353f54cf057..858ae671b17a 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SettingsPopupTest.java
@@ -137,7 +137,8 @@ class SettingsPopupTest {
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
-        assertEquals(5, popup.selectedRow());
+        popup.handleKeyEvent(key(KeyCode.DOWN));
+        assertEquals(6, popup.selectedRow());
         popup.handleKeyEvent(KeyEvent.ofChar('/'));
         popup.handleKeyEvent(KeyEvent.ofChar('a'));
         assertEquals("/a", popup.folderText());
@@ -155,7 +156,8 @@ class SettingsPopupTest {
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
-        assertEquals(5, popup.selectedRow());
+        popup.handleKeyEvent(key(KeyCode.DOWN));
+        assertEquals(6, popup.selectedRow());
         popup.handleKeyEvent(KeyEvent.ofChar(0x01));
         popup.handleKeyEvent(KeyEvent.ofChar(0x00));
         popup.handleKeyEvent(KeyEvent.ofChar('x'));
@@ -179,7 +181,8 @@ class SettingsPopupTest {
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
         popup.handleKeyEvent(key(KeyCode.DOWN));
-        assertEquals(9, popup.selectedRow());
+        popup.handleKeyEvent(key(KeyCode.DOWN));
+        assertEquals(10, popup.selectedRow());
         assertEquals("auto", popup.selectedAiProvider());
         popup.handleKeyEvent(KeyEvent.ofChar(' '));
         assertEquals("ollama", popup.selectedAiProvider());
@@ -211,21 +214,21 @@ class SettingsPopupTest {
         popup.setTabEntries(tabs());
         popup.open();
 
-        // navigate to Shell History (row 8)
-        for (int i = 0; i < 8; i++) {
+        // navigate to Shell History (row 9)
+        for (int i = 0; i < 9; i++) {
             popup.handleKeyEvent(key(KeyCode.DOWN));
         }
-        assertEquals(8, popup.selectedRow());
+        assertEquals(9, popup.selectedRow());
         for (char c : "50".toCharArray()) {
             popup.handleKeyEvent(KeyEvent.ofChar(c));
         }
         assertEquals("50", popup.shellHistoryText());
 
-        // navigate to AI Prompt History (row 12)
+        // navigate to AI Prompt History (row 13)
         for (int i = 0; i < 4; i++) {
             popup.handleKeyEvent(key(KeyCode.DOWN));
         }
-        assertEquals(12, popup.selectedRow());
+        assertEquals(13, popup.selectedRow());
         for (char c : "200".toCharArray()) {
             popup.handleKeyEvent(KeyEvent.ofChar(c));
         }
@@ -258,6 +261,7 @@ class SettingsPopupTest {
         popup.handleKeyEvent(key(KeyCode.DOWN)); // select tab
         popup.handleKeyEvent(key(KeyCode.DOWN)); // log pin
         popup.handleKeyEvent(key(KeyCode.DOWN)); // rate per
+        popup.handleKeyEvent(key(KeyCode.DOWN)); // confirm actions
         popup.handleKeyEvent(key(KeyCode.DOWN)); // folder
         for (char c : "/tmp/p".toCharArray()) {
             popup.handleKeyEvent(KeyEvent.ofChar(c));

Reply via email to