Skip to content

Conversation

@Tyriar
Copy link
Member

@Tyriar Tyriar commented Dec 18, 2025

Fixes #270529

@Tyriar Tyriar added this to the December / January 2026 milestone Dec 18, 2025
@Tyriar Tyriar self-assigned this Dec 18, 2025
Copilot AI review requested due to automatic review settings December 18, 2025 16:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds workspace-scoped and session-scoped auto-approval options for terminal commands in the chat agent tools feature. Users can now choose to auto-approve commands for the current session only, for the workspace, or globally (user settings).

Key changes:

  • Adds session-scoped auto-approve rules stored in-memory (cleared when chat session ends)
  • Adds workspace-scoped auto-approve rules persisted in workspace settings
  • Updates UI to provide three action buttons: "Allow in this Session", "Allow in this Workspace", and "Always Allow"

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
commandLineAutoApprover.ts Adds session rule support with _getSessionRules() method, updates isCommandAutoApproved() and isCommandLineAutoApproved() to accept optional chatSessionId parameter, and defines AutoApproveRuleSource enum
commandLineAutoApproveAnalyzer.ts Updates rule link formatting to display scope indicators (session/workspace/user/default/remote) and handle non-actionable session rules
runInTerminalHelpers.ts Generates three separate action buttons for each scope (session/workspace/user) for both command and exact command line rules, adds separator between action groups
terminalChatService.ts Implements in-memory storage for session auto-approve rules with cleanup on session disposal via addSessionAutoApproveRule() and getSessionAutoApproveRules() methods
terminal.ts Adds interface methods for session auto-approve rule management to ITerminalChatService
chatTerminalToolConfirmationSubPart.ts Handles rule creation by scope, groups rules by session/workspace/user, updates configuration targets appropriately, and provides scope-specific feedback messages

Comment on lines +16 to 22
export const enum AutoApproveRuleSource {
Default = 'default',
User = 'user',
Workspace = 'workspace',
Session = 'session'
}

Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AutoApproveRuleSource enum is defined but appears to be unused anywhere in the codebase. The sourceTarget property in IAutoApproveRule uses ConfigurationTarget | 'session' directly instead of this enum. Consider either using this enum in the IAutoApproveRule interface or removing it if it's not needed.

Suggested change
export const enum AutoApproveRuleSource {
Default = 'default',
User = 'user',
Workspace = 'workspace',
Session = 'session'
}

Copilot uses AI. Check for mistakes.
Comment on lines +195 to +196
if (e.rule!.sourceTarget === 'session') {
return localize('autoApproveRule.sessionIndicator', '{0} (session)', `\`${e.rule!.sourceText}\``);
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-null assertion operator (!) is used on e.rule, but the type signature shows that rule is optional (rule?: IAutoApproveRule). While the current callers of formatRuleLinks check for rule existence before calling, this function should be defensive and add a guard clause at the beginning to handle the case where e.rule is undefined. Consider adding a check like: if (!e.rule) { return ''; } at the start of the map callback.

See below for a potential fix:

				if (!e.rule) {
					return '';
				}
				// Session rules cannot be actioned currently so no link
				if (e.rule.sourceTarget === 'session') {
					return localize('autoApproveRule.sessionIndicator', '{0} (session)', `\`${e.rule.sourceText}\``);
				}
				const settingsUri = createCommandUri(TerminalChatCommandId.OpenTerminalSettingsLink, e.rule.sourceTarget);
				const tooltip = localize('ruleTooltip', 'View rule in settings');
				let label = e.rule.sourceText;
				switch (e.rule.sourceTarget) {

Copilot uses AI. Check for mistakes.
Comment on lines 194 to +200
const settingsUri = createCommandUri(TerminalChatCommandId.OpenTerminalSettingsLink, e.rule!.sourceTarget);
return `[\`${e.rule!.sourceText}\`](${settingsUri.toString()} "${localize('ruleTooltip', 'View rule in settings')}")`;
const tooltip = localize('ruleTooltip', 'View rule in settings');
let label = e.rule!.sourceText;
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-null assertion operator (!) is used on multiple accesses to e.rule throughout this function (lines 198 and 200), but rule is optional according to the type signature. Add a guard clause at the beginning of the map callback to handle undefined rules safely.

See below for a potential fix:

				if (!e.rule) {
					return e.reason;
				}
				// Session rules cannot be actioned currently so no link
				if (e.rule.sourceTarget === 'session') {
					return localize('autoApproveRule.sessionIndicator', '{0} (session)', `\`${e.rule.sourceText}\``);
				}
				const settingsUri = createCommandUri(TerminalChatCommandId.OpenTerminalSettingsLink, e.rule.sourceTarget);
				const tooltip = localize('ruleTooltip', 'View rule in settings');
				let label = e.rule.sourceText;
				switch (e.rule.sourceTarget) {

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +145
subCommandLabel = `\`${subCommandsToSuggest[0]} \u2026\``;
} else {
const commandSeparated = subCommandsToSuggest.join(', ');
subCommandLabel = localize('autoApprove.baseCommand', 'Always Allow Commands: {0}', commandSeparated);
subCommandLabel = `Commands ${subCommandsToSuggest.map(e => `\`${e} \u2026\``).join(', ')}`;
}

actions.push({
label: subCommandLabel,
label: `Allow ${subCommandLabel} in this Session`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label formatting is inconsistent between single and multiple commands. For a single command, the label is "Allow command ... in this Session", but for multiple commands it becomes "Allow Commands cmd1 ..., cmd2 ... in this Session". The word "Commands" appearing in the middle creates an awkward construction. Consider restructuring the label to either: (1) always use a consistent pattern like "Allow Command(s) ... in this Session", or (2) move the plural indicator outside the variable part, such as "Allow the following commands in this Session: cmd1 ..., cmd2 ...".

Copilot uses AI. Check for mistakes.
} satisfies TerminalNewAutoApproveButtonData
});
actions.push({
label: `Allow ${subCommandLabel} in this Workspace`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same label inconsistency issue exists here as well. The pattern "Allow Commands ... in this Workspace" for multiple commands vs "Allow command ... in this Workspace" for a single command creates an awkward reading experience.

Copilot uses AI. Check for mistakes.
} satisfies TerminalNewAutoApproveButtonData
});
actions.push({
label: `Always Allow ${subCommandLabel}`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same label inconsistency issue exists here. The pattern "Always Allow Commands ..." for multiple commands vs "Always Allow command ..." for a single command should be made consistent.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No "always allow in this session/workspace" for some agent commands

2 participants