private/Test-WtwEditorCli.ps1
|
function Test-WtwEditorCli { <# .SYNOPSIS Return $true if a CLI command resolves to a runnable binary. .DESCRIPTION We deliberately do NOT invoke `--version`: on a dangling symlink, pwsh's `& path` outside a pipeline silently succeeds with $LASTEXITCODE=0, and inside a pipeline it raises "Cannot run a document in the middle of a pipeline". Filesystem check instead: if Get-Command resolves to a symlink, follow the chain via FileInfo.ResolveLinkTarget($true) and verify the final target exists. Plain files just need Get-Item to return a FileInfo. Catches the `~/.antigravity/antigravity/bin/antigravity` stub the Antigravity v1 installer leaves behind when v2 ships its CLI as `antigravity-ide` at /Applications/Antigravity IDE.app/. #> param([string]$Cmd) # Functions and aliases are not editor CLIs. Trusting them lets a shell # `function cursor { wtw cursor; }` (or a Pester stub) recurse until # "Stack overflow." Only an Application / ExternalScript on PATH counts. $found = @(Get-Command $Cmd -CommandType Application, ExternalScript -All -ErrorAction SilentlyContinue) foreach ($candidate in $found) { if (Test-WtwEditorCliCandidate $candidate) { return $true } } return $false } function Test-WtwCursorAgentShim { <# .SYNOPSIS The ~/.local/bin/cursor stub from `cursor agent` re-execs another cursor. #> param([string] $Path) if (-not $Path) { return $false } $normalized = $Path.Replace('\', '/').TrimEnd('/') if ($normalized -eq "$($HOME.Replace('\', '/'))/.local/bin/cursor") { return $true } if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return $false } try { $head = Get-Content -LiteralPath $Path -TotalCount 20 -ErrorAction Stop return [bool]($head -match 'excluding the current shim') } catch { return $false } } function Test-WtwEditorCliCandidate { param($found) if (-not $found) { return $false } $resolved = $found.Source if (-not $resolved) { return $false } if (Test-WtwCursorAgentShim $resolved) { return $false } $item = Get-Item -LiteralPath $resolved -ErrorAction SilentlyContinue if (-not $item) { return $false } # Non-symlink: a FileInfo means it exists as a regular file. if (-not $item.LinkType) { return ($item -is [System.IO.FileInfo]) } # Symlink: walk the full chain and verify the final target exists. # Dangling links return a FileSystemInfo with Exists=$false. try { $target = [System.IO.FileInfo]::new($resolved).ResolveLinkTarget($true) return ($null -ne $target -and $target.Exists) } catch { return $false } } |