From 92745c6353d2ec65bf6dcef5bd8ae7d0bedec1d6 Mon Sep 17 00:00:00 2001 From: Oleg Samarin Date: Thu, 8 Oct 2026 18:17:47 +0300 Subject: [PATCH] Improved the IDE log: per-request diagnostics are now written only with debug logging enabled Moved tab label polling, PreToolUse hook, diff tab, permission prompt, choice menu and similar per-request/per-click messages from INFO to FINE. The PreToolUse hook no longer logs the full request body (which contained edited file contents); only its size and the file path are logged. Removed the debug-only project comparison loop from resolveTabLabel, which ran every 15 seconds per open tab. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 2 ++ pom.xml | 2 +- .../controller/ClaudeSessionController.java | 2 +- .../nbplugins/claudecodegui/mcp/MCPSseServer.java | 2 +- .../claudecodegui/mcp/NetBeansMCPHandler.java | 13 +++++++------ .../claudecodegui/mcp/tools/DiffTabTracker.java | 12 ++++++------ .../claudecodegui/mcp/tools/GetDiagnostics.java | 2 +- .../nbplugins/claudecodegui/mcp/tools/OpenDiff.java | 6 +++--- .../mcp/tools/PermissionPromptTool.java | 12 ++++++------ .../claudecodegui/process/ClaudeProcess.java | 2 +- .../claudecodegui/settings/ModelAliasesDialog.java | 2 +- .../nbplugins/claudecodegui/ui/ChoiceMenuPanel.java | 10 +++++----- .../ui/ClaudeSessionSelectorPanel.java | 11 +---------- 13 files changed, 36 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf97b36..f27d061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +- Improved the IDE log (messages.log): per-request and per-click diagnostics (tab label polling, PreToolUse hooks with file contents, diff tabs, choice menus, permission prompts) are now written only when debug logging is enabled, so the log is no longer flooded and no longer contains edited code + # 1.3.28 (2026-10-07) - Fixed subagents and background requests failing with "model is not supported when using Codex with a ChatGPT account" for ChatGPT Subscription profiles: model aliases from the Model Aliases dialog (e.g. haiku, sonnet) are now applied to ChatGPT Subscription sessions too diff --git a/pom.xml b/pom.xml index 4c0fbcb..ca0c1a1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.nbplugins netbeans-plugin-claude-code-gui - 1.3.51-SNAPSHOT + 1.3.53-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 68e379b..cc2bbc8 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionController.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/controller/ClaudeSessionController.java @@ -801,7 +801,7 @@ private void sendShiftTabsUntilMode(EditMode targetMode) { modeSwitchInProgress = true; Thread t = new Thread(() -> { try { - LOG.info("sendShiftTabsUntilMode: target=" + targetMode + LOG.fine("sendShiftTabsUntilMode: target=" + targetMode + " currentModel=" + model.getEditMode()); if (trySendShiftTabsUntilMode(targetMode)) return; // AUTO mode not found — older CC doesn't support it; try fallbacks diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/MCPSseServer.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/MCPSseServer.java index baf25e0..85b3982 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/MCPSseServer.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/MCPSseServer.java @@ -281,7 +281,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) bodyBytes = in.readAllBytes(); } String body = new String(bodyBytes, StandardCharsets.UTF_8); - LOGGER.log(Level.INFO, "PreToolUse hook received: {0}", body); + LOGGER.log(Level.FINE, "PreToolUse hook received: {0} bytes", bodyBytes.length); jakarta.servlet.AsyncContext asyncCtx = req.startAsync(req, resp); asyncCtx.setTimeout(590_000L); diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/NetBeansMCPHandler.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/NetBeansMCPHandler.java index c0c4cf0..6fc78ea 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/NetBeansMCPHandler.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/NetBeansMCPHandler.java @@ -387,7 +387,7 @@ private void sendAsyncToolResponse(Integer requestId, Object result, if (!sessionQueue.offer(json)) { LOGGER.warning("SSE session queue full; async tool response dropped"); } - LOGGER.log(Level.INFO, "Sent async tool response for request ID: {0}", requestId); + LOGGER.log(Level.FINE, "Sent async tool response for request ID: {0}", requestId); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error sending async tool response", e); } @@ -519,10 +519,10 @@ public CompletableFuture handlePreToolUse(String hookJson) { String toolName = hook.has("tool_name") ? hook.get("tool_name").asText() : ""; JsonNode toolInput = hook.has("tool_input") ? hook.get("tool_input") : objectMapper.createObjectNode(); - LOGGER.info("handlePreToolUse: tool=" + toolName); + LOGGER.fine("handlePreToolUse: tool=" + toolName); if (!isFileEditTool(toolName)) { - LOGGER.info("Auto-allowing non-file-edit tool: " + toolName); + LOGGER.fine("Auto-allowing non-file-edit tool: " + toolName); return CompletableFuture.completedFuture(hookAllowJson()); } @@ -531,16 +531,17 @@ public CompletableFuture handlePreToolUse(String hookJson) { EditMode editMode = getEditModeForCwd(cwd); // Session root is the key that matched in the registry (may differ from hook cwd when Claude cd'd into a subdir) String sessionRoot = getSessionRootForCwd(cwd); - LOGGER.info("handlePreToolUse: editMode=" + editMode + " cwd=" + cwd + " sessionRoot=" + sessionRoot); String filePath = getFilePath(toolInput); + LOGGER.fine("handlePreToolUse: editMode=" + editMode + " file=" + filePath + + " cwd=" + cwd + " sessionRoot=" + sessionRoot); // AUTO or higher (BYPASS_PERMISSIONS): auto-allow regardless of location // ACCEPT_EDITS or higher (but below AUTO): auto-allow only inside the session root if (editMode.ordinal() >= EditMode.AUTO.ordinal() || (editMode.ordinal() >= EditMode.ACCEPT_EDITS.ordinal() && io.github.nbplugins.claudecodegui.ui.FileDiffOpener.isFileUnderDirectory(filePath, sessionRoot))) { - LOGGER.info(editMode.key() + " mode — auto-allowing: " + filePath); + LOGGER.fine(editMode.key() + " mode — auto-allowing: " + filePath); return CompletableFuture.completedFuture(hookAllowJson()); } // PLAN / DEFAULT / ACCEPT_EDITS-outside: fall through to show diff dialog @@ -946,7 +947,7 @@ private void stopDiffTabTracking() { private void handleDiffTabClosed(String tabName) { AsyncHandler handler = DiffTabTracker.remove(tabName); if (handler != null) { - LOGGER.log(Level.INFO, "Diff tab closed: {0}", tabName); + LOGGER.log(Level.FINE, "Diff tab closed: {0}", tabName); // Create response with DIFF_REJECTED status List contentList = new ArrayList<>(); diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/DiffTabTracker.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/DiffTabTracker.java index 04ac687..88f7052 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/DiffTabTracker.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/DiffTabTracker.java @@ -31,7 +31,7 @@ private DiffTabTracker() {} * @param handler Handler to call when the diff is accepted or rejected */ public static void register(String tabName, AsyncHandler handler) { - LOGGER.info("Registering async handler for diff tab: " + tabName); + LOGGER.fine("Registering async handler for diff tab: " + tabName); pendingDiffs.put(tabName, handler); } @@ -43,7 +43,7 @@ public static void register(String tabName, AsyncHandler handler) { public static AsyncHandler remove(String tabName) { AsyncHandler handler = pendingDiffs.remove(tabName); if (handler != null) { - LOGGER.info("Removed async handler for diff tab: " + tabName); + LOGGER.fine("Removed async handler for diff tab: " + tabName); } return handler; } @@ -74,12 +74,12 @@ public static void setResponse(String tabName, OpenDiffResult result) { public static void setRejected(String tabName) { AsyncHandler handler = pendingDiffs.remove(tabName); if (handler != null) { - LOGGER.info("Diff rejected for tab: " + tabName); + LOGGER.fine("Diff rejected for tab: " + tabName); java.util.List contentList = new java.util.ArrayList<>(); contentList.add(new org.openbeans.claude.netbeans.tools.params.Content("text", "FILE_REJECTED")); handler.sendResponse(new OpenDiffResult(contentList)); } else { - LOGGER.info("No pending handler for tab (already resolved or never registered): " + tabName); + LOGGER.fine("No pending handler for tab (already resolved or never registered): " + tabName); } } @@ -103,7 +103,7 @@ public static boolean isTracked(String tabName) { * @return the future that will be completed with {@code "allow"} or {@code "deny"} */ public static CompletableFuture registerHookFuture(String tabName) { - LOGGER.info("Registering hook future for tab: " + tabName); + LOGGER.fine("Registering hook future for tab: " + tabName); CompletableFuture future = new CompletableFuture<>(); pendingHookFutures.put(tabName, future); return future; @@ -118,7 +118,7 @@ public static CompletableFuture registerHookFuture(String tabName) { public static void resolveHook(String tabName, String jsonResponse) { CompletableFuture future = pendingHookFutures.remove(tabName); if (future != null) { - LOGGER.info("Hook resolved for tab: " + tabName); + LOGGER.fine("Hook resolved for tab: " + tabName); future.complete(jsonResponse); } } diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/GetDiagnostics.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/GetDiagnostics.java index 85bef49..22489d5 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/GetDiagnostics.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/GetDiagnostics.java @@ -207,7 +207,7 @@ protected List extractDiagnosticsFromFile(String filePath) { } List errors = getErrorDescriptions(fileObject); - LOGGER.log(Level.INFO, "getDiagnostics: {0} errors for {1}", + LOGGER.log(Level.FINE, "getDiagnostics: {0} errors for {1}", new Object[]{errors.size(), filePath}); for (ErrorDescription ed : errors) { diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/OpenDiff.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/OpenDiff.java index fea7461..d65b744 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/OpenDiff.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/OpenDiff.java @@ -236,7 +236,7 @@ public Writer createWriter(Difference[] conflicts) throws IOException { approveButton.setToolTipText("Approve and apply this diff"); approveButton.addActionListener(e -> { // Get the handler from DiffTabTracker - LOGGER.info("Diff approved: " + finalDiffTabName); + LOGGER.fine("Diff approved: " + finalDiffTabName); //NOTE: While the message says FILE_SAVED, the IDE does not need to save it. Claude will want to write to it. @@ -255,7 +255,7 @@ public Writer createWriter(Difference[] conflicts) throws IOException { javax.swing.JButton rejectButton = new javax.swing.JButton("✗ Reject"); rejectButton.setToolTipText("Reject this diff — Claude will not apply the change"); rejectButton.addActionListener(e -> { - LOGGER.info("Diff rejected by user: " + finalDiffTabName); + LOGGER.fine("Diff rejected by user: " + finalDiffTabName); DiffTabTracker.setRejected(finalDiffTabName); diffTC.close(); }); @@ -277,7 +277,7 @@ public Writer createWriter(Difference[] conflicts) throws IOException { return new AsyncResponse() { @Override public void setHandler(AsyncHandler handler) { - LOGGER.info("Registering async handler for diff tab: " + finalDiffTabName); + LOGGER.fine("Registering async handler for diff tab: " + finalDiffTabName); DiffTabTracker.register(finalDiffTabName, handler); } }; diff --git a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/PermissionPromptTool.java b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/PermissionPromptTool.java index d873240..0cbb223 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/PermissionPromptTool.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/mcp/tools/PermissionPromptTool.java @@ -99,11 +99,11 @@ public AsyncResponse> run(Params params) throws Exception { String toolName = params.getToolName(); JsonNode toolInput = params.getToolInput(); - LOGGER.info("permission_prompt called for tool: " + toolName); + LOGGER.fine("permission_prompt called for tool: " + toolName); // For non-file-editing tools, auto-allow. if (!isFileEditTool(toolName)) { - LOGGER.info("Auto-allowing non-file-edit tool: " + toolName); + LOGGER.fine("Auto-allowing non-file-edit tool: " + toolName); return syncAllow(); } @@ -126,22 +126,22 @@ public AsyncResponse> run(Params params) throws Exception { return handler -> FileDiffOpener.open(filePath, before, after, finalTabName, null, () -> { - LOGGER.info("Permission granted for tab: " + finalTabName); + LOGGER.fine("Permission granted for tab: " + finalTabName); AsyncHandler> h = DiffTabTracker.remove(finalTabName); if (h != null) h.sendResponse(allowResult()); }, reason -> { // reason is not forwarded in the MCP protocol — tool returns just "deny" - LOGGER.info("Permission denied for tab: " + finalTabName); + LOGGER.fine("Permission denied for tab: " + finalTabName); DiffTabTracker.setRejected(finalTabName); }, () -> { - LOGGER.info("Permission cancelled for tab: " + finalTabName); + LOGGER.fine("Permission cancelled for tab: " + finalTabName); DiffTabTracker.setRejected(finalTabName); FileDiffOpener.cancelCurrentPromptForFile(filePath); }, () -> { - LOGGER.info("Permission tab closed for tab: " + finalTabName); + LOGGER.fine("Permission tab closed for tab: " + finalTabName); if (DiffTabTracker.isTracked(finalTabName)) { DiffTabTracker.setRejected(finalTabName); } diff --git a/src/main/java/io/github/nbplugins/claudecodegui/process/ClaudeProcess.java b/src/main/java/io/github/nbplugins/claudecodegui/process/ClaudeProcess.java index 8e2b249..137ef3c 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/process/ClaudeProcess.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/process/ClaudeProcess.java @@ -235,7 +235,7 @@ public PtyProcess start(String workingDir, ClaudeProfile profile, String extraCl List cmd = new ArrayList<>(); cmd.add(executable); ClaudeCodeStatusService mcp = Lookup.getDefault().lookup(ClaudeCodeStatusService.class); - LOG.info("MCP service lookup: " + (mcp == null ? "null" : mcp.getClass().getName()) + LOG.fine("MCP service lookup: " + (mcp == null ? "null" : mcp.getClass().getName()) + ", running=" + (mcp != null && mcp.isServerRunning()) + ", port=" + (mcp != null ? mcp.getServerPort() : -1)); if (mcp != null && mcp.isServerRunning()) { diff --git a/src/main/java/io/github/nbplugins/claudecodegui/settings/ModelAliasesDialog.java b/src/main/java/io/github/nbplugins/claudecodegui/settings/ModelAliasesDialog.java index 8911d2a..06b5e63 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/settings/ModelAliasesDialog.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/settings/ModelAliasesDialog.java @@ -323,7 +323,7 @@ private void onFetch() { try { List ids = get(); applyFetchedIds(ids); - LOG.info("Fetch models: " + ids.size() + " models returned"); + LOG.fine("Fetch models: " + ids.size() + " models returned"); setStatus("Fetched " + ids.size() + " models, " + countAvailable() + " available", false); } catch (Exception ex) { Throwable cause = ex.getCause() != null ? ex.getCause() : ex; diff --git a/src/main/java/io/github/nbplugins/claudecodegui/ui/ChoiceMenuPanel.java b/src/main/java/io/github/nbplugins/claudecodegui/ui/ChoiceMenuPanel.java index 2b28eea..21c46e4 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/ui/ChoiceMenuPanel.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/ui/ChoiceMenuPanel.java @@ -99,7 +99,7 @@ public void show(ChoiceMenuModel model, Consumer callback, boolean grabF // --- Question label — full width --- String questionText = model.text(); - LOG.info("[ChoiceMenuPanel] question: " + questionText); + LOG.fine("[ChoiceMenuPanel] question: " + questionText); if (questionText != null && !questionText.isBlank()) { JLabel questionLabel = new JLabel("" + escapeHtml(questionText) + ""); questionLabel.setFont(questionLabel.getFont().deriveFont(questionLabel.getFont().getSize() * 1.5f)); @@ -128,7 +128,7 @@ public void show(ChoiceMenuModel model, Consumer callback, boolean grabF JButton btn = new JButton(label); UiUtils.applyActionStyle(btn, display.equalsIgnoreCase("Yes")); btn.addActionListener(e -> { - LOG.info("[ChoiceMenuPanel] yes/no clicked: \"" + display + "\" → \"" + response + "\""); + LOG.fine("[ChoiceMenuPanel] yes/no clicked: \"" + display + "\" → \"" + response + "\""); submitAnswer(response); }); yesNoBtns.add(btn); @@ -278,7 +278,7 @@ public void keyPressed(java.awt.event.KeyEvent e) { JButton cancelBtn = new JButton("Cancel"); cancelBtn.setAlignmentX(Component.CENTER_ALIGNMENT); cancelBtn.addActionListener(e -> { - LOG.info("[ChoiceMenuPanel] Cancel clicked"); + LOG.fine("[ChoiceMenuPanel] Cancel clicked"); cancel(); }); rightCol.add(cancelBtn); @@ -821,7 +821,7 @@ public void keyPressed(java.awt.event.KeyEvent e) { /** Hides the panel if a prompt is still pending (called when Claude accepted input via terminal). */ public void dismissIfActive() { if (callback != null) { - LOG.info("[ChoiceMenuPanel] dismissing — Claude accepted terminal input"); + LOG.fine("[ChoiceMenuPanel] dismissing — Claude accepted terminal input"); Consumer cb = callback; setVisible(false); callback = null; @@ -891,7 +891,7 @@ public Dimension getMinimumSize() { private void submitAnswer(String answer) { Consumer cb = callback; - LOG.info("[ChoiceMenuPanel] submitAnswer: \"" + answer + "\", cb=" + cb); + LOG.fine("[ChoiceMenuPanel] submitAnswer: \"" + answer + "\""); setVisible(false); callback = null; removeAll(); diff --git a/src/main/java/io/github/nbplugins/claudecodegui/ui/ClaudeSessionSelectorPanel.java b/src/main/java/io/github/nbplugins/claudecodegui/ui/ClaudeSessionSelectorPanel.java index 85b40fc..3f07ff4 100644 --- a/src/main/java/io/github/nbplugins/claudecodegui/ui/ClaudeSessionSelectorPanel.java +++ b/src/main/java/io/github/nbplugins/claudecodegui/ui/ClaudeSessionSelectorPanel.java @@ -348,15 +348,6 @@ public static String resolveTabLabel(File dir) { return NbBundle.getMessage(ClaudeSessionSelectorPanel.class, "TAB_NewSession"); } Project[] openProjects = OpenProjects.getDefault().getOpenProjects(); - LOG.info("resolveTabLabel: dir=" + dir.getAbsolutePath() - + " openProjects=" + openProjects.length); - for (Project p : openProjects) { - File projDir = FileUtil.toFile(p.getProjectDirectory()); - String projName = ProjectUtils.getInformation(p).getDisplayName(); - LOG.info(" comparing with project '" + projName - + "' dir=" + (projDir != null ? projDir.getAbsolutePath() : "null") - + " equal=" + dir.equals(projDir)); - } for (Project p : openProjects) { File projDir = FileUtil.toFile(p.getProjectDirectory()); if (projDir == null) continue; @@ -365,7 +356,7 @@ public static String resolveTabLabel(File dir) { } try { if (dir.getCanonicalPath().equals(projDir.getCanonicalPath())) { - LOG.info(" canonical match found for project '" + LOG.fine(" canonical match found for project '" + ProjectUtils.getInformation(p).getDisplayName() + "'"); return ProjectUtils.getInformation(p).getDisplayName(); }