Skip to content

Respect terminal cwd when resolving local venvs - #1708

Merged
Stella Huang (StellaHuang95) merged 1 commit into
microsoft:mainfrom
StellaHuang95:fix/terminal-cwd-activation-1631
Aug 13, 2026
Merged

Respect terminal cwd when resolving local venvs#1708
Stella Huang (StellaHuang95) merged 1 commit into
microsoft:mainfrom
StellaHuang95:fix/terminal-cwd-activation-1631

Conversation

@StellaHuang95

Copy link
Copy Markdown
Contributor

Summary

  • resolve terminal environments from the terminal cwd before using workspace-wide fallbacks
  • reject a selected local venv when it belongs to a sibling directory, then use one nearest, unambiguous venv that contains the cwd
  • fail closed instead of activating another project's environment when the cwd project has no safe match
  • keep terminal activation menu context synchronized with the currently active terminal

Fixes #1631

Context

The issue uses a single VS Code workspace folder as a container for several independent Python projects:

AILab/
  ProjectA/.venv
  ProjectB/.venv
  ProjectC/.venv

With the default workspaceSearchPaths ([".venv", "*/.venv"]), all three environments are discovered. However, the workspace root is automatically registered as the only Python project unless the nested projects are explicitly added. A terminal opened in ProjectC could therefore receive ProjectA's activation command.

Besides activating the wrong dependencies and Python version, this affects every integrated terminal opened by other extensions because auto-activation runs on the terminal-open event.

Root cause

The failure was caused by two scope-collapsing decisions:

  1. Nested environment paths resolve to the automatically registered workspace-root project through ancestor project lookup. VenvManager can therefore associate one sorted or persisted sibling venv with that root.
  2. getEnvironmentForTerminal() previously preferred project-wide environment consensus before checking terminal cwd. With exactly one registered project, it returned the root's selected environment immediately, so the cwd heuristic never ran.

Simply moving the existing cwd lookup earlier is insufficient: api.getEnvironment(ProjectC) still maps ProjectC back to the root project and returns the same sibling environment.

Fix

Cwd-aware terminal resolution

The terminal resolver now:

  1. reads shell-integration cwd first, then terminal creation cwd
  2. finds the most-specific registered project containing that cwd
  3. preserves the project's selected environment unless it is a built-in venv located on a divergent sibling branch
  4. for a sibling venv only, searches already-known environments for candidates that:
    • belong to the built-in venv manager
    • are valid and have an absolute sysPrefix
    • live inside the containing project
    • have an owner directory that is an ancestor of the terminal cwd
  5. selects exactly one nearest candidate

If no candidate exists, multiple candidates are equally near, lookup fails, or lookup exceeds one second, the resolver returns no environment rather than activating the wrong one. The losing timeout is cancelled after a successful lookup.

A known cwd project with no selected environment also stops resolution, preventing another project's sole environment from leaking through the previous multi-project fallback.

Compatibility boundaries

This is intentionally terminal-only. It does not change central environment selection, persisted manager state, debugger/Pylance resolution, status-bar selection, task execution, or the public environment API.

Scenario Behavior
workspace/.venv with a terminal in workspace/src Existing root venv remains selected
Registered nested project with an explicit environment Existing project environment remains selected
Conda/Poetry/Pyenv or another external environment Existing selected environment remains selected
Terminal cwd outside all registered projects Existing fallback behavior remains
Terminal cwd unavailable Existing fallback behavior remains
Selected venv is under ProjectA and cwd is under ProjectC Use ProjectC's unique nearest venv, or activate nothing
Cwd project has no selected environment Activate nothing; do not borrow another project's environment

Terminal activation UI

Safe resolution can intentionally return undefined. The activation menu contexts are now cleared in that case instead of retaining the previous terminal's Activate/Deactivate state. Async context updates also verify that the originating terminal is still active, preventing slower lookups or background activation events from overwriting the currently focused terminal's global menu state.

Tests

Added direct coverage for:

  • normal workspace-root venvs and nested cwd paths
  • sibling ProjectA/ProjectB/ProjectC venv resolution
  • shell-integration cwd precedence
  • ambiguous equally near venvs
  • missing local venvs
  • global venv exclusion
  • workspace-root terminals with a selected descendant venv
  • projects with no selected environment
  • preventing another project's environment from leaking into the cwd project
  • environment-list rejection and timeout
  • external environments, explicit nested projects, outside-workspace cwd, and unavailable cwd
  • clearing activation menu contexts when no environment resolves

Validation performed:

  • npm run compile-tests
  • npm run compile
  • ESLint on all changed TypeScript files
  • all 97 tracked unit-test files: 1,525 passing, 5 expected pending

Out of scope

The shell-execution timeout also reported in #1631 is a separate activation-state issue. This PR addresses only selecting the correct environment for a terminal cwd.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2f537bc5-b389-4ee2-aac2-e2b83be47f5c
@StellaHuang95 Stella Huang (StellaHuang95) added the bug Issue identified by VS Code Team member as probable bug label Aug 12, 2026
stopFallback: boolean;
}

async function getEnvironmentForCwd(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Previously, a new terminal could activate a sibling project’s venv because workspace-level selection was checked before terminal cwd. The resolver now uses cwd, rejects sibling venvs, and selects the nearest unambiguous local venv, or activates nothing if unsafe.

@StellaHuang95
Stella Huang (StellaHuang95) merged commit 6138122 into microsoft:main Aug 13, 2026
123 of 126 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Issue identified by VS Code Team member as probable bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-activation forces a single environment across an entire multi-project workspace root, injecting activate commands into unrelated terminals

3 participants