Repository navigation
Add ConptyReparentPseudoConsole support - #995
Merged
Anthony Kim (anthonykim1) merged 12 commits intoOct 22, 2026
Merged
Conversation
Add a conptyParentWindow fork option and IPty.setParentWindow(), backed by ConptyReparentPseudoConsole from conpty.dll. The host window becomes the owner of the console window returned by GetConsoleWindow(), so windows that console apps parent to it (for example the WAM sign-in picker) open above the host instead of behind it.
Anthony Kim (anthonykim1)
left a comment
Contributor
Author
There was a problem hiding this comment.
Findings are inline: one p1 on the native guard, the rest p2.
PtyReparentrelies on JS-side bookkeeping (_isKilled) to avoid writing through a freedPseudoConsole*; the native entry should be safe on its own.- The new export swallows every failure (
HRESULT, missing export, lossy BigInt), so callers can't tell whether the owner was applied. - The #921 race extension never reaches
PtyReparent. IPty.setParentWindowas a required member breaksIPtyimplementers in a 1.x minor, and the@paramexample doesn't match the signature.conptyParentWindowis applied from theWindowsTerminalconstructor after the agent already started the pty; a throw there leaks the agent.
- Null the HPCON in PtyKill and skip resize/clear/reparent once it is closed, instead of relying on JS-side bookkeeping. - Return whether ConptyReparentPseudoConsole succeeded, and reject BigInt handles that don't fit in 64 bits. - Apply conptyParentWindow inside WindowsPtyAgent, right after the pseudoconsole is created, and clean up if that throws. - Re-enable the parent window when the shell exits if a modal dialog that died with it left the window disabled. - Make IPty.setParentWindow optional in the public typings and show how to convert Electron's native window handle.
Contributor
Author
|
Pushed 909b13e for the review. All six threads are addressed and resolved. It also included a fix from the VS Code review (microsoft/vscode#342784 (comment)) that re-enabled the parent window when a modal dialog died with the shell. That has since moved out of this PR to #996. Verified on Windows 11:
|
Contributor
Author
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 20, 2026 17:44
Member
|
/cc Leonard Hecker (@lhecker) as well |
Anthony Kim (anthonykim1)
marked this pull request as draft
October 20, 2026 17:45
conpty.dll is no longer experimental, so the APIs added on top of it are documented as regular APIs.
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 20, 2026 18:06
Anthony Kim (anthonykim1)
marked this pull request as draft
October 20, 2026 18:08
- Add conptyReenableParentWindowOnExit (defaults to false). Re-enabling the window on exit is a heuristic, so hosts have to opt in. - Look for visible owned windows through the whole owner chain, and compare window handles by their low 32 bits. - Run the recovery off the exit thread, since EnableWindow waits for the window's thread. - Validate handles before creating the pseudoconsole: numbers must be safe integers, and bigints must fit in 64 bits. - Only close the pseudoconsole once in kill(). - setParentWindow returns whether the request was sent; ConPTY applies it asynchronously. - The parent window tests wait for every pty to exit, since exiting while a conout worker still flushes its pipe can hang mocha.
Contributor
Author
|
Pushed f164f25 after another pass over the review, then 95ed9a4 to keep this PR to one new API, cd33f21 for the handle review, and f699175 to take the handle as a
Verified locally at f699175:
(generated by copilot) |
It's an exact check: the window is still disabled and no visible window is owned by it. What it can't tell is why the window is disabled, which is why hosts opt in.
Remove conptyParentWindow. setParentWindow() isn't deferred, and the shell is only launched once the conout worker is ready, so calling it right after spawn() sends the request before the shell starts. Remove conptyReenableParentWindowOnExit and re-enabling the parent window on exit. That moves to a follow-up issue, so this PR stays focused on the parenting change.
Anthony Kim (anthonykim1)
added a commit
to microsoft/vscode
that referenced
this pull request
Oct 20, 2026
microsoft/node-pty#995 no longer has conptyParentWindow or conptyReenableParentWindowOnExit, so TerminalProcess calls setParentWindow right after spawn, which is before node-pty launches the shell, and no longer opts in to the re-enable.
This was referenced Oct 20, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This reverts commit 271faf3.
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 21, 2026 21:22
Anthony Kim (anthonykim1)
marked this pull request as draft
October 21, 2026 21:49
HWNDs are pointers, so negative handles are now rejected and the handle is converted to an HWND through uintptr_t in C++, which also covers 32-bit builds. Numbers must be non-negative safe integers, since Node-API's integer getters silently truncate fractions, map NaN and Infinity to 0 and lose precision above 2^53. Remove the JS check, so the native binding is the only place that validates the handle.
Only Int64Value() loses precision past Number.MAX_SAFE_INTEGER; the 32-bit getters wrap instead. The invalid handle test also rejects unsafe integers, so say safe integers in its name.
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 22, 2026 01:58
Anthony Kim (anthonykim1)
marked this pull request as draft
October 22, 2026 01:59
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 22, 2026 04:23
roblourens
previously approved these changes
Oct 22, 2026
Robo (deepak1556)
self-requested a review
October 22, 2026 06:28
Robo (deepak1556)
requested changes
Oct 22, 2026
Anthony Kim (anthonykim1)
marked this pull request as draft
October 22, 2026 14:30
setParentWindow() now takes the HWND as a Buffer the size of an HWND, in native byte order, which is how Electron's BrowserWindow.getNativeWindowHandle() returns it, so hosts can pass that Buffer directly. The native side copies it into an HWND, which replaces the number and bigint parsing.
Anthony Kim (anthonykim1)
marked this pull request as ready for review
October 22, 2026 15:18
Robo (deepak1556)
approved these changes
Oct 22, 2026
Anthony Kim (anthonykim1)
deleted the
anthonykim1/conpty-parent-window
branch
October 22, 2026 15:26
Anthony Kim (anthonykim1)
added a commit
to microsoft/vscode
that referenced
this pull request
Oct 23, 2026
Adds IPty.setParentWindow() from microsoft/node-pty#995, which this PR uses.
Anthony Kim (anthonykim1)
added a commit
to microsoft/vscode
that referenced
this pull request
Oct 23, 2026
* Parent the ConPTY console window to the VS Code window Pass the native handle of the window hosting each terminal down to the pty host and node-pty, which calls ConptyReparentPseudoConsole. Windows that console apps parent to GetConsoleWindow(), such as the WAM sign-in picker used by Connect-AzAccount, then open above VS Code instead of behind it. * Address review: wait for the handle in createProcess, add an off switch - Start the window handle lookup without awaiting it in TerminalInstance; createProcess now waits for the handle of the latest window before start(), so a move during startup can't let the shell start unowned. - Drop the second per-window cache; NativeHostService already memoizes the lookup. - Sign-extend the low 32 bits of the HWND, like Windows does for handles. - Add terminal.integrated.windowsReparentConsoleWindow (experimental, ExP-controllable) as an off switch that keeps conpty.dll. - Trace-log node-pty's setParentWindow and whether it applied. - Drop the agent host TestPty stub now that IPty.setParentWindow is optional. * Don't tag windowsReparentConsoleWindow as experimental The setting stays ExP-controllable through `experiment`, but it is not an experimental setting. * Opt in to re-enabling the window when a terminal's dialog dies node-pty only re-enables the parent window on exit when asked to (conptyReenableParentWindowOnExit). VS Code only disables its windows while showing a window they own, so it opts in. Also log setParentWindow's result as "sent", since ConPTY applies the new owner asynchronously. * Send the parent window right after spawn microsoft/node-pty#995 no longer has conptyParentWindow or conptyReenableParentWindowOnExit, so TerminalProcess calls setParentWindow right after spawn, which is before node-pty launches the shell, and no longer opts in to the re-enable. * Pass the parent window to node-pty as an unsigned handle node-pty now rejects negative window handles, since HWNDs are pointers. Sign-extend the signed 32-bit handle to an unsigned 64-bit value, the same bits node-pty used before, and never let setting the parent window fail the terminal launch. * Pass the window handle bytes through to node-pty node-pty now takes the HWND as the Buffer that Electron's getNativeWindowHandle() returns, so send the VSBuffer from IHostService.getNativeWindowHandle to the pty host unchanged instead of converting it to a number and back. * chore: bump node-pty@1.2.0-beta.17 Adds IPty.setParentWindow() from microsoft/node-pty#995, which this PR uses. * chore: bump node-pty@1.2.0-beta.18 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- 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.
IPty.setParentWindow(handle), backed byConptyReparentPseudoConsolefrom the bundledconpty.dll. The window becomes the owner of the console window, so dialogs that console apps parent to the console window or its owner, like theConnect-AzAccountsign-in picker, open in front of the host instead of behind it.spawn(), the request is sent before the shell launches, becauseconnect()waits for the conout worker. Hosts call it again when the terminal moves to another window.useConptyDll, since in-box ConPTY has no reparent API.Bufferthe size of anHWND, the way Electron'sBrowserWindow.getNativeWindowHandle()returns it, so hosts can pass thatBufferdirectly. Throw for anything else.PtyKillso it's only closed once, and skip resize, clear, and reparent after that, since the baton outlives the pseudoconsole until the exit thread erases it.spawn()and while the shell runs, the no-op once the pseudoconsole is closed, and invalid handles. Extend the Windows ConPTY backend data race in ptyHandles can crash in remove_pty_baton #921 race test to callsetParentWindow.setParentWindowoptional in the public typings, so existingIPtyimplementations keep compiling. VS Code adopts this in Parent the ConPTY console window to the VS Code window vscode#342784.Inspirations from:
PtyReparent's argument checks,g_ptyHandlesMutexlookup, andconpty.dllGetProcAddresscall are copied semantically fromPtyClear, with the signature from the bundledconpty.h.TryGetWindowHandleis copied from deepak1556's review suggestion, and takes the handle in the formatwin.getNativeWindowHandle()returns.ConptyConnection::StartandConptyConnection::ReparentWindow.PtyKillfreeing the pseudoconsole while the baton lives until the exit thread erases it.Regression for #921test.