1
>
/*---------------------------------------------------------------------------------------------
copilotShellTools.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import type { Tool, ToolResultObject } from '@github/copilot-sdk';
7
>
import { generateUuid } from '../../../../base/common/uuid.js';
8
>
import { URI } from '../../../../base/common/uri.js';
9
>
import { Disposable, DisposableStore, type IReference, toDisposable } from '../../../../base/common/lifecycle.js';
10
>
import { Emitter, Event } from '../../../../base/common/event.js';
11
>
import { IEnvironmentService } from '../../../environment/common/environment.js';
12
>
import { IInstantiationService } from '../../../instantiation/common/instantiation.js';
13
>
import { ILogService } from '../../../log/common/log.js';
14
>
import { IProductService } from '../../../product/common/productService.js';
15
>
import { ISandboxHelperService } from '../../../sandbox/common/sandboxHelperService.js';
16
>
import type { ITerminalSandboxResolvedNetworkDomains } from '../../../sandbox/common/terminalSandboxService.js';
17
>
import { TerminalSandboxEngine } from '../../../sandbox/common/terminalSandboxEngine.js';
18
>
import { TerminalClaimKind, type TerminalSessionClaim } from '../../common/state/protocol/state.js';
19
>
import { isZsh } from '../agentHostShellUtils.js';
20
>
import { IAgentHostTerminalManager } from '../agentHostTerminalManager.js';
21
>
import { createAgentHostSandboxEngine } from './agentHostSandboxEngine.js';
22
>
import { IAgentConfigurationService } from '../agentConfigurationService.js';
23
>
import { DEFAULT_SHELL_COMMAND_TIMEOUT_MS, executeShellCommand, isMultilineCommand, prefixForHistorySuppression, prepareOutputForModel, shellTypeForExecutable, type IShellCommandResult, type ShellType } from '../shared/shellCommandExecution.js';
24
>
25
>
// Re-exported for consumers (and tests) that historically imported these
26
>
// shell helpers from this module. Their canonical home is the shared,
27
>
// agent-agnostic shellCommandExecution module.
28
>
export { isMultilineCommand, prefixForHistorySuppression, shellTypeForExecutable };
29
>
export type { ShellType };
30
>
31
>
/**
32
>
* Message returned to the model when a command switches to the terminal's
33
>
* alternate buffer (typically an interactive full-screen UI).
34
>
*/
35
>
const ALT_BUFFER_MESSAGE = 'The command opened the alternate buffer and is still running in the terminal. It likely launched an interactive terminal UI. Use write_bash/write_powershell to interact with it, or shutdown the shell to stop it.';
36
>
37
>
/**
38
>
* Tracks a single persistent shell instance backed by a managed PTY terminal.
39
>
*/
40
>
interface IManagedShell {
41
>
readonly id: string;
42
>
readonly terminalUri: string;
43
>
readonly shellType: ShellType;
44
>
readonly executable: string;
45
>
}
46
>
47
>
// ---------------------------------------------------------------------------
48
>
// ShellManager
49
>
// ---------------------------------------------------------------------------
50
>
51
>
/**
52
>
* Per-session manager for persistent shell instances. Each shell is backed by
53
>
* a {@link IAgentHostTerminalManager} terminal and participates in AHP terminal
54
>
* claim semantics.
55
>
*
56
>
* Created via {@link IInstantiationService} once per session and disposed when
57
>
* the session ends.
58
>
*/
59
>
export class ShellManager extends Disposable {
60
>
61
>
private readonly _shells = new Map<string, IManagedShell>();
62
>
private readonly _toolCallShells = new Map<string, string>();
63
>
private _resolvedExecutable: Promise<string> | undefined;
64
>
private _sandboxEngine: TerminalSandboxEngine | undefined;
65
>
/** Set of shell ids currently executing a command and unsafe to share. */
66
>
private readonly _busyShellIds = new Set<string>();
67
>
/** Release listeners for shells held after a tool returns while the command is still running. */
68
>
private readonly _heldShellReleaseListeners = new Map<string, DisposableStore>();
69
>
70
>
private readonly _onDidAssociateTerminal = this._register(new Emitter<{ toolCallId: string; terminalUri: string; displayName: string }>());
71
>
readonly onDidAssociateTerminal: Event<{ toolCallId: string; terminalUri: string; displayName: string }> = this._onDidAssociateTerminal.event;
72
>
73
>
constructor(
74
private readonly _sessionUri: URI,
75
public readonly workingDirectory: URI | undefined,