From b01c96710fa6c25dcc4f77cbc30c329c4a16a91d Mon Sep 17 00:00:00 2001 From: 26zl <143036376+26zl@users.noreply.github.com> Date: Sun, 11 Oct 2026 14:44:17 +0200 Subject: [PATCH 1/2] Stop profile aliases from shadowing built-in commands The profile removed the built-in gc/ls/cat aliases with Remove-Alias and redefined them, which replaced Get-Content/Get-ChildItem for the whole session, including scripts invoked from the prompt. - Rename the git-commit helper gc -> gcmsg and drop Remove-Alias gc. - Expose eza via la/ll/lt only; leave the built-in ls alias intact. - Expose bat via bcat; leave the built-in cat alias intact. - ssh: consult `ssh -G ` and add ConnectTimeout/ServerAlive* only where neither the command line nor ~/.ssh/config already set them. - Correct the misleading gpush/gpull alias comments. - Update help text, command registry, README, and tests to match. --- Microsoft.PowerShell_profile.ps1 | 84 +++++++++++++++++--------------- README.md | 6 +-- tests/ci-functional.ps1 | 6 +-- tests/test.ps1 | 4 +- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/Microsoft.PowerShell_profile.ps1 b/Microsoft.PowerShell_profile.ps1 index 3c63221..26047fa 100644 --- a/Microsoft.PowerShell_profile.ps1 +++ b/Microsoft.PowerShell_profile.ps1 @@ -2211,16 +2211,9 @@ function dtop { # Enhanced Listing (eza - modern ls replacement with icons and git status) if (Get-Command eza -ErrorAction Ignore) { - # Remove-Alias exists only in PS6+; PS5 needs Remove-Item on the Alias: drive - if (Get-Command Remove-Alias -ErrorAction Ignore) { - Remove-Alias ls -Force -ErrorAction SilentlyContinue - } - else { - Remove-Item Alias:\ls -Force -ErrorAction SilentlyContinue - } - # ls/la/ll/lt: directory listing via eza (icons, git status, tree). Pass the icon setting as + # la/ll/lt expose eza under distinct names; the built-in ls alias (Get-ChildItem) is left intact + # so scripts run later in this session keep the standard listing. Pass the icon setting as # --icons=WHEN: eza takes an optional value there, so a bare --icons swallows a following path. - function ls { eza --icons=auto @args } function la { eza -a --icons=auto @args } function ll { eza -la --icons=auto --git @args } function lt { eza --tree --icons=auto --level=2 @args } @@ -2236,14 +2229,9 @@ else { # Syntax-highlighted file viewer (bat - modern cat replacement) if (-not $env:BAT_THEME) { $env:BAT_THEME = "TwoDark" } if (Get-Command bat -ErrorAction Ignore) { - if (Get-Command Remove-Alias -ErrorAction Ignore) { - Remove-Alias cat -Force -ErrorAction SilentlyContinue - } - else { - Remove-Item Alias:\cat -Force -ErrorAction SilentlyContinue - } - # cat: syntax-highlighted output via bat (no paging) - function cat { bat --paging=never @args } + # bcat exposes bat under a distinct name; the built-in cat alias (Get-Content) is left intact so + # scripts run later in this session keep reading raw file contents. + function bcat { bat --paging=never @args } } else { if ($isInteractive) { Write-Warning "bat not found. Install it with: winget install -e --id sharkdp.bat" } @@ -2255,26 +2243,20 @@ function gs { git status } # Git add all function ga { git add .; if ($LASTEXITCODE -ne 0) { Write-Warning "git add failed (exit $LASTEXITCODE)" } } -# Remove built-in gc alias (Get-Content) so our function is reachable -if (Get-Command Remove-Alias -ErrorAction Ignore) { - Remove-Alias gc -Force -ErrorAction SilentlyContinue -} -else { - Remove-Item Alias:\gc -Force -ErrorAction SilentlyContinue -} -# Git commit with message -function gc { - if (-not $args) { Write-Error "Usage: gc [git-flags]"; return } +# Git commit with message. Named gcmsg, not gc, so the built-in gc alias (Get-Content) stays intact +# for scripts run later in this session. +function gcmsg { + if (-not $args) { Write-Error "Usage: gcmsg [git-flags]"; return } $msg = $args[0] $rest = @($args | Select-Object -Skip 1) git commit -m $msg @rest if ($LASTEXITCODE -ne 0) { Write-Warning "git commit failed (exit $LASTEXITCODE)" } } -# Remove built-in gp alias (Get-Process) so our function is reachable +# Git push (gp is a built-in alias, so this is named gpush) function gpush { git push } -# Remove built-in gl alias (Get-ChildItem) so our function is reachable +# Git pull (gl is a built-in alias, so this is named gpull) function gpull { git pull } # Jump to github directory via zoxide @@ -3756,11 +3738,7 @@ if (Get-Command ssh -ErrorAction Ignore) { function ssh { # Match both spaced and compact OpenSSH -o option forms. $argText = ($args -join ' ') - $extra = @() - if ($argText -notmatch '-o\s*ConnectTimeout') { $extra += '-o'; $extra += 'ConnectTimeout=10' } - if ($argText -notmatch '-o\s*ServerAliveInterval') { $extra += '-o'; $extra += 'ServerAliveInterval=30' } - if ($argText -notmatch '-o\s*ServerAliveCountMax') { $extra += '-o'; $extra += 'ServerAliveCountMax=3' } - # Use the first positional SSH argument as the tab title. + # Use the first positional SSH argument as the tab title and as the host for config lookup. $target = $null $skipNext = $false $flagsWithValue = @('-p', '-i', '-l', '-o', '-F', '-L', '-R', '-D', '-W', '-B', '-b', '-c', '-E', '-e', '-I', '-J', '-m', '-O', '-Q', '-S', '-w') @@ -3773,6 +3751,33 @@ if (Get-Command ssh -ErrorAction Ignore) { $target = [string]$a break } + + # Add timeout/keepalive defaults only where neither the command line nor the host's effective + # config already set them, so the user's ~/.ssh/config is never overridden. ssh -G reports an + # unset ConnectTimeout as "none" and an unset ServerAliveInterval as "0". + $effective = @{} + if ($target) { + try { + foreach ($line in (& ssh.exe -G $target 2>$null)) { + if ($line -match '^\s*(\S+)\s+(.+?)\s*$') { $effective[$matches[1].ToLowerInvariant()] = $matches[2] } + } + } + catch { $null = $_ } + } + $extra = @() + if ($argText -notmatch '-o\s*ConnectTimeout' -and + (-not $effective.ContainsKey('connecttimeout') -or $effective['connecttimeout'] -eq 'none')) { + $extra += '-o'; $extra += 'ConnectTimeout=10' + } + if ($argText -notmatch '-o\s*ServerAliveInterval' -and + (-not $effective.ContainsKey('serveraliveinterval') -or $effective['serveraliveinterval'] -eq '0')) { + $extra += '-o'; $extra += 'ServerAliveInterval=30' + } + if ($argText -notmatch '-o\s*ServerAliveCountMax' -and + (-not $effective.ContainsKey('serveralivecountmax') -or $effective['serveralivecountmax'] -eq '3')) { + $extra += '-o'; $extra += 'ServerAliveCountMax=3' + } + $oldTitle = if ($target) { Push-TabTitle "ssh $target" } else { $null } try { if ($MyInvocation.ExpectingInput) { $input | & ssh.exe @extra @args } @@ -6242,14 +6247,14 @@ ${g}Test-ProfileHealth${r} [-PassThru] / ${g}psp-doctor${r} - Diagnose install: ${g}Uninstall-Profile${r} - Remove profile, caches, and WT changes. Use -All for everything, -HardResetWindowsTerminal to reset WT to defaults, -Force to uninstall PSFzf/tools even under CI/agent env vars. ${c}Git${r} -${g}gs${r} - git status. ${g}ga${r} - git add . ${g}gc${r} - git commit -m. +${g}gs${r} - git status. ${g}ga${r} - git add . ${g}gcmsg${r} - git commit -m. ${g}gpush${r} / ${g}gpull${r} - git push / pull. ${g}gcl${r} - git clone. ${g}gcom${r} - add + commit. ${g}lazyg${r} - add + commit + push. ${g}g${r} - zoxide jump to github dir. ${c}Files & Navigation${r} -${g}ls${r} / ${g}la${r} / ${g}ll${r} / ${g}lt${r} - eza listings (icons, hidden, long+git, tree). -${g}cat${r} - Syntax-highlighted viewer (bat). +${g}la${r} / ${g}ll${r} / ${g}lt${r} - eza listings (hidden, long+git, tree). ${g}ls${r} stays Get-ChildItem. +${g}bcat${r} - Syntax-highlighted viewer (bat). ${g}cat${r} stays Get-Content. ${g}ff${r} - Find files recursively. ${g}nf${r} - Create new file. ${g}mkcd${r} - Create dir and cd into it. ${g}touch${r} - Create file or update timestamp. @@ -6426,7 +6431,7 @@ $script:_seedCommands = @( @{ Name = 'Test-Profile'; Category = 'Profile'; Synopsis = 'Profile diagnostics' } @{ Name = 'gs'; Category = 'Git'; Synopsis = 'git status' } @{ Name = 'ga'; Category = 'Git'; Synopsis = 'git add .' } - @{ Name = 'gc'; Category = 'Git'; Synopsis = 'git commit -m' } + @{ Name = 'gcmsg'; Category = 'Git'; Synopsis = 'git commit -m' } @{ Name = 'gpush'; Category = 'Git'; Synopsis = 'git push' } @{ Name = 'gpull'; Category = 'Git'; Synopsis = 'git pull' } @{ Name = 'gcl'; Category = 'Git'; Synopsis = 'git clone' } @@ -6435,11 +6440,10 @@ $script:_seedCommands = @( @{ Name = 'g'; Category = 'Git'; Synopsis = 'zoxide jump to github dir' } @{ Name = 'gcof'; Category = 'Git'; Synopsis = 'Fuzzy git branch checkout (fzf)' } @{ Name = 'gitignore'; Category = 'Git'; Synopsis = 'Generate .gitignore from gitignore.io' } - @{ Name = 'ls'; Category = 'Files'; Synopsis = 'eza listing' } @{ Name = 'la'; Category = 'Files'; Synopsis = 'eza listing with hidden' } @{ Name = 'll'; Category = 'Files'; Synopsis = 'eza long + git listing' } @{ Name = 'lt'; Category = 'Files'; Synopsis = 'eza tree listing' } - @{ Name = 'cat'; Category = 'Files'; Synopsis = 'Syntax-highlighted viewer (bat)' } + @{ Name = 'bcat'; Category = 'Files'; Synopsis = 'Syntax-highlighted viewer (bat)' } @{ Name = 'ff'; Category = 'Files'; Synopsis = 'Find files recursively' } @{ Name = 'nf'; Category = 'Files'; Synopsis = 'Create new file' } @{ Name = 'touch'; Category = 'Files'; Synopsis = 'Create file or update timestamp' } diff --git a/README.md b/README.md index 4d263ab..0868f33 100644 --- a/README.md +++ b/README.md @@ -228,7 +228,7 @@ Run `Show-Help` in your terminal for a colored version of this list. | --- | --- | | `gs` | git status | | `ga` | git add . | -| `gc ` | git commit -m | +| `gcmsg ` | git commit -m | | `gpush` / `gpull` | git push / pull | | `gcl ` | git clone | | `gcom ` | git add . + commit | @@ -239,8 +239,8 @@ Run `Show-Help` in your terminal for a colored version of this list. | Command | Description | | --- | --- | -| `ls` / `la` / `ll` / `lt` | eza listings (icons, hidden, long+git, tree) | -| `cat ` | Syntax-highlighted viewer (bat) | +| `la` / `ll` / `lt` | eza listings (hidden, long+git, tree); `ls` stays the built-in Get-ChildItem | +| `bcat ` | Syntax-highlighted viewer (bat); `cat` stays the built-in Get-Content | | `ff ` | Find files recursively | | `nf ` | Create new file | | `mkcd ` | Create directory and cd into it | diff --git a/tests/ci-functional.ps1 b/tests/ci-functional.ps1 index 26857a9..e6d7dbc 100644 --- a/tests/ci-functional.ps1 +++ b/tests/ci-functional.ps1 @@ -551,13 +551,13 @@ Invoke-TestCase -Name 'Execute full command matrix' -Code { } finally { Set-Location $before } } - Invoke-CommandProbe -Command 'gc' -Code { + Invoke-CommandProbe -Command 'gcmsg' -Code { $before = Get-Location try { Set-Location $gitRepo - gc 'ci gc commit' + gcmsg 'ci gcmsg commit' $last = (git log -1 --pretty=%s | Out-String).Trim() - if ($last -ne 'ci gc commit') { throw "gc commit mismatch: $last" } + if ($last -ne 'ci gcmsg commit') { throw "gcmsg commit mismatch: $last" } } finally { Set-Location $before } } diff --git a/tests/test.ps1 b/tests/test.ps1 index 5f5ce57..531f3dd 100644 --- a/tests/test.ps1 +++ b/tests/test.ps1 @@ -649,7 +649,7 @@ try { 'killport','http','prettyjson','hb','timer','watch','bak', 'hosts','weather','speedtest','wifipass','eventlog','path','env', 'svc','rdp','cpy','pst','Invoke-Clipboard', - 'gs','ga','gc','gpush','gpull','g','gcl','gcom','lazyg', + 'gs','ga','gcmsg','gpush','gpull','g','gcl','gcom','lazyg', 'ls','la','ll','lt','cat','docs','dtop','admin','reload', 'ep','su' ) @@ -1219,7 +1219,7 @@ T 'Reconfigure-Profile' { # ===== GIT ===== T 'gs' { gs } T 'ga' { [System.IO.File]::WriteAllText((Join-Path $gr 'new.txt'), 'x', [System.Text.UTF8Encoding]::new($false)); ga } -T 'gc' { gc "test commit" } +T 'gcmsg' { gcmsg "test commit" } T 'gcom' { [System.IO.File]::WriteAllText((Join-Path $gr 'new2.txt'), 'y', [System.Text.UTF8Encoding]::new($false)); gcom "test gcom" } T 'gpush' $null 'no remote configured' T 'gpull' $null 'no remote configured' From 7c688cce15515468422e6c5e335c79e9a176e0d8 Mon Sep 17 00:00:00 2001 From: 26zl <143036376+26zl@users.noreply.github.com> Date: Sun, 11 Oct 2026 16:11:29 +0200 Subject: [PATCH 2/2] Cover bcat in functional command matrix bcat is a new command exposed only when bat is installed. The coverage audit parses the profile statically, so it sees the bcat function regardless of the runtime bat guard and flagged it as an uncovered export, failing the functional job. Probe bcat when bat is present and skip it with a reason otherwise. --- tests/ci-functional.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/ci-functional.ps1 b/tests/ci-functional.ps1 index e6d7dbc..d173534 100644 --- a/tests/ci-functional.ps1 +++ b/tests/ci-functional.ps1 @@ -584,6 +584,13 @@ Invoke-TestCase -Name 'Execute full command matrix' -Code { Invoke-CommandProbe -Command 'll' -Code { ll $workspace | Out-Null } Invoke-CommandProbe -Command 'lt' -Code { lt $workspace | Out-Null } Invoke-CommandProbe -Command 'cat' -Code { cat $textFile | Out-Null } + # bcat is only defined when bat is installed; exercise it when present, otherwise record a skip. + if (Get-Command bat -ErrorAction Ignore) { + Invoke-CommandProbe -Command 'bcat' -Code { bcat $textFile | Out-Null } + } + else { + Invoke-CommandProbe -Command 'bcat' -SkipReason 'Requires bat (not installed in CI)' + } Invoke-CommandProbe -Command 'ff' -Code { $before = Get-Location try {