Back language model tools and the Command Explorer with new LSP requests#2298
Open
andyleejordan wants to merge 3 commits into
Open
Back language model tools and the Command Explorer with new LSP requests#2298andyleejordan wants to merge 3 commits into
andyleejordan wants to merge 3 commits into
Conversation
Convert `powerShell/showHelp` from a fire-and-forget notification into a
request that returns `ShowHelpResult { HelpText }`, so the client can render
help in a read-only editor pane (and the language model `get_help` tool can
reuse the same path) instead of printing into the integrated console.
The handler captures `Get-Help -Full | Out-String` and `.Trim()`s both ends —
`Out-String` pads the output with a leading and trailing blank line, which
looked wrong in the help pane and in tool output.
Drafted by Copilot (Claude Opus 4.8).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The handler previously serialized the entire command table (names, modules, and full parameter metadata) on every request, which is slow enough to hang the `get_command` language model tool and made the Command Explorer take minutes to populate. Extend `GetCommandParams` so callers can ask for only what they need: - `Name`/`Module` (both wildcard-capable) scope the `Get-Command` call so we don't materialize everything; an unmatched filter writes a non-terminating error, so we pass `-ErrorAction Ignore` and return an empty list instead. - `ExcludeParameters` takes a fast path that returns just name, module, and the new `ModuleVersion` without touching `Parameters`/`ParameterSets`, whose resolution and serialization dominate the cost. - Editor-injected commands are always skipped: the PSES host's fake `PSConsoleHostReadLine` (version 0.0.0) and VS Code's shell-integration helpers (`__VSCode-Escape-Value`, `Set-MappedKeyHandler[s]`) are plumbing, not commands a user authored or imported. - `ExcludeDefaultFunctions` (opt-in) drops PowerShell's module-less default-session functions (`cd..`, `prompt`, `TabExpansion2`, ...) and the install's `pwsh.profile.resource` script. The names come from `InitialSessionState.CreateDefault2()` so the list stays correct across PowerShell versions; module-provided commands are never affected. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds server-side LSP request support needed by upcoming VS Code extension features (language model tools, redesigned Command Explorer, and a read-only Show Help pane), aligning PowerShellEditorServices with new client capabilities in the companion VS Code PR.
Changes:
- Converts
powerShell/showHelpfrom a notification into a request that returns full help text as a string. - Enhances
powerShell/getCommandwith optional name/module filtering, a fast path to exclude parameter metadata, and filtering for editor-injected/default-session commands. - Adds a new
powerShell/getModulerequest handler plus Copilot build/test instructions documentation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/PowerShellEditorServices/Services/PowerShell/Handlers/ShowHelpHandler.cs | Switches showHelp to a request and returns trimmed help text from Get-Help -Full | Out-String. |
| src/PowerShellEditorServices/Services/PowerShell/Handlers/GetModuleHandler.cs | Adds a new LSP request to retrieve module metadata for Command Explorer tooltips. |
| src/PowerShellEditorServices/Services/PowerShell/Handlers/GetCommandHandler.cs | Adds filtering/fast-path options and excludes editor-injected/default-session commands. |
| src/PowerShellEditorServices/Server/PsesLanguageServer.cs | Registers the new GetModuleHandler with the language server. |
| .github/copilot-instructions.md | Documents local build/test workflows and repo architecture/conventions for Copilot. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a8b603f to
8dfaff7
Compare
andyleejordan
commented
Jun 10, 2026
Comment on lines
+64
to
+88
| [System.Diagnostics.DebuggerHidden()] | ||
| [CmdletBinding()] | ||
| param ( | ||
| [String]$Name, | ||
| [String]$Version | ||
| ) | ||
| $modules = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -ErrorAction Ignore | ||
| if ($Version) { | ||
| $modules = $modules | Microsoft.PowerShell.Core\Where-Object { $_.Version.ToString() -eq $Version } | ||
| } | ||
| $module = $modules | Microsoft.PowerShell.Utility\Sort-Object Version -Descending | Microsoft.PowerShell.Utility\Select-Object -First 1 | ||
| if ($null -eq $module) { | ||
| return | ||
| } | ||
| [PSCustomObject]@{ | ||
| Name = $module.Name | ||
| Version = $module.Version.ToString() | ||
| Description = $module.Description | ||
| Path = $module.Path | ||
| Author = $module.Author | ||
| CompanyName = $module.CompanyName | ||
| ProjectUri = if ($module.ProjectUri) { $module.ProjectUri.ToString() } else { '' } | ||
| PowerShellVersion = if ($module.PowerShellVersion) { $module.PowerShellVersion.ToString() } else { '' } | ||
| } | ||
| "; |
Member
Author
There was a problem hiding this comment.
@SeeminglyScience main thing I'd like your eye on.
andyleejordan
commented
Jun 10, 2026
Comment on lines
-43
to
-60
| $helpUri = [Microsoft.PowerShell.Commands.GetHelpCodeMethods]::GetHelpUri($command) | ||
|
|
||
| $oldSslVersion = [System.Net.ServicePointManager]::SecurityProtocol | ||
| [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 | ||
|
|
||
| # HEAD means we don't need the content itself back, just the response header | ||
| $status = (Microsoft.PowerShell.Utility\Invoke-WebRequest -Method Head -Uri $helpUri -TimeoutSec 5 -ErrorAction Stop).StatusCode | ||
| if ($status -lt 400) { | ||
| $null = Microsoft.PowerShell.Core\Get-Help $CommandName -Online | ||
| return | ||
| } | ||
| } catch { | ||
| # Ignore - we want to drop out to Get-Help -Full | ||
| } finally { | ||
| [System.Net.ServicePointManager]::SecurityProtocol = $oldSslVersion | ||
| } | ||
|
|
||
| return Microsoft.PowerShell.Core\Get-Help $CommandName -Full |
Member
Author
There was a problem hiding this comment.
@SeeminglyScience and the removal of the "look up online" bit that I don't think ever worked well for us
ca19276 to
7d3efc5
Compare
The Command Explorer groups commands under versioned module nodes and shows a tooltip on hover. Add a `getModule` request that returns a single module's metadata (version, description, path, author, company, project URI, required PowerShell version) so the client can populate those tooltips lazily, and register the handler in `PsesLanguageServer`. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7d3efc5 to
25305c7
Compare
25305c7 to
ac66fc4
Compare
andyleejordan
added a commit
that referenced
this pull request
Jun 16, 2026
We had no `.github/copilot-instructions.md`, so agents working in this repo had to rediscover how to build and test, how the projects fit together, and how we label pull requests. This adds a single instructions file covering all of it: - **Build & Test** — `dotnet` directly for the fast inner loop versus `Invoke-Build` (which needs `InvokeBuild`/`platyPS`) for assembling the full module and running the complete CI suite. - **Architecture** — the project layout, key services, the LSP/DAP handler pattern, and how the server is wired up. - **Conventions** — C# style enforced by `.editorconfig`, the xUnit testing setup, and the multi-targeting story. - **Pull Request Labels** — every PR needs at least one `Area-*` label and exactly one `Issue-*` label (plus `OS-*` and `Ignore` when relevant). The `Issue-*` label is what GitHub's auto-generated release notes key off of (see `.github/release.yml`); a PR without one silently falls through to "Other Changes 🙏". The build, architecture, and conventions content previously rode along in #2298; consolidating it here keeps that PR focused on its LSP changes and gives us a single source of truth for the instructions. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JustinGrote
pushed a commit
that referenced
this pull request
Jun 18, 2026
* Make `OnIdle` tests deterministic by polling instead of sleeping `CanRunOnIdleTask` (and its twin `CanRunOnIdleInProfileTask`) were flaky on the net462 (Windows PowerShell 5.1) CI leg — the former was just caught failing on PR #2298's Windows job. The root cause is that `PsesInternalHost.OnPowerShellIdle` calls `Events.GenerateEvent(PSEngineEvent.OnIdle, ...)`, which only *enqueues* the event. For a subscriber registered with `-Action {...}`, PowerShell doesn't run the action scriptblock inline; it becomes a pending action that the engine dispatches asynchronously on the pipeline thread, around subsequent pipeline invocations. So the action's execution was never synchronized with the test's `$handled` read, and the fixed `Thread.Sleep(2000)` was just a timing guess — sometimes too short on the slower WinPS leg, leaving `$global:handled` still `$false` at the assertion. The key realization is that each *additional* pipeline execution gives the engine another chance to drain the pending action, so re-reading the handler variable in a loop both waits for *and* drives completion. I replaced the sleep with a shared `WaitForHandledAsync` helper that polls the variable (~200ms apart, ~15s ceiling) until it reports `$true`, returning the last observed value on timeout so the assertion still fails loudly. This keeps the tests' intent intact and isn't merely a longer sleep. I validated both tests on net8.0 (green across repeated runs, ~0.4s each vs. the old fixed 2s); net462 can't run on macOS, but the mechanism is identical across targets and the 15s ceiling self-terminates on success, so it's strictly safer on the slow leg without slowing the fast one. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Move `OnIdle` assertion into helper and drop list return Small follow-up to review feedback: both call sites only ever asserted the handler variable became `$true`, so the `IReadOnlyList<bool>` return was needless ceremony. `AssertHandledAsync` now owns the assertion — it returns once the variable reports `$true` and otherwise fails via `Assert.Fail` when the ~15s poll window elapses, which reads as "the OnIdle handler never ran." `Assert.Fail` is fine here — we're on xUnit 2.9.3 and already use it in the E2E tests. No behavior change to what's being verified; the call sites just shrink to a single `await OnIdleTestHelpers.AssertHandledAsync(...)`. Still green on net8.0. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Assert `OnIdle` poll result with `Assert.True` Follow-up to review feedback: the helper short-circuited with a bare `return` on success and only asserted (`Assert.Fail`) on timeout, so the happy path had no explicit assertion. Restructure the loop to poll until the handler variable is `$true` or the ~15s window elapses, then assert the outcome once with `Assert.True(handled, ...)`. Same behavior, but the success and timeout paths now share a single, self-describing assertion. Still green on net8.0. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
andyleejordan
added a commit
that referenced
this pull request
Jun 18, 2026
We had no `.github/copilot-instructions.md`, so agents working in this repo had to rediscover how to build and test, how the projects fit together, and how we label pull requests. This adds a single instructions file covering all of it: - **Build & Test** — `dotnet` directly for the fast inner loop versus `Invoke-Build` (which needs `InvokeBuild`/`platyPS`) for assembling the full module and running the complete CI suite. - **Architecture** — the project layout, key services, the LSP/DAP handler pattern, and how the server is wired up. - **Conventions** — C# style enforced by `.editorconfig`, the xUnit testing setup, and the multi-targeting story. - **Pull Request Labels** — every PR needs at least one `Area-*` label and exactly one `Issue-*` label (plus `OS-*` and `Ignore` when relevant). The `Issue-*` label is what GitHub's auto-generated release notes key off of (see `.github/release.yml`); a PR without one silently falls through to "Other Changes 🙏". The build, architecture, and conventions content previously rode along in #2298; consolidating it here keeps that PR focused on its LSP changes and gives us a single source of truth for the instructions. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Server-side support for new VS Code extension features (language model tools, a redesigned Command Explorer, and a read-only Show Help pane). The client work lives in PowerShell/vscode-powershell#5508 and depends on this PR; the two should be reviewed and merged together.
powerShell/showHelprequest — convertshowHelpfrom a notification to a request returningShowHelpResult { HelpText }, capturingGet-Help -Full | Out-Stringand trimming both ends (it pads a leading and trailing blank line).get_commandfor tools and the Command Explorer — optionalName/Modulefilters (wildcard,-ErrorAction Ignore), anExcludeParametersfast path plusModuleVersion, unconditional exclusion of editor-injected commands (the fakePSConsoleHostReadLine0.0.0 and VS Code shell-integration helpers), and opt-inExcludeDefaultFunctionsenumerated fromInitialSessionState.CreateDefault2().powerShell/getModulehandler — returns a single module's metadata for the Command Explorer's hover tooltips. Covered by E2E tests verifying metadata is returned for an existing module and a null result for a missing module.Drafted by Copilot (Claude Opus 4.8) — please review/edit before marking ready.