move registering of actions/kbs out of progress part (#278844)

This commit is contained in:
Megan Rogge
2025-11-21 20:18:36 -06:00
committed by GitHub
parent 61915ccbab
commit a8e321dca0
7 changed files with 179 additions and 128 deletions

View File

@@ -13,6 +13,7 @@ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contex
import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js';
import { AccessibilityVerbositySettingId } from '../../../accessibility/browser/accessibilityConfiguration.js';
import { INLINE_CHAT_ID } from '../../../inlineChat/common/inlineChat.js';
import { TerminalContribCommandId } from '../../../terminal/terminalContribExports.js';
import { ChatContextKeyExprs, ChatContextKeys } from '../../common/chatContextKeys.js';
import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../../common/constants.js';
import { IChatWidgetService } from '../chat.js';
@@ -81,8 +82,8 @@ export function getAccessibilityHelpText(type: 'panelChat' | 'inlineChat' | 'age
content.push(localize('workbench.action.chat.previousUserPrompt', 'To navigate to the previous user prompt in the conversation, invoke the Previous User Prompt command{0}.', '<keybinding:workbench.action.chat.previousUserPrompt>'));
content.push(localize('workbench.action.chat.announceConfirmation', 'To focus pending chat confirmation dialogs, invoke the Focus Chat Confirmation Status command{0}.', '<keybinding:workbench.action.chat.focusConfirmation>'));
content.push(localize('chat.showHiddenTerminals', 'If there are any hidden chat terminals, you can view them by invoking the View Hidden Chat Terminals command{0}.', '<keybinding:workbench.action.terminal.chat.viewHiddenChatTerminals>'));
content.push(localize('chat.focusMostRecentTerminal', 'To focus the last chat terminal that ran a tool, invoke the Focus Most Recent Chat Terminal command{0}.', '<keybinding:workbench.action.chat.focusMostRecentChatTerminal>'));
content.push(localize('chat.focusMostRecentTerminalOutput', 'To focus the output from the last chat terminal tool, invoke the Focus Most Recent Chat Terminal Output command{0}.', '<keybinding:workbench.action.chat.focusMostRecentChatTerminalOutput>'));
content.push(localize('chat.focusMostRecentTerminal', 'To focus the last chat terminal that ran a tool, invoke the Focus Most Recent Chat Terminal command{0}.', `<keybinding:${TerminalContribCommandId.FocusMostRecentChatTerminal}>`));
content.push(localize('chat.focusMostRecentTerminalOutput', 'To focus the output from the last chat terminal tool, invoke the Focus Most Recent Chat Terminal Output command{0}.', `<keybinding:${TerminalContribCommandId.FocusMostRecentChatTerminalOutput}>`));
if (type === 'panelChat') {
content.push(localize('workbench.action.chat.newChat', 'To create a new chat session, invoke the New Chat command{0}.', '<keybinding:workbench.action.chat.new>'));
}

View File

@@ -31,7 +31,7 @@ import { IMarkdownRenderer } from '../../../../../../platform/markdown/browser/m
import { IStorageService, StorageScope, StorageTarget } from '../../../../../../platform/storage/common/storage.js';
import { IPreferencesService } from '../../../../../services/preferences/common/preferences.js';
import { ITerminalChatService } from '../../../../terminal/browser/terminal.js';
import { TerminalContribSettingId } from '../../../../terminal/terminalContribExports.js';
import { TerminalContribCommandId, TerminalContribSettingId } from '../../../../terminal/terminalContribExports.js';
import { migrateLegacyTerminalToolSpecificData } from '../../../common/chat.js';
import { ChatContextKeys } from '../../../common/chatContextKeys.js';
import { IChatToolInvocation, ToolConfirmKind, type IChatTerminalToolInvocationData, type ILegacyChatTerminalToolInvocationData } from '../../../common/chatService.js';
@@ -43,7 +43,6 @@ import { ChatCustomConfirmationWidget, IChatConfirmationButton } from '../chatCo
import { EditorPool } from '../chatContentCodePools.js';
import { IChatContentPartRenderContext } from '../chatContentParts.js';
import { ChatMarkdownContentPart } from '../chatMarkdownContentPart.js';
import { disableSessionAutoApprovalCommandId, openTerminalSettingsLinkCommandId } from './chatTerminalToolProgressPart.js';
import { BaseChatToolInvocationSubPart } from './chatToolInvocationSubPart.js';
export const enum TerminalToolConfirmationStorageKeys {
@@ -280,13 +279,13 @@ export class ChatTerminalToolConfirmationSubPart extends BaseChatToolInvocationS
await this.configurationService.updateValue(TerminalContribSettingId.AutoApprove, newValue, ConfigurationTarget.USER);
function formatRuleLinks(newRules: ITerminalNewAutoApproveRule[]): string {
return newRules.map(e => {
const settingsUri = createCommandUri(openTerminalSettingsLinkCommandId, ConfigurationTarget.USER);
const settingsUri = createCommandUri(TerminalContribCommandId.OpenTerminalSettingsLink, ConfigurationTarget.USER);
return `[\`${e.key}\`](${settingsUri.toString()} "${localize('ruleTooltip', 'View rule in settings')}")`;
}).join(', ');
}
const mdTrustSettings = {
isTrusted: {
enabledCommands: [openTerminalSettingsLinkCommandId]
enabledCommands: [TerminalContribCommandId.OpenTerminalSettingsLink]
}
};
if (newRules.length === 1) {
@@ -308,10 +307,10 @@ export class ChatTerminalToolConfirmationSubPart extends BaseChatToolInvocationS
case 'sessionApproval': {
const sessionId = this.context.element.sessionId;
this.terminalChatService.setChatSessionAutoApproval(sessionId, true);
const disableUri = createCommandUri(disableSessionAutoApprovalCommandId, sessionId);
const disableUri = createCommandUri(TerminalContribCommandId.DisableSessionAutoApproval, sessionId);
const mdTrustSettings = {
isTrusted: {
enabledCommands: [disableSessionAutoApprovalCommandId]
enabledCommands: [TerminalContribCommandId.DisableSessionAutoApproval]
}
};
terminalData.autoApproveInfo = new MarkdownString(`${localize('sessionApproval', 'All commands will be auto approved for this session')} ([${localize('sessionApproval.disable', 'Disable')}](${disableUri.toString()}))`, mdTrustSettings);

View File

@@ -5,11 +5,8 @@
import { h } from '../../../../../../base/browser/dom.js';
import { ActionBar } from '../../../../../../base/browser/ui/actionbar/actionbar.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { KeyCode, KeyMod } from '../../../../../../base/common/keyCodes.js';
import { isMarkdownString, MarkdownString } from '../../../../../../base/common/htmlContent.js';
import { IInstantiationService, ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation.js';
import { IPreferencesService, type IOpenSettingsOptions } from '../../../../../services/preferences/common/preferences.js';
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
import { migrateLegacyTerminalToolSpecificData } from '../../../common/chat.js';
import { IChatToolInvocation, IChatToolInvocationSerialized, type IChatMarkdownContent, type IChatTerminalToolInvocationData, type ILegacyChatTerminalToolInvocationData } from '../../../common/chatService.js';
import { CodeBlockModelCollection } from '../../../common/codeBlockModelCollection.js';
@@ -20,14 +17,9 @@ import { ChatMarkdownContentPart, type IChatMarkdownContentPartOptions } from '.
import { ChatProgressSubPart } from '../chatProgressContentPart.js';
import { BaseChatToolInvocationSubPart } from './chatToolInvocationSubPart.js';
import '../media/chatTerminalToolProgressPart.css';
import { TerminalContribSettingId } from '../../../../terminal/terminalContribExports.js';
import { ConfigurationTarget } from '../../../../../../platform/configuration/common/configuration.js';
import type { ICodeBlockRenderOptions } from '../../codeBlockPart.js';
import { ChatConfiguration, CHAT_TERMINAL_OUTPUT_MAX_PREVIEW_LINES } from '../../../common/constants.js';
import { CommandsRegistry } from '../../../../../../platform/commands/common/commands.js';
import { MenuId, MenuRegistry } from '../../../../../../platform/actions/common/actions.js';
import { CHAT_TERMINAL_OUTPUT_MAX_PREVIEW_LINES } from '../../../common/constants.js';
import { IChatTerminalToolProgressPart, ITerminalChatService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalService } from '../../../../terminal/browser/terminal.js';
import { Action, IAction } from '../../../../../../base/common/actions.js';
import { Disposable, MutableDisposable, toDisposable, type IDisposable } from '../../../../../../base/common/lifecycle.js';
import { Emitter, Event } from '../../../../../../base/common/event.js';
import { ThemeIcon } from '../../../../../../base/common/themables.js';
@@ -36,7 +28,6 @@ import * as dom from '../../../../../../base/browser/dom.js';
import { DomScrollableElement } from '../../../../../../base/browser/ui/scrollbar/scrollableElement.js';
import { ScrollbarVisibility } from '../../../../../../base/common/scrollable.js';
import { localize } from '../../../../../../nls.js';
import { TerminalLocation } from '../../../../../../platform/terminal/common/terminal.js';
import { ITerminalCommand, TerminalCapability, type ICommandDetectionCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js';
import { IMarkdownRenderer } from '../../../../../../platform/markdown/browser/markdownRenderer.js';
import { IHoverService } from '../../../../../../platform/hover/browser/hover.js';
@@ -50,8 +41,13 @@ import { IContextKey, IContextKeyService } from '../../../../../../platform/cont
import { AccessibilityVerbositySettingId } from '../../../../accessibility/browser/accessibilityConfiguration.js';
import { ChatContextKeys } from '../../../common/chatContextKeys.js';
import { EditorPool } from '../chatContentCodePools.js';
import { KeybindingWeight, KeybindingsRegistry } from '../../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IKeybindingService } from '../../../../../../platform/keybinding/common/keybinding.js';
import { TerminalLocation } from '../../../../../../platform/terminal/common/terminal.js';
import { Action, IAction } from '../../../../../../base/common/actions.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { TerminalContribCommandId } from '../../../../terminal/terminalContribExports.js';
import { ITelemetryService } from '../../../../../../platform/telemetry/common/telemetry.js';
const MAX_TERMINAL_OUTPUT_PREVIEW_HEIGHT = 200;
@@ -969,108 +965,16 @@ class ChatTerminalToolOutputSection extends Disposable {
}
}
export const focusMostRecentChatTerminalCommandId = 'workbench.action.chat.focusMostRecentChatTerminal';
export const focusMostRecentChatTerminalOutputCommandId = 'workbench.action.chat.focusMostRecentChatTerminalOutput';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: focusMostRecentChatTerminalCommandId,
weight: KeybindingWeight.WorkbenchContrib,
when: ChatContextKeys.inChatSession,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyT,
handler: async (accessor: ServicesAccessor) => {
const terminalChatService = accessor.get(ITerminalChatService);
const part = terminalChatService.getMostRecentProgressPart();
if (!part) {
return;
}
await part.focusTerminal();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: focusMostRecentChatTerminalOutputCommandId,
weight: KeybindingWeight.WorkbenchContrib,
when: ChatContextKeys.inChatSession,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyO,
handler: async (accessor: ServicesAccessor) => {
const terminalChatService = accessor.get(ITerminalChatService);
const part = terminalChatService.getMostRecentProgressPart();
if (!part) {
return;
}
await part.toggleOutputFromKeyboard();
}
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: focusMostRecentChatTerminalCommandId,
title: localize('chat.focusMostRecentTerminal', 'Chat: Focus Most Recent Terminal'),
},
when: ChatContextKeys.inChatSession
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: focusMostRecentChatTerminalOutputCommandId,
title: localize('chat.focusMostRecentTerminalOutput', 'Chat: Focus Most Recent Terminal Output'),
},
when: ChatContextKeys.inChatSession
});
export const openTerminalSettingsLinkCommandId = '_chat.openTerminalSettingsLink';
export const disableSessionAutoApprovalCommandId = '_chat.disableSessionAutoApproval';
CommandsRegistry.registerCommand(openTerminalSettingsLinkCommandId, async (accessor, scopeRaw: string) => {
const preferencesService = accessor.get(IPreferencesService);
if (scopeRaw === 'global') {
preferencesService.openSettings({
query: `@id:${ChatConfiguration.GlobalAutoApprove}`
});
} else {
const scope = parseInt(scopeRaw);
const target = !isNaN(scope) ? scope as ConfigurationTarget : undefined;
const options: IOpenSettingsOptions = {
jsonEditor: true,
revealSetting: {
key: TerminalContribSettingId.AutoApprove
}
};
switch (target) {
case ConfigurationTarget.APPLICATION: preferencesService.openApplicationSettings(options); break;
case ConfigurationTarget.USER:
case ConfigurationTarget.USER_LOCAL: preferencesService.openUserSettings(options); break;
case ConfigurationTarget.USER_REMOTE: preferencesService.openRemoteSettings(options); break;
case ConfigurationTarget.WORKSPACE:
case ConfigurationTarget.WORKSPACE_FOLDER: preferencesService.openWorkspaceSettings(options); break;
default: {
// Fallback if something goes wrong
preferencesService.openSettings({
target: ConfigurationTarget.USER,
query: `@id:${TerminalContribSettingId.AutoApprove}`,
});
break;
}
}
}
});
CommandsRegistry.registerCommand(disableSessionAutoApprovalCommandId, async (accessor, chatSessionId: string) => {
const terminalChatService = accessor.get(ITerminalChatService);
terminalChatService.setChatSessionAutoApproval(chatSessionId, false);
});
class ToggleChatTerminalOutputAction extends Action implements IAction {
export class ToggleChatTerminalOutputAction extends Action implements IAction {
private _expanded = false;
constructor(
private readonly _toggle: () => Promise<void>,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
) {
super(
'chat.showTerminalOutput',
TerminalContribCommandId.ToggleChatTerminalOutput,
localize('showTerminalOutput', 'Show Output'),
ThemeIcon.asClassName(Codicon.chevronRight),
true,
@@ -1079,6 +983,18 @@ class ToggleChatTerminalOutputAction extends Action implements IAction {
}
public override async run(): Promise<void> {
type ToggleChatTerminalOutputTelemetryEvent = {
previousExpanded: boolean;
};
type ToggleChatTerminalOutputTelemetryClassification = {
owner: 'meganrogge';
comment: 'Track usage of the toggle chat terminal output action.';
previousExpanded: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the terminal output was expanded before the toggle.' };
};
this._telemetryService.publicLog2<ToggleChatTerminalOutputTelemetryEvent, ToggleChatTerminalOutputTelemetryClassification>('terminal/chatToggleOutput', {
previousExpanded: this._expanded
});
await this._toggle();
}
@@ -1103,7 +1019,7 @@ class ToggleChatTerminalOutputAction extends Action implements IAction {
}
private _updateTooltip(): void {
const keybinding = this._keybindingService.lookupKeybinding(focusMostRecentChatTerminalOutputCommandId);
const keybinding = this._keybindingService.lookupKeybinding(TerminalContribCommandId.FocusMostRecentChatTerminalOutput);
const label = keybinding?.getLabel();
this.tooltip = label ? `${this.label} (${label})` : this.label;
}
@@ -1120,9 +1036,10 @@ export class FocusChatInstanceAction extends Action implements IAction {
@ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService,
@ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
) {
super(
'chat.focusTerminalInstance',
TerminalContribCommandId.FocusChatInstanceAction,
isTerminalHidden ? localize('showTerminal', 'Show and Focus Terminal') : localize('focusTerminal', 'Focus Terminal'),
ThemeIcon.asClassName(Codicon.openInProduct),
true,
@@ -1133,6 +1050,32 @@ export class FocusChatInstanceAction extends Action implements IAction {
public override async run() {
this.label = localize('focusTerminal', 'Focus Terminal');
this._updateTooltip();
let target: FocusChatInstanceTelemetryEvent['target'] = 'none';
let location: FocusChatInstanceTelemetryEvent['location'] = 'panel';
if (this._instance) {
target = 'instance';
location = this._instance.target === TerminalLocation.Editor ? 'editor' : 'panel';
} else if (this._commandUri) {
target = 'commandUri';
}
type FocusChatInstanceTelemetryEvent = {
target: 'instance' | 'commandUri' | 'none';
location: 'panel' | 'editor';
};
type FocusChatInstanceTelemetryClassification = {
owner: 'meganrogge';
comment: 'Track usage of the focus chat terminal action.';
target: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether focusing targeted an existing instance or opened a command URI.' };
location: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Location of the terminal instance when focusing.' };
};
this._telemetryService.publicLog2<FocusChatInstanceTelemetryEvent, FocusChatInstanceTelemetryClassification>('terminal/chatFocusInstance', {
target,
location
});
if (this._instance) {
this._terminalService.setActiveInstance(this._instance);
if (this._instance.target === TerminalLocation.Editor) {
@@ -1174,7 +1117,7 @@ export class FocusChatInstanceAction extends Action implements IAction {
}
private _updateTooltip(): void {
const keybinding = this._keybindingService.lookupKeybinding(focusMostRecentChatTerminalCommandId);
const keybinding = this._keybindingService.lookupKeybinding(TerminalContribCommandId.FocusMostRecentChatTerminal);
const label = keybinding?.getLabel();
this.tooltip = label ? `${this.label} (${label})` : this.label;
}

View File

@@ -7,6 +7,7 @@ import type { IConfigurationNode } from '../../../platform/configuration/common/
import { TerminalAccessibilityCommandId, defaultTerminalAccessibilityCommandsToSkipShell } from '../terminalContrib/accessibility/common/terminal.accessibility.js';
import { terminalAccessibilityConfiguration } from '../terminalContrib/accessibility/common/terminalAccessibilityConfiguration.js';
import { terminalAutoRepliesConfiguration } from '../terminalContrib/autoReplies/common/terminalAutoRepliesConfiguration.js';
import { TerminalChatCommandId } from '../terminalContrib/chat/browser/terminalChat.js';
import { terminalInitialHintConfiguration } from '../terminalContrib/chat/common/terminalInitialHintConfiguration.js';
import { terminalChatAgentToolsConfiguration, TerminalChatAgentToolsSettingId } from '../terminalContrib/chatAgentTools/common/terminalChatAgentToolsConfiguration.js';
import { terminalCommandGuideConfiguration } from '../terminalContrib/commandGuide/common/terminalCommandGuideConfiguration.js';
@@ -25,6 +26,12 @@ import { terminalZoomConfiguration } from '../terminalContrib/zoom/common/termin
export const enum TerminalContribCommandId {
A11yFocusAccessibleBuffer = TerminalAccessibilityCommandId.FocusAccessibleBuffer,
DeveloperRestartPtyHost = TerminalDeveloperCommandId.RestartPtyHost,
OpenTerminalSettingsLink = TerminalChatCommandId.OpenTerminalSettingsLink,
DisableSessionAutoApproval = TerminalChatCommandId.DisableSessionAutoApproval,
FocusMostRecentChatTerminalOutput = TerminalChatCommandId.FocusMostRecentChatTerminalOutput,
FocusMostRecentChatTerminal = TerminalChatCommandId.FocusMostRecentChatTerminal,
ToggleChatTerminalOutput = TerminalChatCommandId.ToggleChatTerminalOutput,
FocusChatInstanceAction = TerminalChatCommandId.FocusChatInstanceAction,
}
// HACK: Export some settings from `terminalContrib/` that are depended upon elsewhere. These are

View File

@@ -19,6 +19,12 @@ export const enum TerminalChatCommandId {
ViewInChat = 'workbench.action.terminal.chat.viewInChat',
RerunRequest = 'workbench.action.terminal.chat.rerunRequest',
ViewHiddenChatTerminals = 'workbench.action.terminal.chat.viewHiddenChatTerminals',
OpenTerminalSettingsLink = 'workbench.action.terminal.chat.openTerminalSettingsLink',
DisableSessionAutoApproval = 'workbench.action.terminal.chat.disableSessionAutoApproval',
FocusMostRecentChatTerminalOutput = 'workbench.action.terminal.chat.focusMostRecentChatTerminalOutput',
FocusMostRecentChatTerminal = 'workbench.action.terminal.chat.focusMostRecentChatTerminal',
ToggleChatTerminalOutput = 'workbench.action.terminal.chat.toggleChatTerminalOutput',
FocusChatInstanceAction = 'workbench.action.terminal.chat.focusChatInstance',
}
export const MENU_TERMINAL_CHAT_WIDGET_INPUT_SIDE_TOOLBAR = MenuId.for('terminalChatWidget');

View File

@@ -5,15 +5,15 @@
import { Codicon } from '../../../../../base/common/codicons.js';
import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';
import { localize2 } from '../../../../../nls.js';
import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { localize, localize2 } from '../../../../../nls.js';
import { Action2, MenuId, MenuRegistry, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { KeybindingsRegistry, KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { ChatViewId, IChatWidgetService } from '../../../chat/browser/chat.js';
import { ChatContextKeys } from '../../../chat/common/chatContextKeys.js';
import { IChatService } from '../../../chat/common/chatService.js';
import { LocalChatSessionUri } from '../../../chat/common/chatUri.js';
import { ChatAgentLocation } from '../../../chat/common/constants.js';
import { ChatAgentLocation, ChatConfiguration } from '../../../chat/common/constants.js';
import { AbstractInline1ChatAction } from '../../../inlineChat/browser/inlineChatActions.js';
import { isDetachedTerminalInstance, ITerminalChatService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalService } from '../../../terminal/browser/terminal.js';
import { registerActiveXtermAction } from '../../../terminal/browser/terminalActions.js';
@@ -26,6 +26,10 @@ import { getIconId } from '../../../terminal/browser/terminalIcon.js';
import { TerminalChatController } from './terminalChatController.js';
import { TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js';
import { isString } from '../../../../../base/common/types.js';
import { CommandsRegistry } from '../../../../../platform/commands/common/commands.js';
import { IPreferencesService, IOpenSettingsOptions } from '../../../../services/preferences/common/preferences.js';
import { ConfigurationTarget } from '../../../../../platform/configuration/common/configuration.js';
import { TerminalChatAgentToolsSettingId } from '../../chatAgentTools/common/terminalChatAgentToolsConfiguration.js';
registerActiveXtermAction({
id: TerminalChatCommandId.Start,
@@ -425,3 +429,94 @@ registerAction2(class ShowChatTerminalsAction extends Action2 {
qp.show();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: TerminalChatCommandId.FocusMostRecentChatTerminal,
weight: KeybindingWeight.WorkbenchContrib,
when: ChatContextKeys.inChatSession,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyT,
handler: async (accessor: ServicesAccessor) => {
const terminalChatService = accessor.get(ITerminalChatService);
const part = terminalChatService.getMostRecentProgressPart();
if (!part) {
return;
}
await part.focusTerminal();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: TerminalChatCommandId.FocusMostRecentChatTerminalOutput,
weight: KeybindingWeight.WorkbenchContrib,
when: ChatContextKeys.inChatSession,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyO,
handler: async (accessor: ServicesAccessor) => {
const terminalChatService = accessor.get(ITerminalChatService);
const part = terminalChatService.getMostRecentProgressPart();
if (!part) {
return;
}
await part.toggleOutputFromKeyboard();
}
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: TerminalChatCommandId.FocusMostRecentChatTerminal,
title: localize('chat.focusMostRecentTerminal', 'Chat: Focus Most Recent Terminal'),
},
when: ChatContextKeys.inChatSession
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: TerminalChatCommandId.FocusMostRecentChatTerminalOutput,
title: localize('chat.focusMostRecentTerminalOutput', 'Chat: Focus Most Recent Terminal Output'),
},
when: ChatContextKeys.inChatSession
});
CommandsRegistry.registerCommand(TerminalChatCommandId.OpenTerminalSettingsLink, async (accessor, scopeRaw: string) => {
const preferencesService = accessor.get(IPreferencesService);
if (scopeRaw === 'global') {
preferencesService.openSettings({
query: `@id:${ChatConfiguration.GlobalAutoApprove}`
});
} else {
const scope = parseInt(scopeRaw);
const target = !isNaN(scope) ? scope as ConfigurationTarget : undefined;
const options: IOpenSettingsOptions = {
jsonEditor: true,
revealSetting: {
key: TerminalChatAgentToolsSettingId.AutoApprove,
}
};
switch (target) {
case ConfigurationTarget.APPLICATION: preferencesService.openApplicationSettings(options); break;
case ConfigurationTarget.USER:
case ConfigurationTarget.USER_LOCAL: preferencesService.openUserSettings(options); break;
case ConfigurationTarget.USER_REMOTE: preferencesService.openRemoteSettings(options); break;
case ConfigurationTarget.WORKSPACE:
case ConfigurationTarget.WORKSPACE_FOLDER: preferencesService.openWorkspaceSettings(options); break;
default: {
// Fallback if something goes wrong
preferencesService.openSettings({
target: ConfigurationTarget.USER,
query: `@id:${TerminalChatAgentToolsSettingId.AutoApprove}`,
});
break;
}
}
}
});
CommandsRegistry.registerCommand(TerminalChatCommandId.DisableSessionAutoApproval, async (accessor, chatSessionId: string) => {
const terminalChatService = accessor.get(ITerminalChatService);
terminalChatService.setChatSessionAutoApproval(chatSessionId, false);
});

View File

@@ -13,7 +13,6 @@ import { IInstantiationService } from '../../../../../../../platform/instantiati
import { ITerminalChatService } from '../../../../../terminal/browser/terminal.js';
import { IStorageService, StorageScope } from '../../../../../../../platform/storage/common/storage.js';
import { TerminalToolConfirmationStorageKeys } from '../../../../../chat/browser/chatContentParts/toolInvocationParts/chatTerminalToolConfirmationSubPart.js';
import { openTerminalSettingsLinkCommandId } from '../../../../../chat/browser/chatContentParts/toolInvocationParts/chatTerminalToolProgressPart.js';
import { ChatConfiguration } from '../../../../../chat/common/constants.js';
import type { ToolConfirmationAction } from '../../../../../chat/common/languageModelToolsService.js';
import { TerminalChatAgentToolsSettingId } from '../../../common/terminalChatAgentToolsConfiguration.js';
@@ -22,6 +21,7 @@ import { dedupeRules, generateAutoApproveActions, isPowerShell } from '../../run
import type { RunInTerminalToolTelemetry } from '../../runInTerminalToolTelemetry.js';
import { type TreeSitterCommandParser } from '../../treeSitterCommandParser.js';
import type { ICommandLineAnalyzer, ICommandLineAnalyzerOptions, ICommandLineAnalyzerResult } from './commandLineAnalyzer.js';
import { TerminalChatCommandId } from '../../../../chat/browser/terminalChat.js';
const promptInjectionWarningCommandsLower = [
'curl',
@@ -53,10 +53,10 @@ export class CommandLineAutoApproveAnalyzer extends Disposable implements IComma
async analyze(options: ICommandLineAnalyzerOptions): Promise<ICommandLineAnalyzerResult> {
if (options.chatSessionId && this._terminalChatService.hasChatSessionAutoApproval(options.chatSessionId)) {
this._log('Session has auto approval enabled, auto approving command');
const disableUri = createCommandUri('_chat.disableSessionAutoApproval', options.chatSessionId);
const disableUri = createCommandUri(TerminalChatCommandId.DisableSessionAutoApproval, options.chatSessionId);
const mdTrustSettings = {
isTrusted: {
enabledCommands: ['_chat.disableSessionAutoApproval']
enabledCommands: [TerminalChatCommandId.DisableSessionAutoApproval]
}
};
return {
@@ -191,21 +191,21 @@ export class CommandLineAutoApproveAnalyzer extends Disposable implements IComma
): IMarkdownString | undefined {
const formatRuleLinks = (result: SingleOrMany<{ result: ICommandApprovalResult; rule?: IAutoApproveRule; reason: string }>): string => {
return asArray(result).map(e => {
const settingsUri = createCommandUri(openTerminalSettingsLinkCommandId, e.rule!.sourceTarget);
const settingsUri = createCommandUri(TerminalChatCommandId.OpenTerminalSettingsLink, e.rule!.sourceTarget);
return `[\`${e.rule!.sourceText}\`](${settingsUri.toString()} "${localize('ruleTooltip', 'View rule in settings')}")`;
}).join(', ');
};
const mdTrustSettings = {
isTrusted: {
enabledCommands: [openTerminalSettingsLinkCommandId]
enabledCommands: [TerminalChatCommandId.OpenTerminalSettingsLink]
}
};
const config = this._configurationService.inspect<boolean | Record<string, boolean>>(ChatConfiguration.GlobalAutoApprove);
const isGlobalAutoApproved = config?.value ?? config.defaultValue;
if (isGlobalAutoApproved) {
const settingsUri = createCommandUri(openTerminalSettingsLinkCommandId, 'global');
const settingsUri = createCommandUri(TerminalChatCommandId.OpenTerminalSettingsLink, 'global');
return new MarkdownString(`${localize('autoApprove.global', 'Auto approved by setting {0}', `[\`${ChatConfiguration.GlobalAutoApprove}\`](${settingsUri.toString()} "${localize('ruleTooltip.global', 'View settings')}")`)}`, mdTrustSettings);
}