Search code examples
windowspowershellgithubcommand-line-interfacealias

Creating aliases for Github Copilot CLI (ghcs, ghce not recognised)


I'm having an issue setting up aliases for github copilot. gh copilot suggest and gh copilot explain work fine, I want to reduce them to ghcs and ghce.

When I run ghcs "create new dir" this is the error I get,

ghcs : The term 'ghcs' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ ghcs "new dir"
+ ~~~~
    + CategoryInfo          : ObjectNotFound: (ghcs:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

CONTEXT I use VSC with Powershell on Windows, also just downloaded the Microsoft's Powershell extension, but it didn't help.

On github's manual page, they say it should be as simple as running this in the terminal gh copilot alias.

This created two files in my powershell folder: New Files in the folder

PS. I've also tried to create a new powershell profile by New-Item -Force $PROFILE and copied this (this is what GH also suggested in their manual) $GH_COPILOT_PROFILE = Join-Path -Path $(Split-Path -Path $PROFILE -Parent) -ChildPath "gh-copilot.ps1" gh copilot alias -- pwsh | Out-File ( New-Item -Path $GH_COPILOT_PROFILE -Force ) echo ". $GH_COPILOT_PROFILE" >> $PROFILE, but still had no luck.

Thanks in advance! :)


Solution

  • tl;dr

    • Run the alias-installation commands detailed in the instructions once, in order to programmatically update your PowerShell $PROFILE file - do NOT add those instructions themselves to the latter.

    • As of this writing, the generated "aliases" (which are actually wrapper functions) work in PowerShell (Core) 7+ only. See below for a Windows PowerShell solution.


    Current problems:

    As of this writing, there are two problems with the Copilot extension for gh, the GitHub CLI:

    • gh copilot alias -- pwsh produces PowerShell code that works in PowerShell (Core) 7+ only; your symptom implies that you ran it from Windows PowerShell.

      • However, the code could easily be fixed to run in Windows PowerShell - see below.

      • See GitHub issue #32189.

    • The instructions for setting up aliases are confusing:

      • The code shown is setup code, meant to be run once in order to programmatically add the "aliases" (which are actually functions) to the profile / initialization files of supported shells, whereas the instructions, e.g. "Add the following to your PowerShell profile:", mistakenly suggest that the setup code itself should be added to the profile / initialization file.

      • See GitHub issue #32187.


    Installing Windows PowerShell-compatible aliases (functions):

    Hopefully, the need for the following workarounds will go away, once the Copilot extension is updated to be compatible with Windows PowerShell too - once that has happened, simply run the original setup code from the instructions again.

    • If you're happy with the functions being nothing more than short names for the underlying gh copilot commands, you can update your $PROFILE as follows:
    $GH_COPILOT_PROFILE = Join-Path (Split-Path $PROFILE) gh-copilot.ps1
    @'
    function ghce { gh copilot explain @args }
    function ghcs { gh copilot suggest @args }
    '@ >> (New-Item -FORCE $GH_COPILOT_PROFILE)
    ". $GH_COPILOT_PROFILE" >> $PROFILE
    
    • If you want to use a Windows PowerShell-compatible version of the more sophisticated wrapper functions that gh copilot alias -- pwsh generates, based on the version current as of this writing:
    $GH_COPILOT_PROFILE = Join-Path (Split-Path $PROFILE) gh-copilot.ps1
    @'
    function ghcs {
        # Debug support provided by common PowerShell function parameters, which is natively aliased as -d or -db
        # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_commonparameters?view=powershell-7.4#-debug
        param(
            [ValidateSet('gh', 'git', 'shell')]
            [Alias('t')]
            [String]$Target = 'shell',
    
            [Parameter(Position = 0, ValueFromRemainingArguments)]
            [string]$Prompt
        )
        # Create temporary file to store potential command user wants to execute when exiting
        $executeCommandFile = New-TemporaryFile
    
        # Store original value of GH_DEBUG environment variable
        $envGhDebug = $Env:GH_DEBUG
    
        if ($PSBoundParameters['Debug']) {
            $Env:GH_DEBUG = 'api'
        }
    
        try {
            gh copilot suggest -t $Target -s "$executeCommandFile" $Prompt
    
            # Execute command contained within temporary file if it is not empty
            if ($executeCommandFile.Length -gt 0) {
                # Extract command to execute from temporary file
                $executeCommand = (Get-Content -Path $executeCommandFile -Raw).Trim()
    
                # Insert command into PowerShell up/down arrow key history
                [Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($executeCommand)
    
                # Insert command into PowerShell history
                $now = Get-Date
                $executeCommandHistoryItem = [PSCustomObject]@{
                    CommandLine        = $executeCommand
                    ExecutionStatus    = [Management.Automation.Runspaces.PipelineState]::NotStarted
                    StartExecutionTime = $now
                    EndExecutionTime   = $now.AddSeconds(1)
                }
                Add-History -InputObject $executeCommandHistoryItem
    
                # Execute command
                Write-Host "`n"
                Invoke-Expression $executeCommand
          
            }
        }
        finally {
            # Clean up temporary file used to store potential command user wants to execute when exiting
            Remove-Item -Path $executeCommandFile
            # Restore GH_DEBUG environment variable to its original value
            $Env:GH_DEBUG = $envGhDebug
        }
    }
    
    function ghce {
        # Debug support provided by common PowerShell function parameters, which is natively aliased as -d or -db
        # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_commonparameters?view=powershell-7.4#-debug
        param(
            [Parameter(Position = 0, ValueFromRemainingArguments)]
            [string[]]$Prompt
        )
        # Store original value of GH_DEBUG environment variable
        $envGhDebug = $Env:GH_DEBUG
        if ($PSBoundParameters['Debug']) {
            $Env:GH_DEBUG = 'api'
        }
    
        try {
            gh copilot explain $Prompt
        }
        finally {
            # Restore GH_DEBUG environment variable to its original value
            $Env:GH_DEBUG = $envGhDebug
        }
    
    }
    '@ >> (New-Item -Force $GH_COPILOT_PROFILE)
    ". $GH_COPILOT_PROFILE" >> $PROFILE
    

    The wrapper functions add support for debugging and, for ghcs, the ability to execute a suggested command and add it to PowerShell's command history.


    General notes on profile loading:
    • Note that installing Visual Studio Code's PowerShell extension, which comes with its own special-purpose shell - the PIC (PowerShell Integrated Console) - changes the file path that the automatic $PROFILE variable points to, because the PIC uses a separate profile file.

      • Additionally, it is possible to disable profile loading in the PIC, so be sure that it is enabled: Open the Settings view (Ctrl+,) and navigate to PowerShell: Enable Profile Loading; searching for profile load should be enough to locate it.
    • Therefore, installing the aliases from the PIC will not make them available in regular PowerShell console / Windows Terminal sessions, and also not in regular (non-PIC) PowerShell sessions in Visual Studio Code's integrated terminal.

      • To make all these environments share definitions, you have two options:

        • Either: Target $PROFILE.CurrentUserAllHosts rather than just $PROFILE; the path that the former points is loaded by all PowerShell environments run by the current user, irrespective of what application hosts them.

        • Or: Modify $PROFILE from a regular (non-PIC) session, then add the following to the PIC-specific $PROFILE file (open it for editing with psedit $PROFILE), which simply loads the the .CurrentUserCurrentHost profile that console-based (terminal-based) PowerShell sessions use:

          . ($PROFILE -replace '\.VSCode_', '.PowerShell_')
          
    • After modifying a profile, you must either start a new PowerShell session or explicitly reload it, e.g. with . $PROFILE, using ., the dot-sourcing operator.