Ability to add permission

This commit is contained in:
andrepimenta
2025-07-09 00:19:14 +01:00
parent 3ec983188a
commit 1fa94b9c54
3 changed files with 298 additions and 0 deletions

View File

@@ -280,6 +280,9 @@ class ClaudeChatProvider {
case 'removePermission':
this._removePermission(message.toolName, message.command);
return;
case 'addPermission':
this._addPermission(message.toolName, message.command);
return;
}
}
@@ -1376,6 +1379,71 @@ class ClaudeChatProvider {
}
}
private async _addPermission(toolName: string, command: string | null): Promise<void> {
try {
const storagePath = this._context.storageUri?.fsPath;
if (!storagePath) return;
const permissionsUri = vscode.Uri.file(path.join(storagePath, 'permission-requests', 'permissions.json'));
let permissions: any = { alwaysAllow: {} };
try {
const content = await vscode.workspace.fs.readFile(permissionsUri);
permissions = JSON.parse(new TextDecoder().decode(content));
} catch {
// File doesn't exist, use default permissions
}
// Add the new permission
if (command === null || command === '') {
// Allow all commands for this tool
permissions.alwaysAllow[toolName] = true;
} else {
// Add specific command pattern
if (!permissions.alwaysAllow[toolName]) {
permissions.alwaysAllow[toolName] = [];
}
// Convert to array if it's currently set to true
if (permissions.alwaysAllow[toolName] === true) {
permissions.alwaysAllow[toolName] = [];
}
if (Array.isArray(permissions.alwaysAllow[toolName])) {
// For Bash commands, convert to pattern using existing logic
let commandToAdd = command;
if (toolName === 'Bash') {
commandToAdd = this.getCommandPattern(command);
}
// Add if not already present
if (!permissions.alwaysAllow[toolName].includes(commandToAdd)) {
permissions.alwaysAllow[toolName].push(commandToAdd);
}
}
}
// Ensure permissions directory exists
const permissionsDir = vscode.Uri.file(path.dirname(permissionsUri.fsPath));
try {
await vscode.workspace.fs.stat(permissionsDir);
} catch {
await vscode.workspace.fs.createDirectory(permissionsDir);
}
// Save updated permissions
const permissionsContent = new TextEncoder().encode(JSON.stringify(permissions, null, 2));
await vscode.workspace.fs.writeFile(permissionsUri, permissionsContent);
// Send updated permissions to UI
this._sendPermissions();
console.log(`Added permission for ${toolName}${command ? ` command: ${command}` : ' (all commands)'}`);
} catch (error) {
console.error('Error adding permission:', error);
}
}
public getMCPConfigPath(): string | undefined {
const storagePath = this._context.storageUri?.fsPath;
if (!storagePath) {return undefined;}

View File

@@ -360,6 +360,134 @@ const styles = `
opacity: 0.5;
}
/* Add Permission Form */
.permissions-add-section {
margin-top: 6px;
}
.permissions-show-add-btn {
background-color: transparent;
color: var(--vscode-descriptionForeground);
border: none;
border-radius: 3px;
padding: 6px 8px;
font-size: 11px;
cursor: pointer;
transition: all 0.2s ease;
font-weight: 400;
opacity: 0.7;
}
.permissions-show-add-btn:hover {
background-color: var(--vscode-list-hoverBackground);
opacity: 1;
}
.permissions-add-form {
margin-top: 8px;
padding: 12px;
border: 1px solid var(--vscode-panel-border);
border-radius: 6px;
background-color: var(--vscode-input-background);
animation: slideDown 0.2s ease;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.permissions-form-row {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 8px;
}
.permissions-tool-select {
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-panel-border);
border-radius: 3px;
padding: 4px 8px;
font-size: 12px;
min-width: 100px;
height: 24px;
flex-shrink: 0;
}
.permissions-command-input {
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-panel-border);
border-radius: 3px;
padding: 4px 8px;
font-size: 12px;
flex-grow: 1;
height: 24px;
font-family: var(--vscode-editor-font-family);
}
.permissions-command-input::placeholder {
color: var(--vscode-input-placeholderForeground);
}
.permissions-add-btn {
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
border-radius: 3px;
padding: 4px 12px;
font-size: 12px;
cursor: pointer;
transition: background-color 0.2s ease;
height: 24px;
font-weight: 500;
flex-shrink: 0;
}
.permissions-add-btn:hover {
background-color: var(--vscode-button-hoverBackground);
}
.permissions-add-btn:disabled {
background-color: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
cursor: not-allowed;
opacity: 0.5;
}
.permissions-cancel-btn {
background-color: transparent;
color: var(--vscode-foreground);
border: 1px solid var(--vscode-panel-border);
border-radius: 3px;
padding: 4px 12px;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
height: 24px;
font-weight: 500;
}
.permissions-cancel-btn:hover {
background-color: var(--vscode-list-hoverBackground);
border-color: var(--vscode-focusBorder);
}
.permissions-form-hint {
font-size: 11px;
color: var(--vscode-descriptionForeground);
font-style: italic;
line-height: 1.3;
}
/* WSL Alert */
.wsl-alert {
margin: 8px 12px;

102
src/ui.ts
View File

@@ -260,6 +260,35 @@ const html = `<!DOCTYPE html>
Loading permissions...
</div>
</div>
<div class="permissions-add-section">
<div id="addPermissionForm" class="permissions-add-form" style="display: none;">
<div class="permissions-form-row">
<select id="addPermissionTool" class="permissions-tool-select" onchange="toggleCommandInput()">
<option value="">Select tool...</option>
<option value="Bash">Bash</option>
<option value="Read">Read</option>
<option value="Edit">Edit</option>
<option value="Write">Write</option>
<option value="MultiEdit">MultiEdit</option>
<option value="Glob">Glob</option>
<option value="Grep">Grep</option>
<option value="LS">LS</option>
<option value="WebSearch">WebSearch</option>
<option value="WebFetch">WebFetch</option>
</select>
<div style="flex-grow: 1; display: flex;">
<input type="text" id="addPermissionCommand" class="permissions-command-input" placeholder="Command pattern (e.g., npm i *)" style="display: none;" />
</div>
<button id="addPermissionBtn" class="permissions-add-btn" onclick="addPermission()">Add</button>
</div>
<div id="permissionsFormHint" class="permissions-form-hint">
Select a tool to add always-allow permission.
</div>
</div>
<button id="showAddPermissionBtn" class="permissions-show-add-btn" onclick="showAddPermissionForm()">
+ add permission
</button>
</div>
</div>
<h3 style="margin-top: 24px; margin-bottom: 16px; font-size: 14px; font-weight: 600;">MCP Configuration (coming soon)</h3>
@@ -2540,6 +2569,79 @@ const html = `<!DOCTYPE html>
});
}
function showAddPermissionForm() {
document.getElementById('showAddPermissionBtn').style.display = 'none';
document.getElementById('addPermissionForm').style.display = 'block';
// Focus on the tool select dropdown
setTimeout(() => {
document.getElementById('addPermissionTool').focus();
}, 100);
}
function hideAddPermissionForm() {
document.getElementById('showAddPermissionBtn').style.display = 'flex';
document.getElementById('addPermissionForm').style.display = 'none';
// Clear form inputs
document.getElementById('addPermissionTool').value = '';
document.getElementById('addPermissionCommand').value = '';
document.getElementById('addPermissionCommand').style.display = 'none';
}
function toggleCommandInput() {
const toolSelect = document.getElementById('addPermissionTool');
const commandInput = document.getElementById('addPermissionCommand');
const hintDiv = document.getElementById('permissionsFormHint');
if (toolSelect.value === 'Bash') {
commandInput.style.display = 'block';
hintDiv.textContent = 'Use patterns like "npm i *" or "git add *" for specific commands.';
} else if (toolSelect.value === '') {
commandInput.style.display = 'none';
commandInput.value = '';
hintDiv.textContent = 'Select a tool to add always-allow permission.';
} else {
commandInput.style.display = 'none';
commandInput.value = '';
hintDiv.textContent = 'This will allow all ' + toolSelect.value + ' commands without asking for permission.';
}
}
function addPermission() {
const toolSelect = document.getElementById('addPermissionTool');
const commandInput = document.getElementById('addPermissionCommand');
const addBtn = document.getElementById('addPermissionBtn');
const toolName = toolSelect.value.trim();
const command = commandInput.value.trim();
if (!toolName) {
return;
}
// Disable button during processing
addBtn.disabled = true;
addBtn.textContent = 'Adding...';
vscode.postMessage({
type: 'addPermission',
toolName: toolName,
command: command || null
});
// Clear form and hide it
toolSelect.value = '';
commandInput.value = '';
hideAddPermissionForm();
// Re-enable button
setTimeout(() => {
addBtn.disabled = false;
addBtn.textContent = 'Add';
}, 500);
}
// Close settings modal when clicking outside
document.getElementById('settingsModal').addEventListener('click', (e) => {
if (e.target === document.getElementById('settingsModal')) {