Skip to content

@W-23618508 fix VS Code extension blocking others on empty workspace - #598

Merged
clavery merged 1 commit into
mainfrom
work/W-23618508
Jul 29, 2026
Merged

@W-23618508 fix VS Code extension blocking others on empty workspace#598
clavery merged 1 commit into
mainfrom
work/W-23618508

Conversation

@clavery

@clavery clavery commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes W-23618508: the B2C Commerce VS Code extension was blocking other extensions when opened in an empty (no-folder) or non-B2C workspace. Clicking a B2C DX activity-bar icon in an empty window would spin forever, and other extensions (e.g. Claude Code) would also show a loading badge with an empty, un-activated panel.

Root cause

VS Code runs all extensions in a single shared extension-host process, so synchronous CPU work in one extension's activation stalls the event loop and makes every other extension appear stuck "activating" (the spinner + empty panels in the repro).

The extension can be activated in an empty window by several events — clicking a B2C DX view icon (onView:*), or opening any JS/TS file (the extension contributes a TypeScript server plugin, which VS Code loads for all JS/TS files). Whatever the trigger, activate()activateInner() then ran heavy synchronous, unbounded filesystem work:

  1. detectWorkingDirectory() fell back to process.cwd() when there were no workspace folders — the extension host's arbitrary cwd, often the user's home directory.
  2. Eager activation work then ran unbounded globSync('**/.project') walks on the shared extension-host thread (via registerScriptTypesCartridgeService.getCartridges()findCartridges(cwd), and updateStorefrontNextContext()detectWorkspaceType(cwd)).

Scanning the whole home tree synchronously freezes the extension host, blocking every other extension.

Fix (all in packages/b2c-vs-extension)

Do no filesystem discovery without a concrete workspace folder, and never let findCartridges scan out of home/root:

  • workspace-discovery.ts: added isUnscannableRoot(dir) (empty / home dir / filesystem root) and findCartridgesSafe(dir, opts) — the single entry point all extension cartridge discovery now uses. It returns [] for unscannable roots (never falls back to process.cwd()) and depth-bounds every scan (WORKSPACE_DISCOVERY_MAX_DEPTH = 5). Mirrors the MCP server's existing registry.ts home/root guard.
  • config-provider.ts: detectWorkingDirectory() returns '' (not process.cwd()) when there are no workspace folders; resolveAsync skips resolution/discovery for home/root/missing dirs.
  • extension.ts: updateStorefrontNextContext() skips detection for unscannable roots and depth-bounds the scan otherwise.
  • Routed all findCartridges call sites through findCartridgesSafe (cartridge-service, code-sync-manager, deploy-command, debugger, jobs-commands, jobs-tree-provider, scaffold-commands, onboardingPanel) so no path can recursively scan out of home.

Manual testing

Reproduce the original report:

  1. Install the VSIX and open VS Code → File → New Window (empty window, no folder).
  2. Click any B2C DX activity-bar icon (WebDAV Explorer, Sandbox Explorer, etc.).
    • Before: the B2C icon shows a spinner that never resolves; clicking another extension's icon (e.g. Claude Code) also shows a spinner with an empty, un-activated panel — the extension host is blocked.
    • After: the B2C DX views load immediately (empty/welcome state) and other extensions activate normally with no spinner. Output → B2C DX logs No workspace folders open; skipping filesystem discovery.
  3. (Also) open your home directory as a folder and confirm the extension does not hang and does no recursive .project scan.
  4. (Regression) open a real B2C project (with dw.json and cartridges) and confirm cartridge discovery, code sync, debugger, and Script API IntelliSense still work as before.

The extension registers a TypeScript server plugin, so VS Code activates
it whenever any JS/TS file is opened — including empty (no-folder)
windows. On that path the config provider fell back to process.cwd()
(the extension host's arbitrary cwd, often the user's home directory),
and eager activation work then ran unbounded synchronous
globSync('**/.project') / detectWorkspaceType filesystem walks on the
shared extension-host thread, freezing every other extension.

Fix (all in packages/b2c-vs-extension):
- detectWorkingDirectory() returns '' when there are no workspace
  folders instead of falling back to process.cwd(), so an empty window
  does no filesystem discovery.
- Add isUnscannableRoot() (home dir, filesystem root, or empty path) and
  guard config resolution + storefront-next detection with it, mirroring
  the MCP server's existing home/root guard.
- Add findCartridgesSafe(): the single entry point all extension
  cartridge discovery now uses. It refuses to scan an empty/home/root
  directory (never falls back to cwd) and depth-bounds the scan
  (WORKSPACE_DISCOVERY_MAX_DEPTH=5). Route every findCartridges() call
  site through it.
- Add unit tests for isUnscannableRoot and findCartridgesSafe.

Gated on pnpm run typecheck:agent (all packages) and the extension test
suite (all vscode-test labels) passing.
@clavery
clavery marked this pull request as ready for review July 28, 2026 23:55
@clavery
clavery requested a review from wei-liu-sf as a code owner July 28, 2026 23:55
@clavery
clavery requested a review from yhsieh1 July 28, 2026 23:56

@yhsieh1 yhsieh1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks good. Thanks!

@clavery
clavery merged commit 258f6bd into main Jul 29, 2026
8 checks passed
@clavery
clavery deleted the work/W-23618508 branch July 29, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants