Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Added Advanced tab in Tools → Options → Claude Code with Debug mode, Hang timeout, and a new "Enable MCP integration" toggle (disabling it skips the --mcp-config flag while hooks remain active)
- Fixed process start errors and hang timeouts now logged to the IDE log file at SEVERE level
- Added hang detection: configurable timeout (default 60 s) kills the process and shows an error if no PTY output is received after launch; set to 0 to disable
- Fixed authentication for profiles with the "Claude API" connection type: the API key is now correctly recognised by Claude Code on session start
Expand Down
Binary file added docs/screenshots/settings-advanced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/settings-favorites.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/settings-general.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 20 additions & 3 deletions docs/user-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ Open **Tools → Options → Claude Code** in NetBeans.

### General tab

![Settings — General tab](screenshots/settings-general.png)

| Setting | Default | Description |
|---------|---------|-------------|
| Claude CLI path | (empty) | Absolute path to the `claude` executable. Leave empty to use the system `PATH`. |
Expand All @@ -341,14 +343,25 @@ Open **Tools → Options → Claude Code** in NetBeans.
| 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. |
| Debug mode | Off | Enables verbose logging of all Claude I/O to the NetBeans log file and the Output window. |
| Open diff in a separate tab | Off | Opens the diff panel in a new IDE tab instead of embedding it in the session tab. |
| Show markdown preview for .md files in diff | On | Shows a rendered markdown preview alongside the raw diff for `.md` files. |
| 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. |

### Advanced tab

![Settings — Advanced tab](screenshots/settings-advanced.png)

| Setting | Default | Description |
|---------|---------|-------------|
| Debug mode | Off | Enables verbose logging of all Claude I/O to the NetBeans log file and the Output window. |
| Hang timeout (seconds) | 60 | Kill the process if no PTY output is received within this many seconds after launch. Set to 0 to disable. |
| 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. |

### Favorites tab

![Settings — Favorites tab](screenshots/settings-favorites.png)

Manages global favorites — prompts available in every project.

The table shows all global favorites with columns: ☐ (checkbox for multi-select), **Text**, **Shortcut**.
Expand All @@ -365,6 +378,10 @@ The table shows all global favorites with columns: ☐ (checkbox for multi-selec

The search field filters entries by text.

### Profiles tab

See [Section 12 — Profiles](#12-profiles) for full details on creating and managing profiles.

---

## 12. Profiles
Expand Down Expand Up @@ -651,14 +668,14 @@ 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.
2. Enable **Debug mode** and check the log file (`~/.netbeans/<version>/var/log/messages.log`) for `MCP SSE server started on port`.
2. Enable **Debug mode** (**Tools → Options → Claude Code → Advanced**) and check the log file (`~/.netbeans/<version>/var/log/messages.log`) for `MCP SSE server started on port`.

---

## 15. Troubleshooting

### Enable debug mode
Go to **Tools → Options → Claude Code → General** and check **Debug mode**. This writes detailed logs of all Claude I/O (PTY bytes, MCP messages, hook calls) to the NetBeans log file.
Go to **Tools → Options → Claude Code → Advanced** and check **Debug mode**. This writes detailed logs of all Claude I/O (PTY bytes, MCP messages, hook calls) to the NetBeans log file.

### Log file location
```
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.nbclaudecodegui</groupId>
<artifactId>netbeans-claude-code-gui</artifactId>
<version>0.21.34-SNAPSHOT</version>
<version>0.21.36-SNAPSHOT</version>
<packaging>nbm</packaging>
<name>Netbeans Claude Code GUI</name>
<description>NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,15 @@ public PtyProcess start(String workingDir, ClaudeProfile profile, String extraCl
+ ", port=" + (mcp != null ? mcp.getServerPort() : -1));
if (mcp != null && mcp.isServerRunning()) {
int port = mcp.getServerPort();
// Pass MCP server config via --mcp-config (Claude 2.x no longer reads
// mcpServers from settings.local.json; --mcp-config works in TUI mode).
cmd.add("--mcp-config");
cmd.add(buildMcpConfigJson(port));
LOG.info("Passing --mcp-config with netbeans SSE server on port " + port);
if (io.github.nbclaudecodegui.settings.ClaudeCodePreferences.isMcpEnabled()) {
// Pass MCP server config via --mcp-config (Claude 2.x no longer reads
// mcpServers from settings.local.json; --mcp-config works in TUI mode).
cmd.add("--mcp-config");
cmd.add(buildMcpConfigJson(port));
LOG.info("Passing --mcp-config with netbeans SSE server on port " + port);
} else {
LOG.info("MCP integration disabled by user preference; skipping --mcp-config");
}
try {
writeSettingsLocalJson(workingDir, port, profile);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public final class ClaudeCodeOptionsPanel extends JPanel {
private JSpinner sessionListLimitSpinner;
/** Spinner for the hang-detection timeout in seconds (0 = disabled). */
private JSpinner hangTimeoutSpinner;
/** Checkbox to enable MCP integration (pass --mcp-config flag). */
private javax.swing.JCheckBox mcpEnabledCheckBox;

/** send-key radio buttons: value → button */
private final Map<String, JRadioButton> sendRadios = new LinkedHashMap<>();
Expand Down Expand Up @@ -99,6 +101,7 @@ private void initComponents() {

JTabbedPane tabs = new JTabbedPane();
tabs.addTab("General", buildGeneralPanel());
tabs.addTab("Advanced", buildAdvancedPanel());
tabs.addTab("Favorites", favoritesPanel);
tabs.addTab("Profiles", profilesPanel);
add(tabs, BorderLayout.CENTER);
Expand Down Expand Up @@ -181,16 +184,6 @@ private JPanel buildGeneralPanel() {
newlineRadios.get(val).addActionListener(e -> syncExclusion(val, false));
}

// --- 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 = 3;
dbgGbc.anchor = GridBagConstraints.WEST;
dbgGbc.insets = new Insets(4, 8, 4, 8);
form.add(debugCheckBox, dbgGbc);
row++;

// --- diff in session ---
diffInSessionCheck = new javax.swing.JCheckBox("Open diff in a separate tab");
GridBagConstraints diffGbc = new GridBagConstraints();
Expand Down Expand Up @@ -229,18 +222,68 @@ private JPanel buildGeneralPanel() {
form.add(sessionListLimitSpinner, gbc(1, row, false));
row++;

// spacer
GridBagConstraints spacer = new GridBagConstraints();
spacer.gridx = 0; spacer.gridy = row;
spacer.gridwidth = 3; spacer.weighty = 1.0;
spacer.fill = GridBagConstraints.VERTICAL;
form.add(new JPanel(), spacer);

return form;
}

/**
* Builds the Advanced tab containing debug and hang-timeout settings.
*
* @return the Advanced tab panel
*/
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);
row++;

// --- hang timeout ---
form.add(new JLabel("Hang timeout (seconds, 0=disabled):"), gbc(0, row, false));
hangTimeoutSpinner = new JSpinner(new SpinnerNumberModel(
ClaudeCodePreferences.DEFAULT_HANG_TIMEOUT_SECONDS, 0, 3600, 5));
hangTimeoutSpinner.setToolTipText("Kill the process if no PTY output is received within this many seconds after launch (0 = disabled)");
form.add(hangTimeoutSpinner, gbc(1, row, false));
GridBagConstraints hangSpinnerGbc = gbc(1, row, false);
hangSpinnerGbc.weightx = 1.0;
form.add(hangTimeoutSpinner, hangSpinnerGbc);
row++;

// --- MCP enabled ---
mcpEnabledCheckBox = new javax.swing.JCheckBox("Enable MCP integration");
GridBagConstraints mcpGbc = new GridBagConstraints();
mcpGbc.gridx = 0; mcpGbc.gridy = row;
mcpGbc.gridwidth = 2;
mcpGbc.anchor = GridBagConstraints.WEST;
mcpGbc.insets = new Insets(12, 8, 0, 8);
form.add(mcpEnabledCheckBox, mcpGbc);
row++;

JLabel mcpDesc = new JLabel("<html><small>When disabled, the --mcp-config flag is not passed to claude. Hooks are always configured.</small></html>");
GridBagConstraints mcpDescGbc = new GridBagConstraints();
mcpDescGbc.gridx = 0; mcpDescGbc.gridy = row;
mcpDescGbc.gridwidth = 2;
mcpDescGbc.anchor = GridBagConstraints.WEST;
mcpDescGbc.insets = new Insets(0, 28, 4, 8);
form.add(mcpDesc, mcpDescGbc);
row++;

// spacer
GridBagConstraints spacer = new GridBagConstraints();
spacer.gridx = 0; spacer.gridy = row;
spacer.gridwidth = 3; spacer.weighty = 1.0;
spacer.gridwidth = 2; spacer.weighty = 1.0;
spacer.fill = GridBagConstraints.VERTICAL;
form.add(new JPanel(), spacer);

Expand Down Expand Up @@ -315,6 +358,7 @@ void load() {
== io.github.nbclaudecodegui.model.SessionMode.NEW);
sessionListLimitSpinner.setValue(ClaudeCodePreferences.getSessionListLimit());
hangTimeoutSpinner.setValue(ClaudeCodePreferences.getHangTimeoutSeconds());
mcpEnabledCheckBox.setSelected(ClaudeCodePreferences.isMcpEnabled());

String sendVal = ClaudeCodePreferences.getSendKey();
String newlineVal = ClaudeCodePreferences.getNewlineKey();
Expand Down Expand Up @@ -348,6 +392,7 @@ void store() {
: io.github.nbclaudecodegui.model.SessionMode.CONTINUE_LAST);
ClaudeCodePreferences.setSessionListLimit((Integer) sessionListLimitSpinner.getValue());
ClaudeCodePreferences.setHangTimeoutSeconds((Integer) hangTimeoutSpinner.getValue());
ClaudeCodePreferences.setMcpEnabled(mcpEnabledCheckBox.isSelected());
ClaudeCodePreferences.setSendKey(selectedValue(sendRadios));
ClaudeCodePreferences.setNewlineKey(selectedValue(newlineRadios));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,32 @@ public static void setHangTimeoutSeconds(int v) {
.putInt(KEY_HANG_TIMEOUT_SECONDS, Math.max(0, Math.min(3600, v)));
}

// -------------------------------------------------------------------------
// mcpEnabled
// -------------------------------------------------------------------------

/** Preference key: pass {@code --mcp-config} flag to claude CLI. */
private static final String MCP_ENABLED = "mcpEnabled";

/**
* Returns whether MCP integration is enabled (default {@code true}).
*
* @return {@code true} to pass {@code --mcp-config}; {@code false} to skip it
*/
public static boolean isMcpEnabled() {
return NbPreferences.forModule(ClaudeCodePreferences.class)
.getBoolean(MCP_ENABLED, true);
}

/**
* Persists the MCP-enabled flag.
*
* @param v {@code true} to enable MCP integration
*/
public static void setMcpEnabled(boolean v) {
NbPreferences.forModule(ClaudeCodePreferences.class).putBoolean(MCP_ENABLED, v);
}

private static String validated(String value, String fallback) {
return ENTER.equals(value) || SHIFT_ENTER.equals(value)
|| CTRL_ENTER.equals(value) || ALT_ENTER.equals(value)
Expand Down
Loading