Improve plan mode display and permission prompt

- Render ExitPlanMode as formatted markdown plan with proper headings,
  lists, and code blocks instead of raw key-value dump
- Show allowed prompts as clickable action buttons below the plan
- Use 📋 Plan header instead of 🔧 ExitPlanMode
- Permission prompt says "Approve the plan above?" with Approve button
- Hide "Always allow" for plan approvals
- Full height plan content without scroll constraint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
andrepimenta
2026-04-14 21:18:52 +01:00
parent 6d112012b2
commit 58de99030c
4 changed files with 97 additions and 9 deletions

View File

@@ -6,7 +6,7 @@
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERSION="2.0.2"
VERSION="2.0.3"
OUTPUT_NAME="vsix-claude-code-chat-${VERSION}.vsix"
echo "Building Open VSIX version ${VERSION}..."

View File

@@ -2,7 +2,7 @@
"name": "claude-code-chat",
"displayName": "Chat for Claude Code",
"description": "Beautiful Claude Code Chat Interface for VS Code",
"version": "2.0.2",
"version": "2.0.3",
"publisher": "AndrePimenta",
"author": "Andre Pimenta",
"repository": {

View File

@@ -207,14 +207,15 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
const iconDiv = document.createElement('div');
iconDiv.className = 'tool-icon';
iconDiv.textContent = '🔧';
iconDiv.textContent = data.toolName === 'ExitPlanMode' ? '📋' : '🔧';
const toolInfoElement = document.createElement('div');
toolInfoElement.className = 'tool-info';
let toolName = data.toolInfo.replace('🔧 Executing: ', '');
// Replace TodoWrite with more user-friendly name
if (toolName === 'TodoWrite') {
toolName = 'Update Todos';
} else if (toolName === 'ExitPlanMode') {
toolName = 'Plan';
}
toolInfoElement.textContent = toolName;
@@ -287,6 +288,8 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
} else {
contentDiv.innerHTML = formatWriteToolDiff(data.rawInput, data.fileContentBefore, showButton);
}
} else if (data.toolName === 'ExitPlanMode' && data.rawInput) {
contentDiv.innerHTML = formatPlanOutput(data.rawInput);
} else {
contentDiv.innerHTML = formatToolInputUI(data.rawInput);
}
@@ -464,6 +467,34 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
scrollToBottomIfNeeded(messagesDiv, shouldScroll);
}
function formatPlanOutput(input) {
var html = '';
// Render plan markdown
if (input.plan) {
html += '<div class="plan-content">' + parseSimpleMarkdown(input.plan) + '</div>';
}
// Render allowed prompts as action buttons
if (input.allowedPrompts && input.allowedPrompts.length > 0) {
html += '<div class="plan-actions">';
html += '<div class="plan-actions-label">Suggested actions:</div>';
input.allowedPrompts.forEach(function(p) {
var label = p.prompt || (p.tool + ' command');
var escapedPrompt = escapeHtml(label).replace(/'/g, '&#39;');
html += '<button class="plan-action-btn" onclick="sendPlanAction(&#39;' + escapedPrompt + '&#39;)" title="' + escapeHtml(p.tool) + '">' + escapeHtml(label) + '</button>';
});
html += '</div>';
}
return html;
}
function sendPlanAction(prompt) {
messageInput.value = prompt;
sendMessage();
}
function formatToolInputUI(input) {
if (!input || typeof input !== 'object') {
const str = String(input);
@@ -3796,7 +3827,8 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
messageDiv.id = \`permission-\${data.id}\`;
messageDiv.dataset.status = data.status || 'pending';
const toolName = data.tool || 'Unknown Tool';
let toolName = data.tool || 'Unknown Tool';
if (toolName === 'ExitPlanMode') toolName = 'Approve Plan';
const status = data.status || 'pending';
// Create always allow button text with command styling for Bash
@@ -3832,11 +3864,11 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
</div>
</div>
<div class="permission-content">
<p>Allow <strong>\${toolName}</strong> to execute the tool call above?</p>
<p>\${data.tool === 'ExitPlanMode' ? 'Approve the plan above?' : 'Allow <strong>' + toolName + '</strong> to execute the tool call above?'}</p>
<div class="permission-buttons">
<button class="btn deny" onclick="respondToPermission('\${data.id}', false)">Deny</button>
<button class="btn always-allow" onclick="respondToPermission('\${data.id}', true, true)" \${alwaysAllowTooltip}>\${alwaysAllowText}</button>
<button class="btn allow" onclick="respondToPermission('\${data.id}', true)">Allow</button>
\${data.tool === 'ExitPlanMode' ? '' : '<button class="btn always-allow" onclick="respondToPermission(\\'' + data.id + '\\', true, true)" ' + alwaysAllowTooltip + '>' + alwaysAllowText + '</button>'}
<button class="btn allow" onclick="respondToPermission('\${data.id}', true)">\${data.tool === 'ExitPlanMode' ? 'Approve' : 'Allow'}</button>
</div>
</div>
\`;

View File

@@ -1324,6 +1324,62 @@ const styles = `
opacity: 0.95;
}
.plan-content {
font-size: 13px;
line-height: 1.6;
}
.plan-content h1, .plan-content h2, .plan-content h3 {
margin: 12px 0 6px;
font-weight: 600;
}
.plan-content h1 { font-size: 16px; }
.plan-content h2 { font-size: 14px; }
.plan-content h3 { font-size: 13px; }
.plan-content ul, .plan-content ol {
padding-left: 20px;
margin: 4px 0;
}
.plan-content code {
font-family: var(--vscode-editor-font-family);
font-size: 12px;
background: rgba(127, 127, 127, 0.15);
padding: 1px 4px;
border-radius: 3px;
}
.plan-actions {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--vscode-panel-border);
}
.plan-actions-label {
font-size: 11px;
color: var(--vscode-descriptionForeground);
margin-bottom: 8px;
}
.plan-action-btn {
display: inline-block;
background: var(--vscode-button-secondaryBackground, rgba(128, 128, 128, 0.2));
color: var(--vscode-button-secondaryForeground, var(--vscode-foreground));
border: 1px solid var(--vscode-panel-border);
padding: 5px 12px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
margin: 0 6px 6px 0;
}
.plan-action-btn:hover {
background: var(--vscode-list-hoverBackground);
border-color: var(--vscode-focusBorder);
}
/* Diff display styles for Edit tool */
.diff-container {
border: 1px solid var(--vscode-panel-border);