getTerminalInfos(): TerminalInfo[] {
return [...this._terminals.values()].map(t => ({
title: t.title,
claim: t.claim,
exitCode: t.exitCode,
}));
}
Frontier kind: Code frontier
unlabeled · c_423d80934a2c
8 tests · 25781 LOC · 110 files · introduces 0 tests · 212 LOC · 2 files
The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.
Introduced files, introduced tests, and structurally relevant concept specialization
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.
Every exact file and test below is linked only from the concept that introduces it.
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle Action bar has broken accessibility #100273|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle dispose disposable array|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/common/agentHostSchema.test|title=agentHostSchema createSchema toProtocol emits a JSON-Schema-compatible object|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/common/agentHostSchema.test|title=agentHostSchema platformSessionSchema exposes approval choices in picker order with current copy|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication creates new entry when none exists|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication duplicate IDs with existing entry - fixed version reuses existing|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication duplicate status IDs - buggy version leaks entry|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication duplicate status IDs - fixed version reuses entry from current update|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication mixed unique and duplicate IDs|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/languageStatus/test/common/languageStatusDedupe.test|title=LanguageStatus - Dedicated Entry Deduplication reuses existing entry from previous update|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/charCode.test|title=CharCode has good values|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/path.test|title=Paths (Node Implementation) path|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI File paths containing apostrophes break URI parsing and cannot be opened #276075|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI URI#file, win-speciale|occurrence=1Every collected test enters the hierarchy at exactly one concept.
No tests are introduced at this concept. Its intent tests are introduced by other concepts.
Every collected source range enters the hierarchy at exactly one concept.
2 files ranked by introduced lines: 212 introduced LOC across 22 ranges. Expand a file to inspect source; the > gutter marks introduced lines.
getTerminalInfos(): TerminalInfo[] {
return [...this._terminals.values()].map(t => ({
title: t.title,
claim: t.claim,
exitCode: t.exitCode,
}));
}
*/
async createTerminal(params: CreateTerminalParams, options?: { shell?: string; preventShellHistory?: boolean; nonInteractive?: boolean }): Promise<void> {
if (this._terminals.has(uri)) {
throw new Error(`Terminal already exists: ${uri}`);
}
const cwd = await this._resolveCwd(params.cwd, uri);
const cols = params.cols ?? 80;
const rows = params.rows ?? 24;
const shell = options?.shell ?? await this.getDefaultShell();
const name = platform.isWindows ? 'cmd' : 'xterm-256color';
this._logService.info(`[TerminalManager] Creating terminal ${uri}: shell=${shell}, cwd=${cwd}, cols=${cols}, rows=${rows}`);
// Shell integration — inject scripts so the shell emits OSC 633 sequences
const nonce = generateUuid();
const env: Record<string, string> = { ...process.env as Record<string, string> };
// Attribute these commands to VS Code. Already inherited from the agent
// host process; set here as defense in depth.
env[AiAgentEnvVar] = AiAgentEnvValue;
if (options?.preventShellHistory) {
// Picked up by the shell integration scripts to set HISTCONTROL=ignorespace
// (bash) / HIST_IGNORE_SPACE (zsh), or suppress PSReadLine history (pwsh).
env['VSCODE_PREVENT_SHELL_HISTORY'] = '1';
}
// Zsh-specific fixups for agent tool terminals: disable bang history
agentHostTerminalManager.ts
// expansion and enable inline # comments.
if (params.claim?.kind === TerminalClaimKind.Session && isZsh(shell)) {
env['VSCODE_AGENT_ZSH_FIXUPS'] = '1';
}
// Suppress paging and interactive prompts so that tool-spawned
// terminals produce clean, machine-friendly output. An empty
env['DEBIAN_FRONTEND'] = 'noninteractive';
}
if (platform.isMacintosh) {
const shellName = pathParse(shell).name;
if (shellName.match(/(zsh|bash)/)) {
}
}
const injection = await getShellIntegrationInjection(
{ executable: shell, args: shellArgs, forceShellIntegration: true },
{
shellIntegration: { enabled: true, suggestEnabled: false, nonce },
windowsUseConptyDll: false,
environmentVariableCollections: undefined,
workspaceFolder: undefined,
isScreenReaderOptimized: false,
},
undefined,
this._logService,
this._productService,
);
let commandTracker: ICommandTracker | undefined;
if (injection.type === 'injection') {
this._logService.info(`[TerminalManager] Shell integration injected for ${uri}`);
if (injection.envMixin) {
for (const [key, value] of Object.entries(injection.envMixin)) {
if (value !== undefined) {
env[key] = value;
}
}
}
if (injection.newArgs) {
shellArgs = injection.newArgs;
}
if (injection.filesToCopy) {
for (const f of injection.filesToCopy) {
try {
}
}
parser: new Osc633Parser(),
nonce,
commandCounter: 0,
detectionAvailableEmitted: false,
};
} else {
this._logService.info(`[TerminalManager] Shell integration not available for ${uri}: ${injection.reason}`);
}
const ptyProcess = await this._spawnPty(shell, shellArgs, {
name,
cwd,
env,
cols,
rows,
});
const store = new DisposableStore();
const claim: TerminalClaim = params.claim ?? { kind: TerminalClaimKind.Client, clientId: '' };
const onDataEmitter = store.add(new Emitter<string>());
const onExitEmitter = store.add(new Emitter<number>());
const onClaimChangedEmitter = store.add(new Emitter<TerminalClaim>());
const onCommandFinishedEmitter = store.add(new Emitter<ICommandFinishedEvent>());
const headlessTerminal = store.add(new AgentHostHeadlessTerminal({
cols,
rows,
scrollback: HEADLESS_TERMINAL_SCROLLBACK,
logService: this._logService,
}));
const managed: IManagedTerminal = {
uri,
store,
pty: ptyProcess,
onDataEmitter,
onExitEmitter,
onClaimChangedEmitter,
onCommandFinishedEmitter,
title: params.name ?? shell,
cwd,
cols,
rows,
content: [],
contentSize: 0,
claim,
commandTracker,
headlessTerminal,
terminalQueryFilterState: { pendingData: '' },
};
this._terminals.set(uri, managed);
store.add(headlessTerminal.onResponseData(data => {
this._logService.debug(`[TerminalManager] Writing headless terminal response for ${uri}: ${JSON.stringify(data)}`);
try {
this._logService.debug(`[TerminalManager] Failed to write headless terminal response for ${uri}: ${err instanceof Error ? err.message : String(err)}`);
}
// Wire PTY events → protocol events
store.add(toDisposable(() => {
try { ptyProcess.kill(); } catch { /* already dead */ }
}));
const onFirstData = new DeferredPromise<void>();
const dataListener = ptyProcess.onData(rawData => {
void managed.headlessTerminal?.writePtyData(rawData);
this._handlePtyData(managed, rawData);
onFirstData.complete();
});
store.add(toDisposable(() => dataListener.dispose()));
const exitListener = ptyProcess.onExit(e => {
managed.exitCode = e.exitCode;
managed.onExitEmitter.fire(e.exitCode);
});
this._broadcastTerminalList();
store.add(toDisposable(() => exitListener.dispose()));
// Poll for title changes (non-Windows)
if (!platform.isWindows) {
const titleInterval = setInterval(() => {
const newTitle = ptyProcess.process;
if (newTitle && newTitle !== managed.title) {
this._broadcastTerminalList();
}
store.add(toDisposable(() => clearInterval(titleInterval)));
}
await raceCancellablePromises([onFirstData.p, timeout(WAIT_FOR_PROMPT_TIMEOUT)]);
this._broadcastTerminalList();
}
protected async _spawnPty(file: string, args: string[], options: import('node-pty').IPtyForkOptions | import('node-pty').IWindowsPtyForkOptions): Promise<import('node-pty').IPty> {
/** Process raw PTY output: parse OSC 633 sequences, dispatch actions, track content. */
private _handlePtyData(managed: IManagedTerminal, rawData: string): void {
// Without command detection there are no OSC 633 sequences to
// interleave — the whole chunk is command output. With a tracker,
// process cleaned-data and events in stream order so that output which
// arrives before a CommandFinished marker (commonly in the same PTY
// read for fast commands) is appended to the command's output BEFORE the
// finished event snapshots it. Handling all events first would emit
// CommandFinished with the not-yet-appended output missing.
const segments: Osc633ParseSegment[] = tracker
? tracker.parser.parseSegments(rawData)
: (rawData.length > 0 ? [{ kind: 'data', data: rawData }] : []);
// Preserve OSC 633 stream order when emitting AHP actions: command data must remain between
// TerminalCommandExecuted and TerminalCommandFinished, matching the AHP contract and xterm.
let pendingClientData = '';
const flushClientData = (): void => {
if (pendingClientData.length === 0) {
return;
}
this._stateManager.dispatchServerAction(managed.uri, {
type: ActionType.TerminalData,
data: pendingClientData,
});
pendingClientData = '';
};
for (const segment of segments) {
if (segment.kind === 'event') {
flushClientData();
this._handleOsc633Event(managed, tracker!, segment.event);
continue;
}
// Agent Host's server-side headless terminal answers CPR so terminals
// work without an attached client. Hide those queries from client xterms
// to avoid a second CPR response flowing back through AgentHostPty.input.
const cleanedData = removeServerHandledTerminalQueries(segment.data, managed.terminalQueryFilterState);
if (cleanedData.length > 0) {
this._appendToContent(managed, cleanedData);
pendingClientData += cleanedData;
}
}
flushClientData();
// Trim content if too large
this._trimContent(managed);
}
/** Handle a parsed OSC 633 event by dispatching the appropriate protocol actions. */
*/
private async _resolveCwd(cwd: string | undefined, terminalURI: string): Promise<string> {
if (cwd) {
const parsed = URI.parse(cwd);
if (parsed.scheme === 'file' && parsed.fsPath && parsed.fsPath !== '/') {
resolved = parsed.fsPath;
} else {
this._logService.warn(`[TerminalManager] Ignoring non-file cwd for ${terminalURI}: ${cwd}`);
}
try {
if (resolved) {
const stat = await fs.promises.stat(resolved);
if (stat.isDirectory()) {
return resolved;
}
}
} catch {
// fall through to fallback
}
const fallback = process.env['HOME'] || process.env['USERPROFILE'] || process.cwd();
agentHostTerminalManager.ts
this._logService.warn(`[TerminalManager] cwd '${resolved}' is not accessible, falling back to ${fallback}`);
return fallback;
}
/** Dispatch root/terminalsChanged with the current terminal list. */
private _broadcastTerminalList(): void {
type: ActionType.RootTerminalsChanged,
terminals: this.getTerminalInfos(),
});
}
override dispose(): void {
for (const terminal of this._terminals.values()) {
}
this._terminals.clear();
super.dispose();
case ActionType.RootTerminalsChanged:
case ActionType.RootConfigChanged: