diff --git a/CHANGELOG.md b/CHANGELOG.md index e7477681..56c3225e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Reorganized General and Advanced settings tabs: moved technical settings (hang timeout, MCP port, Enable MCP integration, session list limit, debug mode) to Advanced - Fixed prompt area being collapsible to zero height by dragging the divider - Fixed terminal scrolling to the beginning and locking when a choice/confirmation menu appears (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/22) - Added a setting to control whether the choice menu grabs keyboard focus (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/20) diff --git a/docs/screenshots/settings-advanced.png b/docs/screenshots/settings-advanced.png index 59885b08..edebc68e 100644 Binary files a/docs/screenshots/settings-advanced.png and b/docs/screenshots/settings-advanced.png differ diff --git a/docs/screenshots/settings-general.png b/docs/screenshots/settings-general.png index d786910d..ed0dd7d9 100644 Binary files a/docs/screenshots/settings-general.png and b/docs/screenshots/settings-general.png differ diff --git a/docs/user-manual.md b/docs/user-manual.md index 2e9fee5c..c526a595 100644 --- a/docs/user-manual.md +++ b/docs/user-manual.md @@ -337,15 +337,10 @@ Open **Tools → Options → Claude Code** in NetBeans. | Setting | Default | Description | |---------|---------|-------------| -| Claude CLI path | (empty) | Absolute path to the `claude` executable. Leave empty to use the system `PATH`. | -| MCP server port | 28991 | Port for the internal MCP SSE server. Change only if 28991 conflicts. Requires IDE restart. | -| History max depth | 200 | Maximum number of history entries kept per working directory. | -| History TTL (days) | 0 | Number of days after which history entries expire. 0 = keep forever. | -| Send prompt key | Ctrl+Enter | Key combination that sends the prompt from the input area. | -| Insert newline key | Enter | Key combination that inserts a newline in the input area. The send and newline keys are configured independently but cannot be set to the same value. | | Start new session when opening with Claude | Off (Continue last) | Checked → always start a **New session** when opening with the project context menu or when NetBeans restores a closed session tab on restart. Unchecked → **Continue last**. | -| Session list limit | 30 | Maximum number of past sessions shown in the session selector table. | | Session tab dock position | Editor area | Where the Claude Code session tab is docked when first opened. Choices: Editor area, Right side, Left side top, Left side bottom, Bottom dock. | +| Send prompt key | Ctrl+Enter | Key combination that sends the prompt from the input area. | +| Insert newline key | Enter | Key combination that inserts a newline in the input area. The send and newline keys are configured independently but cannot be set to the same value. | | Open file diff in a separate tab | Off | Opens the diff panel in a new IDE tab instead of embedding it in the session tab. | | File diff tab dock position | Editor area | Where the File Diff tab is docked when opened as a separate tab. Enabled only when "Open file diff in a separate tab" is checked. | | Show markdown preview for .md files in diff | On | Shows a rendered markdown preview alongside the raw diff for `.md` files. | @@ -358,9 +353,14 @@ Open **Tools → Options → Claude Code** in NetBeans. | Setting | Default | Description | |---------|---------|-------------| -| Debug mode | Off | Enables verbose logging of all Claude I/O to the NetBeans log file and the Output window. | +| Claude CLI path | (empty) | Absolute path to the `claude` executable. Leave empty to use the system `PATH`. | | Hang timeout (seconds) | 60 | Kill the process if no PTY output is received within this many seconds after launch. Set to 0 to disable. | +| MCP server port | 28991 | Port for the internal MCP SSE server. Change only if 28991 conflicts. Requires IDE restart. | | Enable MCP integration | On | When unchecked, the `--mcp-config` flag is not passed to `claude`. Hooks (PreToolUse) are always configured regardless of this setting. Disable only if MCP causes issues. | +| History max depth | 200 | Maximum number of history entries kept per working directory. | +| History TTL (days) | 0 | Number of days after which history entries expire. 0 = keep forever. | +| Session list limit | 30 | Maximum number of past sessions shown in the session selector table. | +| Debug mode | Off | Enables verbose logging of all Claude I/O to the NetBeans log file and the Output window. | ### Favorites tab @@ -671,7 +671,7 @@ As you move the cursor or change the selection in any open editor, the plugin au If Claude says a tool is unavailable (e.g. "I don't have access to `getWorkspaceFolders`"): -1. Check that no other application is using the MCP server port (**Tools → Options → Claude Code → General → MCP server port**, default: 28991). Change the port if needed and restart the IDE. +1. Check that no other application is using the MCP server port (**Tools → Options → Claude Code → Advanced → MCP server port**, default: 28991). Change the port if needed and restart the IDE. 2. Enable **Debug mode** (**Tools → Options → Claude Code → Advanced**) and check the log file (`~/.netbeans//var/log/messages.log`) for `MCP SSE server started on port`. --- @@ -691,7 +691,7 @@ For example: `~/.netbeans/28/var/log/messages.log` | Symptom | Likely cause | Fix | |---------|-------------|-----| -| Session tab does not open | `claude` not found on PATH | Set the full path in **Tools → Options → Claude Code → General → Claude CLI path** | +| Session tab does not open | `claude` not found on PATH | Set the full path in **Tools → Options → Claude Code → Advanced → Claude CLI path** | | Diff panel shows but Accept/Decline have no effect | Claude timed out waiting for the hook response (600 s limit) | Respond to the diff panel within ~9 minutes; if this happens regularly, check for blocking processes | | Claude asked a question but the Choice Menu panel did not appear | The plugin did not recognise the prompt format | Switch to the terminal area and answer directly by typing | | Choice Menu appeared but Claude did not ask anything (false trigger) | The plugin mis-detected a numbered list as a menu | Dismiss the panel with **Esc** or ignore it; Claude will continue on its own | diff --git a/pom.xml b/pom.xml index b09d1b82..5884868c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.nbclaudecodegui netbeans-claude-code-gui - 0.22.13-SNAPSHOT + 0.22.16-SNAPSHOT nbm Netbeans 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/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java index 3f7a3939..3313ee3e 100644 --- a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java +++ b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java @@ -137,45 +137,28 @@ private JPanel buildGeneralPanel() { JPanel form = new JPanel(new GridBagLayout()); int row = 0; - // --- executable path --- - form.add(new JLabel("Claude CLI path:"), gbc(0, row, false)); - executablePathField = new JTextField(30); - executablePathField.setToolTipText("Leave empty to detect 'claude' from PATH"); - form.add(executablePathField, gbcFill(1, row)); - JButton browseButton = new JButton("Browse\u2026"); - browseButton.addActionListener(e -> { - JFileChooser chooser = new JFileChooser(); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - executablePathField.setText( - chooser.getSelectedFile().getAbsolutePath()); - } - }); - form.add(browseButton, gbc(2, row, false)); - row++; - - // --- MCP port --- - form.add(new JLabel("MCP server port:"), gbc(0, row, false)); - mcpPortSpinner = new JSpinner(new SpinnerNumberModel( - ClaudeCodePreferences.DEFAULT_MCP_PORT, 1024, 65535, 1)); - mcpPortSpinner.setToolTipText("Port for the NetBeans MCP SSE server (restart required)"); - form.add(mcpPortSpinner, gbc(1, row, false)); - row++; - - // --- history max depth --- - form.add(new JLabel("History max depth:"), gbc(0, row, false)); - historyMaxDepthSpinner = new JSpinner(new SpinnerNumberModel( - ClaudeCodePreferences.DEFAULT_HISTORY_MAX_DEPTH, 1, 2000, 10)); - historyMaxDepthSpinner.setToolTipText("Maximum number of history entries to keep per project"); - form.add(historyMaxDepthSpinner, gbc(1, row, false)); + // --- context-menu session mode --- + startNewSessionCheck = new javax.swing.JCheckBox("Start new session when opening with Claude"); + GridBagConstraints cmGbc = new GridBagConstraints(); + cmGbc.gridx = 0; cmGbc.gridy = row; + cmGbc.gridwidth = 3; + cmGbc.anchor = GridBagConstraints.WEST; + cmGbc.insets = new Insets(8, 8, 4, 8); + form.add(startNewSessionCheck, cmGbc); row++; - // --- history TTL --- - form.add(new JLabel("History TTL (days, 0 = keep forever):"), gbc(0, row, false)); - historyTtlDaysSpinner = new JSpinner(new SpinnerNumberModel( - ClaudeCodePreferences.DEFAULT_HISTORY_TTL_DAYS, 0, 3650, 1)); - historyTtlDaysSpinner.setToolTipText("Delete history entries older than this many days (0 = keep forever)"); - form.add(historyTtlDaysSpinner, gbc(1, row, false)); + // --- session tab dock position --- + form.add(new JLabel("Session tab dock position:"), gbc(0, row, false)); + dockModeCombo = new javax.swing.JComboBox<>( + DockMode.labels(ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE)); + dockModeCombo.setToolTipText("Where to dock the Claude Code session tab when opening it"); + form.add(dockModeCombo, gbc(1, row, false)); + GridBagConstraints hSpacer = new GridBagConstraints(); + hSpacer.gridx = 2; hSpacer.gridy = row; + hSpacer.weightx = 1.0; + hSpacer.fill = GridBagConstraints.HORIZONTAL; + hSpacer.insets = new Insets(0, 0, 0, 8); + form.add(new JLabel(""), hSpacer); row++; // --- send key --- @@ -205,32 +188,6 @@ private JPanel buildGeneralPanel() { newlineRadios.get(val).addActionListener(e -> syncExclusion(val, false)); } - // --- context-menu session mode --- - startNewSessionCheck = new javax.swing.JCheckBox("Start new session when opening with Claude"); - GridBagConstraints cmGbc = new GridBagConstraints(); - cmGbc.gridx = 0; cmGbc.gridy = row; - cmGbc.gridwidth = 3; - cmGbc.anchor = GridBagConstraints.WEST; - cmGbc.insets = new Insets(4, 8, 4, 8); - form.add(startNewSessionCheck, cmGbc); - row++; - - // --- session list limit --- - form.add(new JLabel("Session list limit:"), gbc(0, row, false)); - sessionListLimitSpinner = new JSpinner(new SpinnerNumberModel( - ClaudeCodePreferences.DEFAULT_SESSION_LIST_LIMIT, 1, 500, 5)); - sessionListLimitSpinner.setToolTipText("Maximum number of sessions shown in the session list"); - form.add(sessionListLimitSpinner, gbc(1, row, false)); - row++; - - // --- session tab dock position --- - form.add(new JLabel("Session tab dock position:"), gbc(0, row, false)); - dockModeCombo = new javax.swing.JComboBox<>( - DockMode.labels(ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE)); - dockModeCombo.setToolTipText("Where to dock the Claude Code session tab when opening it"); - form.add(dockModeCombo, gbc(1, row, false)); - row++; - // --- diff in session --- diffInSessionCheck = new javax.swing.JCheckBox("Open file diff in a separate tab"); GridBagConstraints diffGbc = new GridBagConstraints(); @@ -298,14 +255,21 @@ private JPanel buildAdvancedPanel() { JPanel form = new JPanel(new GridBagLayout()); int row = 0; - // --- debug mode --- - debugCheckBox = new javax.swing.JCheckBox("Debug mode (log all claude I/O to NetBeans log and output area)"); - GridBagConstraints dbgGbc = new GridBagConstraints(); - dbgGbc.gridx = 0; dbgGbc.gridy = row; - dbgGbc.gridwidth = 2; - dbgGbc.anchor = GridBagConstraints.WEST; - dbgGbc.insets = new Insets(8, 8, 4, 8); - form.add(debugCheckBox, dbgGbc); + // --- executable path --- + form.add(new JLabel("Claude CLI path:"), gbc(0, row, false)); + executablePathField = new JTextField(30); + executablePathField.setToolTipText("Leave empty to detect 'claude' from PATH"); + form.add(executablePathField, gbcFill(1, row)); + JButton browseButton = new JButton("Browse\u2026"); + browseButton.addActionListener(e -> { + JFileChooser chooser = new JFileChooser(); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + executablePathField.setText( + chooser.getSelectedFile().getAbsolutePath()); + } + }); + form.add(browseButton, gbc(2, row, false)); row++; // --- hang timeout --- @@ -318,6 +282,14 @@ private JPanel buildAdvancedPanel() { form.add(hangTimeoutSpinner, hangSpinnerGbc); row++; + // --- MCP port --- + form.add(new JLabel("MCP server port:"), gbc(0, row, false)); + mcpPortSpinner = new JSpinner(new SpinnerNumberModel( + ClaudeCodePreferences.DEFAULT_MCP_PORT, 1024, 65535, 1)); + mcpPortSpinner.setToolTipText("Port for the NetBeans MCP SSE server (restart required)"); + form.add(mcpPortSpinner, gbc(1, row, false)); + row++; + // --- MCP enabled --- mcpEnabledCheckBox = new javax.swing.JCheckBox("Enable MCP integration"); GridBagConstraints mcpGbc = new GridBagConstraints(); @@ -331,16 +303,52 @@ private JPanel buildAdvancedPanel() { JLabel mcpDesc = new JLabel("When disabled, the --mcp-config flag is not passed to claude. Hooks are always configured."); GridBagConstraints mcpDescGbc = new GridBagConstraints(); mcpDescGbc.gridx = 0; mcpDescGbc.gridy = row; - mcpDescGbc.gridwidth = 2; + mcpDescGbc.gridwidth = 3; + mcpDescGbc.fill = GridBagConstraints.HORIZONTAL; + mcpDescGbc.weightx = 1.0; mcpDescGbc.anchor = GridBagConstraints.WEST; mcpDescGbc.insets = new Insets(0, 28, 4, 8); form.add(mcpDesc, mcpDescGbc); row++; + // --- history max depth --- + form.add(new JLabel("History max depth:"), gbc(0, row, false)); + historyMaxDepthSpinner = new JSpinner(new SpinnerNumberModel( + ClaudeCodePreferences.DEFAULT_HISTORY_MAX_DEPTH, 1, 2000, 10)); + historyMaxDepthSpinner.setToolTipText("Maximum number of history entries to keep per project"); + form.add(historyMaxDepthSpinner, gbc(1, row, false)); + row++; + + // --- history TTL --- + form.add(new JLabel("History TTL (days, 0 = keep forever):"), gbc(0, row, false)); + historyTtlDaysSpinner = new JSpinner(new SpinnerNumberModel( + ClaudeCodePreferences.DEFAULT_HISTORY_TTL_DAYS, 0, 3650, 1)); + historyTtlDaysSpinner.setToolTipText("Delete history entries older than this many days (0 = keep forever)"); + form.add(historyTtlDaysSpinner, gbc(1, row, false)); + row++; + + // --- session list limit --- + form.add(new JLabel("Session list limit:"), gbc(0, row, false)); + sessionListLimitSpinner = new JSpinner(new SpinnerNumberModel( + ClaudeCodePreferences.DEFAULT_SESSION_LIST_LIMIT, 1, 500, 5)); + sessionListLimitSpinner.setToolTipText("Maximum number of sessions shown in the session list"); + form.add(sessionListLimitSpinner, gbc(1, row, false)); + row++; + + // --- debug mode --- + debugCheckBox = new javax.swing.JCheckBox("Debug mode (log all claude I/O to NetBeans log and output area)"); + GridBagConstraints dbgGbc = new GridBagConstraints(); + dbgGbc.gridx = 0; dbgGbc.gridy = row; + dbgGbc.gridwidth = 2; + dbgGbc.anchor = GridBagConstraints.WEST; + dbgGbc.insets = new Insets(8, 8, 4, 8); + form.add(debugCheckBox, dbgGbc); + row++; + // spacer GridBagConstraints spacer = new GridBagConstraints(); spacer.gridx = 0; spacer.gridy = row; - spacer.gridwidth = 2; spacer.weighty = 1.0; + spacer.gridwidth = 3; spacer.weighty = 1.0; spacer.fill = GridBagConstraints.VERTICAL; form.add(new JPanel(), spacer);