@@ -37,7 +37,20 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
3737 # legacy per-prompt stream spawn.
3838 $script :ServeSupported = -not $script :ConstrainedLanguageMode -and $PSVersionTable.PSVersion.Major -ge 6
3939
40- # Prompt related backup.
40+ # Async mode: state is threaded through $global:_ompAsyncInit (set by the
41+ # trampoline installed in the profile) and consumed once here, then
42+ # cleared so a later *sync* re-source of this same file takes the sync
43+ # branch below. Read via Get-Variable, not a bare $global: dereference -
44+ # a plain sync source never sets this global, and a bare read of an
45+ # unset variable throws under Set-StrictMode.
46+ $script :AsyncInit = [bool ](Get-Variable - Name _ompAsyncInit - Scope Global - ErrorAction Ignore - ValueOnly)
47+ $global :_ompAsyncInit = $false
48+
49+ # Prompt related backup. In async mode this ends up capturing whatever
50+ # wraps the trampoline at first-draw time (e.g. another tool's prompt
51+ # hook), not the true pre-omp prompt - $global:_ompOriginalPromptFunction
52+ # (captured by the trampoline itself, before anything can wrap it) is
53+ # authoritative there instead. Kept here unconditionally for the sync path.
4154 $script :OriginalPromptFunction = $Function: prompt
4255 $originalPSReadLineOptions = Get-PSReadLineOption
4356 $script :OriginalContinuationPrompt = $originalPSReadLineOptions.ContinuationPrompt
@@ -986,7 +999,22 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
986999 $global :LASTEXITCODE = $script :OriginalLastExitCode
9871000 }
9881001
989- $Function: prompt = $promptFunction
1002+ if ($script :AsyncInit ) {
1003+ # Never touch the global prompt binding after the trampoline installed
1004+ # it - anything wrapping it (e.g. another tool's prompt hook) must
1005+ # keep a valid reference forever. Export-ModuleMember below becomes a
1006+ # silent no-op with no function named "prompt" in this module, which
1007+ # is intentional. $global:_ompInitialized is deliberately separate
1008+ # from $global:_ompPromptFunction: it only ever means "don't
1009+ # re-import", so OnRemove can restore a falsy original prompt without
1010+ # the trampoline mistaking that for "never initialized" and silently
1011+ # reinstalling this module on the next draw.
1012+ $global :_ompPromptFunction = $promptFunction
1013+ $global :_ompInitialized = $true
1014+ }
1015+ else {
1016+ $Function: prompt = $promptFunction
1017+ }
9901018
9911019 # set secondary prompt
9921020 Set-PSReadLineOption - ContinuationPrompt ((Invoke-Utf8Posh @ (" print" , " secondary" , " --shell=$script :ShellName " )) -join " `n " )
@@ -1328,7 +1356,29 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
13281356
13291357 Remove-Item Function:Get-PoshStackCount - ErrorAction SilentlyContinue
13301358
1331- $Function: prompt = $script :OriginalPromptFunction
1359+ if ($script :AsyncInit ) {
1360+ # Restore from the trampoline's own capture, never from
1361+ # $script:OriginalPromptFunction - in async mode that backup
1362+ # holds the wrapper chain (e.g. another tool's prompt hook),
1363+ # and restoring it here would recurse infinitely. Keep
1364+ # $global:_ompInitialized true even when the captured
1365+ # original is falsy, so the trampoline treats this as
1366+ # "restored", not "never initialized" - otherwise the next
1367+ # draw would silently reinstall the module Remove-Module just
1368+ # removed.
1369+ $global :_ompPromptFunction = $global :_ompOriginalPromptFunction
1370+ $global :_ompInitialized = $true
1371+ }
1372+ else {
1373+ # Only restore if this module's own prompt function is still
1374+ # the live global binding. If something replaced it since
1375+ # (e.g. a fresh async trampoline installed while switching
1376+ # this session from sync to async), leave it alone instead of
1377+ # clobbering whatever now owns the prompt.
1378+ if ($Function: prompt -eq $promptFunction ) {
1379+ $Function: prompt = $script :OriginalPromptFunction
1380+ }
1381+ }
13321382
13331383 (Get-PSReadLineOption ).ContinuationPrompt = $script :OriginalContinuationPrompt
13341384 (Get-PSReadLineOption ).PromptText = $script :OriginalPromptText
0 commit comments