-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Terminal/Shell Command Permissions UI Feature
Overview
This feature allows users to manage terminal/shell command permissions directly from the chat interface when Roo executes terminal commands.
Feature Description
The command permissions feature adds an interactive UI component to command execution blocks that allows users to:
- View suggested command patterns for the allow list
- Add patterns to the allowed commands list (for auto-execution)
- Add patterns to the denied commands list (to block execution)
- Toggle patterns between allowed/denied/none states
- View pattern descriptions that explain what each pattern will allow
UI Components
1. CommandExecution Component
Location: webview-ui/src/components/chat/CommandExecution.tsx
This is the main component that displays command execution blocks in the chat interface.
Key Features:
- Displays the command being executed
- Shows execution status (running/exited with exit code)
- Collapsible output section
- Integrated command pattern management section
Component Structure:
<div className="w-full">
{/* Header section */}
<div className="flex flex-row items-center justify-between gap-2 px-3 py-2 bg-vscode-editor-background border border-vscode-border rounded-t-md">
{/* Icon, title, status display, output toggle */}
</div>
{/* Command execution box */}
<div className="bg-vscode-editor-background border-x border-b border-vscode-border rounded-b-md">
{/* Command display */}
<div className="p-3">
<CodeBlock source={command} language="shell" />
</div>
{/* Command management section */}
{showSuggestions && (
<CommandPatternSelector
patterns={commandPatterns}
allowedCommands={allowedCommands}
deniedCommands={deniedCommands}
onAllowPatternChange={handleAllowPatternChange}
onDenyPatternChange={handleDenyPatternChange}
/>
)}
{/* Output section */}
{output.length > 0 && (
<div className={cn("border-t border-vscode-panel-border", { hidden: !isOutputExpanded })}>
<div className="p-3">
<CodeBlock source={output} language="log" />
</div>
</div>
)}
</div>
</div>2. CommandPatternSelector Component
Location: webview-ui/src/components/chat/CommandPatternSelector.tsx
This component handles the command pattern management UI.
Key Features:
- Collapsible section with chevron indicator
- Lists command patterns with descriptions
- Allow/Deny toggle buttons for each pattern
- Visual indicators for pattern status
- Tooltip with help text and link to settings
Component Structure:
<div className="border-t border-vscode-panel-border bg-vscode-sideBar-background/30">
<button
onClick={() => setIsExpanded(!isExpanded)}
className="flex items-center gap-2 w-full px-3 py-2 text-xs text-vscode-descriptionForeground hover:text-vscode-foreground hover:bg-vscode-list-hoverBackground transition-all"
>
<ChevronDown className={cn("size-3 transition-transform duration-200", {
"rotate-0": isExpanded,
"-rotate-90": !isExpanded,
})} />
<span className="font-medium">{t("chat:commandExecution.manageCommands")}</span>
{/* Info tooltip when expanded */}
</button>
{isExpanded && (
<div className="px-3 pb-3 space-y-2">
{patterns.map((item, index) => (
<div key={`${item.pattern}-${index}`} className="ml-5 flex items-center gap-2">
<div className="flex-1">
<span className="font-mono text-xs text-vscode-foreground">{item.pattern}</span>
{item.description && (
<span className="text-xs text-vscode-descriptionForeground ml-2">
- {item.description}
</span>
)}
</div>
<div className="flex items-center gap-1">
{/* Allow button */}
<button className={cn("p-1 rounded transition-all", /* status-based styles */)}>
<Check className="size-3.5" />
</button>
{/* Deny button */}
<button className={cn("p-1 rounded transition-all", /* status-based styles */)}>
<X className="size-3.5" />
</button>
</div>
</div>
))}
</div>
)}
</div>Styling
Color Scheme
The UI uses VSCode theme variables for consistent appearance:
-
Background Colors:
- Main container:
bg-vscode-editor-background - Pattern selector section:
bg-vscode-sideBar-background/30 - Hover states:
hover:bg-vscode-list-hoverBackground,hover:bg-vscode-toolbar-hoverBackground
- Main container:
-
Text Colors:
- Primary text:
text-vscode-foreground - Secondary text:
text-vscode-descriptionForeground - Muted text:
text-vscode-descriptionForeground/70
- Primary text:
-
Border Colors:
- Main borders:
border-vscode-border - Section dividers:
border-vscode-panel-border
- Main borders:
-
Status Indicators:
- Running:
bg-lime-400(green dot) - Success (exit 0):
bg-lime-400 - Error (non-zero exit):
bg-red-400 - Allowed pattern:
bg-green-500/20 text-green-500 - Denied pattern:
bg-red-500/20 text-red-500
- Running:
Button States
- Default:
text-vscode-descriptionForeground - Hover (Allow):
hover:text-green-500 hover:bg-green-500/10 - Hover (Deny):
hover:text-red-500 hover:bg-red-500/10 - Active (Allow):
bg-green-500/20 text-green-500 hover:bg-green-500/30 - Active (Deny):
bg-red-500/20 text-red-500 hover:bg-red-500/30
Pattern Extraction Logic
Command Pattern Extraction
Location: webview-ui/src/utils/commandPatterns.ts
The system extracts command patterns using two methods:
-
LLM Suggestions: If the AI provides suggestions in the command text
- Format:
<suggestions>["pattern1", "pattern2"]</suggestions> - Alternative:
<suggest>pattern1</suggest><suggest>pattern2</suggest>
- Format:
-
Programmatic Extraction: If no suggestions provided, patterns are extracted automatically
- Base command (e.g., "git" from "git push origin main")
- Command + subcommand (e.g., "git push")
- Special handling for package managers (npm, yarn, pnpm, bun)
- Stops at flags, paths, or complex arguments
Pattern Descriptions
The system generates human-readable descriptions for patterns:
npm run→ "all npm run scripts"git push→ "git push commands"./script.sh→ "this specific script"python→ "python scripts"cd→ "directory navigation"
State Management
Extension State Integration
The component integrates with the extension state to:
- Read current
allowedCommandsanddeniedCommandsarrays - Update lists via
setAllowedCommandsandsetDeniedCommands - Send updates to VSCode via
postMessage
Pattern Status Logic
const getPatternStatus = (pattern: string): "allowed" | "denied" | "none" => {
if (allowedCommands.includes(pattern)) return "allowed"
if (deniedCommands.includes(pattern)) return "denied"
return "none"
}Mutual Exclusivity
When a pattern is added to one list, it's automatically removed from the other:
- Adding to allowed → removes from denied
- Adding to denied → removes from allowed
Internationalization
Translation Keys
Location: webview-ui/src/i18n/locales/en/chat.json
{
"commandExecution": {
"running": "Running",
"pid": "PID: {{pid}}",
"exited": "Exited ({{exitCode}})",
"manageCommands": "Manage Command Permissions",
"commandManagementDescription": "Manage command permissions: Click ✓ to allow auto-execution, ✗ to deny execution. Patterns can be toggled on/off or removed from lists. <settingsLink>View all settings</settingsLink>",
"addToAllowed": "Add to allowed list",
"removeFromAllowed": "Remove from allowed list",
"addToDenied": "Add to denied list",
"removeFromDenied": "Remove from denied list",
"abortCommand": "Abort command execution",
"expandOutput": "Expand output",
"collapseOutput": "Collapse output",
"expandManagement": "Expand command management section",
"collapseManagement": "Collapse command management section"
}
}Implementation Details
Command Parsing
Location: webview-ui/src/utils/commandUtils.ts
The parseCommandAndOutput function extracts:
- The command string
- Output (if present after "Output:" marker)
- Suggestions from
<suggestions>or<suggest>tags
Event Handling
- Pattern allow/deny changes trigger state updates and VSCode messages
- Collapsible sections use local state for expand/collapse
- Status updates received via message events from the extension
Message Format
When updating command lists:
vscode.postMessage({
type: "allowedCommands", // or "deniedCommands"
commands: updatedCommandArray
})Usage Example
When Roo executes a command like npm install express, the UI will:
- Display the command in a code block
- Show "Manage Command Permissions" section (collapsed by default)
- When expanded, show patterns:
npm- npm commandsnpm install- npm install commands
- User can click ✓ to allow or ✗ to deny each pattern
- Changes are immediately reflected in the UI and saved to extension state
Accessibility
- All interactive elements have proper
aria-labelattributes - Expand/collapse states use
aria-expanded - Tooltips provide additional context
- Keyboard navigation supported
- Visual indicators complement color coding
Testing Considerations
- Pattern Extraction: Test with various command formats
- State Synchronization: Verify updates persist across sessions
- UI Interactions: Test expand/collapse, button clicks, tooltips
- Edge Cases: Empty patterns, malformed suggestions, special characters
- Theme Compatibility: Verify appearance in different VSCode themes
Parsing Mechanism Implementation
Overview
The new implementation uses the shell-quote library to properly parse shell commands and extract command patterns. This approach handles complex shell syntax including pipes, command chaining, and special operators.
Parser Implementation
Location: webview-ui/src/utils/commandPatterns.ts (proposed)
import { parse } from 'shell-quote';
function extractPatterns(cmdStr) {
const patterns = new Set();
const parsed = parse(cmdStr);
const commandSeparators = new Set(['|', '&&', '||', ';']);
let current = [];
for (const token of parsed) {
if (typeof token === 'object' && token.op && commandSeparators.has(token.op)) {
if (current.length) processCommand(current, patterns);
current = [];
} else {
current.push(token);
}
}
if (current.length) processCommand(current, patterns);
return patterns;
}Filter/ProcessCommand Function
The processCommand function extracts patterns from individual commands by progressively building patterns from the command and its arguments:
function processCommand(cmd, patterns) {
if (!cmd.length || typeof cmd[0] !== 'string') return;
const mainCmd = cmd[0];
patterns.add(mainCmd);
const breakingExps = [ /^-/, /[\\/:.~ ]/, ];
for (let i = 1; i < cmd.length; i++) {
const arg = cmd[i];
if (typeof arg !== 'string' || breakingExps.some(re => re.test(arg))) break;
const pattern = cmd.slice(0, i + 1).join(' ');
patterns.add(pattern);
}
}Breaking Rules
The parser stops building patterns when it encounters:
- Flags (arguments starting with
-) - Path separators (
/,\) - Special characters (
:,.,~, space)
Display Logic
To display sorted command patterns from shell history:
const exampleCommands = [ 'git ... ' , ... ]
const allPatterns = new Set();
exampleCommands.forEach(cmd => {
extractPatterns(cmd).forEach(pattern => allPatterns.add(pattern));
});
const sorted = Array.from(allPatterns).sort((a, b) => {
return a.localeCompare(b);
});
console.log('All suggested command patterns for auto-allowing (sorted and unique):', sorted);Example Outputs
When processing shell history, the parser generates a sorted list of unique command patterns:
[
'../repackage.sh',
'../roo-main/build.sh',
'../roo-main/clean.sh',
'cd',
'code',
'code-insiders',
'fg',
'git',
'git add',
'git checkout',
'git cherry-pick',
'git diff',
'git diff HEAD',
'git fetch',
'git fetch github',
'git fetch origin',
'git log',
'git push',
'git push github',
'git push github refactor-use-files-for-history',
'git rebase',
'git reset',
'git restore',
'git show',
'git stash',
'git stash pop',
'git status',
'grep',
'grep map',
'head',
'npm',
'npm run',
'npm run start',
'npx',
'npx jest',
'pnpm',
'pnpm test',
'top',
'unzip',
'vi',
'xclip'
]Example Inputs from Shell History
The following examples demonstrate the parser's ability to handle complex real-world commands from a developer's shell history:
# Complex piped commands
unzip -l builds/roo-cline-3.21.5-error-boundary-component.vsix|grep map
unzip -l builds/roo-cline-3.21.5-error-boundary-component.vsix|grep map|head
# Git commands with various arguments
git checkout -b use-safe-write-json-for-all-files
git checkout v3.16.5 .roomodes
git cherry-pick --continue
git diff HEAD
git diff pnpm-lock.yaml
git fetch github
git push github refactor-use-files-for-history -f
git rebase origin/main
git restore .roomodes
git restore --staged .roomodes
git show f65fb69fd~1 f65fb69fdfb60abb0968b658c320ae5adb1e3d8b
# Package manager commands
npx jest core/prompts/sections/__tests__/custom-instructions.test.ts
pnpm test
npm run start
# VSCode commands
code --install-extension builds/roo-cline-3.21.5-error-boundary-component.vsix
code-insiders .
# Shell built-ins and utilities
cd src/
cd webview-ui/
cd ..
cd -
fg
top
vi ../repackage.sh
# Script executions
../roo-main/clean.sh
../roo-main/build.sh
../repackage.sh
# Complex chained commands
../roo-main/build.sh && code --install-extension builds/roo-cline-3.21.5-error-boundary-component.vsix && codePattern Extraction Benefits
- Granular Control: Users can allow broad patterns (e.g.,
git) or specific subcommands (e.g.,git push) - Safety: The parser stops at flags and paths, preventing overly specific patterns
- Flexibility: Handles complex shell syntax including pipes, redirects, and command chaining
- Deduplication: Automatically removes duplicate patterns from history
- Sorting: Presents patterns in alphabetical order for easy scanning
Integration with UI
The extracted patterns are passed to the CommandPatternSelector component as:
interface CommandPattern {
pattern: string;
description?: string;
}The UI then displays these patterns with appropriate descriptions and allow/deny toggle buttons, enabling users to quickly build their command permission lists based on their actual command usage history.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status