Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
40882e1
Enable sandboxing for terminal commands
dileepyavan Dec 1, 2025
0b15f7e
removing unused types
dileepyavan Dec 4, 2025
1084d72
code review comments update
dileepyavan Jan 6, 2026
c0b6751
main merge
dileepyavan Jan 7, 2026
b1976dc
refactored the code and added utility for sandboxing
dileepyavan Jan 10, 2026
a7ce30e
refactored the code and added utility for sandboxing
dileepyavan Jan 10, 2026
63cac43
refactored the code and added utility for sandboxing
dileepyavan Jan 10, 2026
caf2c45
fixing build error
dileepyavan Jan 12, 2026
5c21691
review suggestions
dileepyavan Jan 14, 2026
cd71156
review suggestions
dileepyavan Jan 14, 2026
762aaad
changes for retry
dileepyavan Jan 14, 2026
5147287
changes for retry
dileepyavan Jan 14, 2026
697f4f5
Update src/vs/workbench/contrib/terminalContrib/chatAgentTools/common…
dileepyavan Jan 14, 2026
353d912
Update src/vs/workbench/contrib/terminalContrib/chatAgentTools/browse…
dileepyavan Jan 14, 2026
b634138
Update src/vs/workbench/contrib/terminalContrib/chatAgentTools/common…
dileepyavan Jan 14, 2026
94f319d
Update src/vs/workbench/contrib/terminalContrib/chatAgentTools/browse…
dileepyavan Jan 14, 2026
a8b410c
Update src/vs/workbench/contrib/terminalContrib/chatAgentTools/browse…
dileepyavan Jan 14, 2026
f4e9d28
merging from main
dileepyavan Jan 15, 2026
49aeae9
updating anthropic sandbox runtime to 0.0.23
dileepyavan Jan 15, 2026
31ea4be
fixing tests for runInTerminalTool
dileepyavan Jan 15, 2026
10ce464
refactoring changes
dileepyavan Jan 15, 2026
02fec9b
review changes
dileepyavan Jan 15, 2026
22c6a80
review changes
dileepyavan Jan 15, 2026
544d616
review changes
dileepyavan Jan 15, 2026
5b01c73
review changes
dileepyavan Jan 15, 2026
dd41b1b
review changes
dileepyavan Jan 15, 2026
4742604
review changes
dileepyavan Jan 15, 2026
4adb2a6
review changes
dileepyavan Jan 16, 2026
aa3945e
update to sandboxservice
dileepyavan Jan 16, 2026
1e046d4
update to sandboxservice
dileepyavan Jan 16, 2026
e35e56f
update to sandboxservice
dileepyavan Jan 16, 2026
2ed1d8d
removing extra line
dileepyavan Jan 16, 2026
46534e1
formatting PR suggested by copilot
dileepyavan Jan 16, 2026
07dc6df
files location change suggested for review
dileepyavan Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 76 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"update-build-ts-version": "npm install -D typescript@next && npm install -D @typescript/native-preview && (cd build && npm run typecheck)"
},
"dependencies": {
"@anthropic-ai/sandbox-runtime": "0.0.23",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
"@parcel/watcher": "^2.5.4",
Expand Down Expand Up @@ -240,4 +241,4 @@
"optionalDependencies": {
"windows-foreground-love": "0.5.0"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const enum TerminalContribSettingId {
AutoApprove = TerminalChatAgentToolsSettingId.AutoApprove,
EnableAutoApprove = TerminalChatAgentToolsSettingId.EnableAutoApprove,
ShellIntegrationTimeout = TerminalChatAgentToolsSettingId.ShellIntegrationTimeout,
OutputLocation = TerminalChatAgentToolsSettingId.OutputLocation
OutputLocation = TerminalChatAgentToolsSettingId.OutputLocation,
}

// HACK: Export some context key strings from `terminalContrib/` that are depended upon elsewhere.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import { RunInTerminalTool, createRunInTerminalToolData } from './tools/runInTer
import { CreateAndRunTaskTool, CreateAndRunTaskToolData } from './tools/task/createAndRunTaskTool.js';
import { GetTaskOutputTool, GetTaskOutputToolData } from './tools/task/getTaskOutputTool.js';
import { RunTaskTool, RunTaskToolData } from './tools/task/runTaskTool.js';
import { InstantiationType, registerSingleton } from '../../../../../platform/instantiation/common/extensions.js';
import { ITerminalSandboxService, TerminalSandboxService } from '../common/terminalSandboxService.js';

// #region Services

registerSingleton(ITerminalSandboxService, TerminalSandboxService, InstantiationType.Delayed);

// #endregion Services

class ShellIntegrationTimeoutMigrationContribution extends Disposable implements IWorkbenchContribution {
static readonly ID = 'terminal.shellIntegrationTimeoutMigration';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { localize } from '../../../../../../nls.js';
import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js';
import { IInstantiationService, type ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../../../platform/storage/common/storage.js';
import { TerminalCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js';
import { ICommandDetectionCapability, TerminalCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js';
import { ITerminalLogService, ITerminalProfile } from '../../../../../../platform/terminal/common/terminal.js';
import { IRemoteAgentService } from '../../../../../services/remote/common/remoteAgentService.js';
import { TerminalToolConfirmationStorageKeys } from '../../../../chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolConfirmationSubPart.js';
Expand All @@ -45,6 +45,7 @@ import { CommandLineAutoApproveAnalyzer } from './commandLineAnalyzer/commandLin
import { CommandLineFileWriteAnalyzer } from './commandLineAnalyzer/commandLineFileWriteAnalyzer.js';
import { OutputMonitor } from './monitoring/outputMonitor.js';
import { IPollingResult, OutputMonitorState } from './monitoring/types.js';
import { ITerminalSandboxService } from '../../common/terminalSandboxService.js';
import { chatSessionResourceToId, LocalChatSessionUri } from '../../../../chat/common/model/chatUri.js';
import { URI } from '../../../../../../base/common/uri.js';
import type { ICommandLineRewriter } from './commandLineRewriter/commandLineRewriter.js';
Expand Down Expand Up @@ -308,6 +309,7 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
@ITerminalService private readonly _terminalService: ITerminalService,
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
@ITerminalSandboxService private readonly _sandboxService: ITerminalSandboxService,
) {
super();

Expand Down Expand Up @@ -336,6 +338,15 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
this._storageService.remove(TerminalToolConfirmationStorageKeys.TerminalAutoApproveWarningAccepted, StorageScope.APPLICATION);
}
}
// If terminal sandbox settings changed, update sandbox config.
if (
e?.affectsConfiguration(TerminalChatAgentToolsSettingId.TerminalSandboxEnabled) ||
e?.affectsConfiguration(TerminalChatAgentToolsSettingId.TerminalSandboxNetwork) ||
e?.affectsConfiguration(TerminalChatAgentToolsSettingId.TerminalSandboxLinuxFileSystem) ||
e?.affectsConfiguration(TerminalChatAgentToolsSettingId.TerminalSandboxMacFileSystem)
) {
this._sandboxService.setNeedsForceUpdateConfigFile();
}
}));

// Restore terminal associations from storage
Expand Down Expand Up @@ -417,6 +428,15 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
};
}

// If in sandbox mode, skip confirmation logic. In sandbox mode, commands are run in a restricted environment and explicit
// user confirmation is not required.
if (this._sandboxService.isEnabled()) {
toolSpecificData.autoApproveInfo = new MarkdownString(localize('autoApprove.sandbox', 'In sandbox mode'));
return {
toolSpecificData
};
}

// Determine auto approval, this happens even when auto approve is off to that reasoning
// can be reviewed in the terminal channel. It also allows gauging the effective set of
// commands that would be auto approved if it were enabled.
Expand Down Expand Up @@ -530,11 +550,11 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {

const args = invocation.parameters as IRunInTerminalInputParams;
this._logService.debug(`RunInTerminalTool: Invoking with options ${JSON.stringify(args)}`);
let toolResultMessage: string | undefined;
let toolResultMessage: string | IMarkdownString | undefined;

const chatSessionResource = invocation.context?.sessionResource ?? LocalChatSessionUri.forSession(invocation.context?.sessionId ?? 'no-chat-session');
const chatSessionId = chatSessionResourceToId(chatSessionResource);
const command = toolSpecificData.commandLine.userEdited ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original;
let command = toolSpecificData.commandLine.userEdited ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original;
const didUserEditCommand = (
toolSpecificData.commandLine.userEdited !== undefined &&
toolSpecificData.commandLine.userEdited !== toolSpecificData.commandLine.original
Expand All @@ -545,6 +565,12 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
toolSpecificData.commandLine.toolEdited !== toolSpecificData.commandLine.original
);

if (this._sandboxService.isEnabled()) {
await this._sandboxService.getSandboxConfigPath();
this._logService.info(`RunInTerminalTool: Sandboxing is enabled, wrapping command with srt.`);
command = this._sandboxService.wrapCommand(command);
}

if (token.isCancellationRequested) {
throw new CancellationError();
}
Expand Down Expand Up @@ -688,21 +714,9 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
}

try {
let strategy: ITerminalExecuteStrategy;
switch (toolTerminal.shellIntegrationQuality) {
case ShellIntegrationQuality.None: {
strategy = this._instantiationService.createInstance(NoneExecuteStrategy, toolTerminal.instance, () => toolTerminal.receivedUserInput ?? false);
toolResultMessage = '$(info) Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) to improve command detection';
break;
}
case ShellIntegrationQuality.Basic: {
strategy = this._instantiationService.createInstance(BasicExecuteStrategy, toolTerminal.instance, () => toolTerminal.receivedUserInput ?? false, commandDetection!);
break;
}
case ShellIntegrationQuality.Rich: {
strategy = this._instantiationService.createInstance(RichExecuteStrategy, toolTerminal.instance, commandDetection!);
break;
}
const strategy: ITerminalExecuteStrategy = this._getExecuteStrategy(toolTerminal.shellIntegrationQuality, toolTerminal, commandDetection!);
if (toolTerminal.shellIntegrationQuality === ShellIntegrationQuality.None) {
toolResultMessage = '$(info) Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) to improve command detection';
}
this._logService.debug(`RunInTerminalTool: Using \`${strategy.type}\` execute strategy for command \`${command}\``);
store.add(strategy.onDidCreateStartMarker(startMarker => {
Expand Down Expand Up @@ -762,7 +776,6 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
}
terminalResult = resultArr.join('\n\n');
}

} catch (e) {
// Handle timeout case - get output collected so far and return it
if (didTimeout && e instanceof CancellationError) {
Expand Down Expand Up @@ -1006,6 +1019,21 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
}
}
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

[nitpick] Unnecessary blank line removed. This blank line removal is inconsistent with the codebase style which typically has a blank line before the comment indicating the end of a region.

Suggested change
}
}

Copilot uses AI. Check for mistakes.

private _getExecuteStrategy(shellIntegrationQuality: ShellIntegrationQuality, toolTerminal: IToolTerminal, commandDetection: ICommandDetectionCapability): ITerminalExecuteStrategy {
let strategy: ITerminalExecuteStrategy;
switch (shellIntegrationQuality) {
case ShellIntegrationQuality.None:
strategy = this._instantiationService.createInstance(NoneExecuteStrategy, toolTerminal.instance, () => toolTerminal.receivedUserInput ?? false);
break;
case ShellIntegrationQuality.Basic:
strategy = this._instantiationService.createInstance(BasicExecuteStrategy, toolTerminal.instance, () => toolTerminal.receivedUserInput ?? false, commandDetection!);
break;
case ShellIntegrationQuality.Rich:
strategy = this._instantiationService.createInstance(RichExecuteStrategy, toolTerminal.instance, commandDetection!);
break;
}
return strategy;
}
// #endregion
}

Expand Down
Loading
Loading