Skip to content

[pull] main from microsoft:main#1373

Merged
pull[bot] merged 23 commits into
KingDEV95:mainfrom
microsoft:main
May 2, 2026
Merged

[pull] main from microsoft:main#1373
pull[bot] merged 23 commits into
KingDEV95:mainfrom
microsoft:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 2, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

AshtonYoon and others added 23 commits April 4, 2026 10:14
Two regressions from the merge of #287050:

1. preview.ts: The merge retained `this.#isScrolling = false` inside
   the early-return guard of `scrollTo()`, which was intentionally
   removed in the original PR. This resets the timer-based flag on
   the very first forward-sync call, allowing subsequent editor scroll
   events to re-trigger forward sync while reverse sync is in
   progress, causing the editor to jump back up.

2. index.ts: The PR converted `onUpdateView` from a decrement-counter
   to a timer-based approach but left initialization and resize
   handlers still using `scrollDisabledCount += 1` without a
   corresponding timer reset. The old scroll handler decremented the
   counter naturally; the new handler only returns early. As a result,
   after page load `scrollDisabledCount` stays at 1 indefinitely,
   blocking all preview-to-editor sync until the user scrolls the
   editor once.

Fixes:
- Remove the erroneous `this.#isScrolling = false` from scrollTo()
- Apply the same timer-reset pattern (200ms) to initialization and
  resize handlers so scrollDisabledCount is always auto-cleared

Fixes #307762
Fixes #313645

Co-authored-by: Copilot <copilot@github.com>
Make background inline summarization the default and only path.
* IChatModes refactor

* Updated IChatModeService to provide modes based on session type.

Co-authored-by: Copilot <copilot@github.com>

* update

---------

Co-authored-by: Copilot <copilot@github.com>
Disable emmet commands when there is no active editor
* reindex cmd

Co-authored-by: Copilot <copilot@github.com>

* few updates

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
…#313079)

* Try to get model and token info to show up for cli in chat

Co-authored-by: Copilot <copilot@github.com>

* make sure that auto mode persists for CLI

* make ui appear for non-contoller api route

* make controller route work without modifying requestHandler

Co-authored-by: Copilot <copilot@github.com>

* dqwdqwdwq

* ship more stuf

Co-authored-by: Copilot <copilot@github.com>

* gate this behind setting

Co-authored-by: Copilot <copilot@github.com>

* cleaner

Co-authored-by: Copilot <copilot@github.com>

* stop messing with tests

Co-authored-by: Copilot <copilot@github.com>

* try fix test

* Make sure the test pass

Co-authored-by: Copilot <copilot@github.com>

* rename better

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: justschen <justchen@microsoft.com>
Concurrent invocations of the bash/powershell shell tools used to share a single PTY, which caused the input streams and output to interleave and garble each other. Acquire shells via a disposable IReference: idle shells are reused, busy ones are skipped, and a new terminal is created when none are idle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* add last asst messages logs

* add last asst messages logs ...

* add tokens info

* add parentHeaderrequestId value to subagent telemetry

* remove debug logging

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* suggested change

* extra verification

* revert suggested change

* remove debug logs

* add modelcallId and parentModelCallId to response.success telemetry

* add engine.messages logs

* fix modelCallId

* add logging

* add turnIndex to response.success

* add iterationNumber proxy for request turn

* add iterationNumber proxy for request turn to model.modelCall events

* add to response.success telemetry

* change parentRequestId to point to correct corresponding requestId

* remove debug logs

* Update extensions/copilot/src/extension/intents/node/toolCallingLoop.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* atomatic review comments changes

---------

Co-authored-by: Yevhen Mohylevskyy <yevhenmohylevskyy@Yevhens-MacBook-Pro-2.local>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Move agent host picker to sessions sidebar (web desktop)

On web desktop (vscode.dev/agents), surface the agent host picker in a
new toolbar at the bottom of the sessions sidebar instead of the
titlebar's left layout. The new widget is modeled on
AICustomizationShortcutsWidget but is always expanded -- no collapse
chevron, no storage key.

Scope:
- Web desktop:  picker moves to the sidebar (new SidebarAgentHost menu).
- Web phone:    unchanged -- still rendered in MobileTitlebarPart.
- Electron:     unchanged -- no host picker, never had one.

Visual alignment:
HostFilterActionViewItem gains a HostFilterAppearance ('titlebar' |
'sidebar') parameter so it can render the same Monaco Button +
.sidebar-action-button shell used by CustomizationLinkViewItem. The
sidebar appearance lays out the picker button as
[remote-icon] [host-name (flex:1)] [chevron-down], with the connect /
disconnect / re-discover indicator as an independent 26x26 sibling
control to the right. When there are no hosts the right slot becomes a
refresh button that triggers rediscover().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update src/vs/sessions/contrib/remoteAgentHost/browser/hostFilterActionViewItem.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/vs/sessions/contrib/sessions/test/browser/agentHostShortcutsWidget.test.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Address PR #313619 review feedback

- Drop the icon-by-state enumeration from the HostFilterActionViewItem
  class JSDoc.
- Sidebar picker no longer no-ops with 0 hosts: pass the click event
  through to `_showMenu`, which already routes to `rediscover()` when
  no hosts are known. Same affordance as the dedicated refresh slot.
- Widen `_showMenu(e)` to accept `Event`; this avoids fabricating a
  synthetic `MouseEvent('click')` that would anchor the context menu
  at (0,0) on touch/gesture activations. `dom.isMouseEvent(e)` keeps
  the runtime check.
- Gate the `AgentHostShortcutsWidget` mount on
  `IsSessionsWindowContext && !IsAuxiliaryWindowContext && !IsPhoneLayoutContext`
  instead of `isWeb && !isPhoneLayout(...)`. Prevents an empty toolbar
  shell in auxiliary windows and aligns the runtime gate with the
  agents-window context the menu items target.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Avoid querySelector in HostFilterActionViewItem (sidebar)

Hold stable references to the leading host icon and trailing chevron
as `_sidebarLeadingIcon` / `_sidebarTrailingIcon` fields, created
once in `_renderSidebar()`. `_renderSidebarButtonAffordances` now
attaches/detaches the chevron via `appendChild` / `remove` on the
stored reference instead of `querySelector(':scope > ...)`, fixing
the `no-restricted-syntax` ESLint warnings reported by CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…l-sync-regressions

markdown: fix scroll sync regressions introduced in #287050
… in web (#313575)

* chat: add real BrowserPluginGitCommandService for adding plugins in web

Replaces the throwing stub at
src/vs/workbench/contrib/chat/browser/pluginGitCommandService.ts with a
real implementation that lets browser/web clients install agent plugins
from public (and authenticated) GitHub repositories without a local git
binary or AHP server.

How it works
- Resolve the requested ref to a commit SHA via GitHub's
  /repos/{owner}/{repo}/commits/{ref} endpoint.
- Download the tarball at that SHA, decompress with the platform
  DecompressionStream, and stream-extract the USTAR archive directly
  into the workbench virtual file system at the caller's targetDir.
  The standard GitHub-archive wrapper directory ({repo}-{shortSha}/)
  is stripped so consumers see a clean tree, and any prior contents
  are wiped first so files removed upstream don't linger.
- Persist {owner, repo, ref, sha, fetchedAt} per-target via
  IStorageService (chat.plugins.browserCache.v1). This lets revParse()
  answer locally and lets pull()/checkout() short-circuit when the
  upstream SHA matches the cached one -- which also feeds
  CustomizationRef.nonce so the AHP server's plugin manager dedupes.
- Best-effort silent IAuthenticationService lookup attaches a GitHub
  token when one is already available, enabling private-repo installs;
  public repos still work with no session. 401/403 surfaces a typed
  GitHubAuthRequiredError so future UI can drive sign-in.
- checkout() handles SHA-pinned plugin sources (the
  AbstractGitPluginSource path): no-op when the SHA matches, otherwise
  fetches the tarball at the requested SHA. Branches/tags/short SHAs
  resolve through the commits API.
- Non-GitHub clone URLs throw an actionable localized error directing
  users to the desktop client or a remote agent host.
- TAR extraction validates entry paths (rejects '.', '..', empty, NUL,
  leading-slash segments and double-checks isEqualOrParent) so a
  malicious archive cannot escape targetDir.

The DI singleton registration in chat.contribution.ts already wires
IPluginGitService -> BrowserPluginGitCommandService; the new
constructor parameters are injected automatically.

Tests
- New src/vs/workbench/contrib/chat/test/browser/pluginGitCommandService.test.ts
  covers URL parsing (canonical / trailing-slash / extra-segment /
  malformed), tarball fetch+extract, no-op pull on SHA match,
  re-download on SHA change, stale-file cleanup, path-traversal entry
  rejection, checkout no-op / re-extract / no-metadata, and the
  auth-required error path. Test fixtures build a minimal valid USTAR
  + gzip via CompressionStream so bytes round-trip through the
  production DecompressionStream.

Reuse notes
- Uses isSuccess / isClientError / asJson from platform/request rather
  than rolling status-code checks.
- Uses dirname / isEqualOrParent / joinPath from base/common/resources
  for path arithmetic and traversal defence.
- GitHubApiClient (sessions/contrib/github) was considered but is
  layering-isolated, JSON-only, and forces sign-in -- wrong semantics
  for best-effort silent auth and binary tarball download.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chat: address council review on browser plugin git service

Council review surfaced ~12 follow-ups across correctness, security,
and parser robustness. This commit addresses the actionable ones.

Correctness
- Stage extraction in a sibling `.staging-{uuid}` directory and swap
  into place via `IFileService.move(..., overwrite=true)` only on
  success. If anything throws (network, gunzip, malformed tar,
  cancellation, FS write error), the staging dir is cleaned up and
  the existing `targetDir` is left untouched. Previously the target
  was wiped *before* extraction began, so a mid-flight failure left
  the persisted SHA cache pointing at an empty directory.
  (consensus C1)
- `pull()` now wraps its catch block with `_maybeLogTransientError`
  for parity with `cloneRepository` / `checkout`. (S6)
- `revParse(repoDir, ref)` no longer silently ignores `ref`: when
  asked for a 40-hex SHA that does not match the cached one, it
  throws instead of lying. (S3)

Rate-limit detection
- New `GitHubRateLimitError`, distinct from `GitHubAuthRequiredError`,
  thrown when GitHub returns 403 with `X-RateLimit-Remaining: 0` or a
  `Retry-After` header. Higher-layer UI can present "wait" rather than
  "sign in". `_maybeLogTransientError` logs the retry-after window. (C2)

Auth + redirects
- Drop the dead `followRedirects: 5` option (browser fetch ignores it
  per IRequestService impl). Add a comment on
  `fetchAndExtractGitHubTarball` explaining the codeload signed-URL
  flow: GitHub's tarball endpoint 302s to a URL whose authorization
  is encoded in the URL itself, so private-repo downloads survive the
  cross-origin Authorization-header strip. (C3 cleanup)
- Document the multi-account auth-session selection limitation in
  `_lookupGitHubToken` rather than try to solve it here -- account
  selection is the auth provider's responsibility. (C6)

Parser robustness
- `readOctal` -> `readNumericField`. Now handles:
  - leading whitespace (legal POSIX padding) -- previously truncated to 0
  - GNU base-256 binary encoding (high bit of byte 0 set) -- previously
    silently mis-aligned subsequent block offsets
  - Invalid fields throw rather than silently returning 0, so corrupt
    tarballs surface as errors instead of producing empty entries.
- USTAR `prefix` field now joined unconditionally per spec
  (`${prefix}/${name}`); previous heuristic skipped the prefix when
  `name.startsWith(prefix)` which is non-standard. The GNU LongLink
  path correctly bypasses prefix join via a `fromLongLink` flag. (C5)
- `stripArchiveRoot` rejects absolute paths instead of silently
  rebasing them under `targetDir`. (S4)
- `safeJoinUnderTarget` also rejects backslash-bearing segments to
  defend against Windows-style separators on tar entries that would
  escape `targetDir` when materialised through a Windows AHP server's
  `agent-client:` provider. (S1)

URL parsing
- Reorder normalisation in `parseGitHubCloneUrl` so trailing slashes
  are stripped before the `.git` suffix; URLs like
  `https://github.com/o/r.git/` now parse correctly. (S2)

Cache hygiene
- Cache-key on `getComparisonKey(targetDir, ignoreFragment=true)`
  instead of `URI.toString()`, so callers passing equivalent URIs
  with different trailing-slash / percent-encoding don't silently
  miss the cache. (S5)
- On first cache load, kick off a fire-and-forget sweep that drops
  entries whose `targetDir` no longer exists on disk. Bounds the
  storage map size when external code (e.g.
  `cleanupPluginSource`) deletes a plugin directory without
  notifying us. (C4)

Tests
- Rate-limit (`GitHubRateLimitError`) on `403 + X-RateLimit-Remaining: 0`.
- Failed extraction leaves the previous `targetDir` intact and the
  cache reporting the previous SHA.
- Backslash-traversal entry rejected.
- USTAR prefix split + GNU LongLink paths via a new
  `makeGzippedTarWithSpecial` test fixture.
- `parseGitHubCloneUrl` accepts `https://github.com/o/r.git/`.
- `revParse` throws on unrelated full SHA, accepts cached one.

Council items not addressed in this commit
- Multi-account session selection (C6): documented as a VS Code-wide
  auth UX concern, not a plugin-git issue.
- Cross-origin redirect end-to-end test (C3): the unit-test stub
  doesn't simulate redirects; the fix is a real-world smoke test
  against vscode.dev which is out of scope for this commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chat: keep default plugin toolbar actions

* chat: refine plugin add actions

* chat: reuse signed in github session for plugin clone

* chat: fallback to anonymous plugin clone

* chat: fetch plugin repos via tree+raw to bypass CORS

GitHub's /tarball/ endpoint 302-redirects to codeload.github.com,
which returns no CORS headers. Browser fetch() therefore fails the
preflight check with TypeError: Failed to fetch before any of the
existing auth-retry logic in BrowserPluginGitCommandService can run,
so even public repos with a signed-in session cannot be installed.

Replace the tarball flow with two CORS-friendly endpoints:
  - GET /repos/{owner}/{repo}/git/trees/{sha}?recursive=1 returns the
    full file listing.
  - GET https://raw.githubusercontent.com/{owner}/{repo}/{sha}/{path}
    returns each blob's bytes (and accepts the same Authorization
    header for private repos).

Drop the now-unused gunzip + tar parser. Update tests to stub the
new tree + raw responses instead of building synthetic gzipped tar
archives.

* chat: fetch plugin blobs via api.github.com to bypass CORS

raw.githubusercontent.com refuses the OPTIONS preflight that an
Authorization: Bearer header forces, so the previous tree+raw flow
still failed the CORS check (TypeError: Failed to fetch).

Switch the per-blob download to api.github.com's /git/blobs/{sha}
endpoint, which is properly CORS-enabled and accepts auth headers.
The blob SHA already comes back from the tree response, so no extra
round-trips are needed; content is base64-encoded JSON which we
decode via decodeBase64.

Also add a loggedRequest wrapper that re-throws transport-level
errors with the URL we were trying to reach. Without it, browser
fetch CORS / DNS failures bubble up as a bare 'TypeError: Failed
to fetch' that hides which request actually failed. Surface the
same context through _maybeLogTransientError in the install path.

* chat: drop unused bytesResponse test helper

* chat: rename githubTarballFetcher to githubRepoFetcher

The file no longer contains tarball logic — it fetches the repo
tree and individual blobs via api.github.com. Rename to match.

* chat: trim verbose comments in plugin git service

* chat: tidy plugin git service auth ladder and comments

- Flatten the nested try/catch in cloneRepository into a linear loop over
  the auth-ladder rungs (signed-in token → anonymous → fresh repo session).
- Trim further verbose comments in the fetcher and cache helpers.

* chat: surface locally-installed plugin items in remote-harness view

When the active harness has both an itemProvider and a syncProvider
(remote agent host), fetchItems blends remote items with local items.
The local pass only included PromptsStorage.local / .user files, so
files contributed by locally-installed agent plugins (e.g. one just
cloned into vscode-userdata:/User/agent-plugins/...) never reached
the customizations UI.

Widen the local pass to also include PromptsStorage.plugin files.
Plugin files are not individually syncable — the plugin is the unit
of sync — so they're returned without the syncable marker. They
still get the right grouping via the normalizer's plugin-URI check.

* chat: refresh customizations debug output

- Stage 6: render fromMarketplace as name@version (marketplace, type)
  instead of [object Object].
- Stage 3: surface syncable count and per-item syncable / pluginUri
  flags so the local syncable vs locally-installed plugin split (added
  in fetchLocalSyncableItems) is visible.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
@pull pull Bot locked and limited conversation to collaborators May 2, 2026
@pull pull Bot added the ⤵️ pull label May 2, 2026
@pull pull Bot merged commit 9b92388 into KingDEV95:main May 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.