examples/contracts/Git.Status.ps1

#requires -Version 7.6
#requires -PSEdition Core
param([Parameter(Mandatory)][hashtable]$Invocation)
# Source: https://git-scm.com/docs/git-status, porcelain v2 and NUL framing.
# Scope: git status [-- pathspec...]. One observed local worktree, no fetch.
$native=@($Invocation.ArgumentList)
if(!$native.Count -or $native[0] -cne 'status'){
    return New-QuietResult -Outcome Unsupported -Execution @{ExitCode=$null} -ErrorInfo @{Code='ArgumentsUnsupported'}
}
$paths=@()
if($native.Count -gt 1){
    if($native[1] -cne '--'){return New-QuietResult -Outcome Unsupported -Summary 'Supported: git status [-- pathspec...].' -Execution @{ExitCode=$null} -ErrorInfo @{Code='ArgumentsUnsupported'}}
    if($native.Count -gt 2){$paths=@($native[2..($native.Count-1)])}
}
$state=@{Branch=$null;HeadOid=$null;Unborn=$false;Detached=$false;Upstream=$null;Ahead=$null;Behind=$null;Pending=$null
    Entries=[Collections.Generic.List[object]]::new();Counts=@{Changed=0L;Staged=0L;Unstaged=0L;Untracked=0L;Conflicted=0L;Renamed=0L}
    Scope=@{WorkingDirectory=$Invocation.WorkingDirectory;Pathspec=@($paths);UntrackedFiles='all';IgnoreSubmodules='none';RemoteState='local refs only'}}
$parse={
    param($record,$state)
    if($record.Truncated){throw 'A status record was truncated.'}
    if($record.Stream -ne 'stdout'){return}
    $text=$record.Text
    if($state.Pending){
        if(!$text.Length){throw 'Missing rename source path.'}
        $state.Pending.OriginalPath=$text;$state.Pending=$null;return
    }
    if($text.StartsWith('# ')){
        if($text -match '^# branch\.(\S+) (.*)$'){
            $kind=$Matches[1];$value=$Matches[2]
            switch($kind){
                head{$state.Detached=$value -eq '(detached)';$state.Branch=if($state.Detached){$null}else{$value}}
                oid{$state.Unborn=$value -eq '(initial)';$state.HeadOid=if($state.Unborn){$null}else{$value}}
                upstream{$state.Upstream=$value}
                ab{if($value -notmatch '^\+(\d+) -(\d+)$'){throw 'Invalid branch divergence.'};$state.Ahead=[long]$Matches[1];$state.Behind=[long]$Matches[2]}
            }
        }
        return # Porcelain v2 explicitly permits unknown extension headers.
    }
    $entry=$null
    if($text.StartsWith('? ')){
        $entry=[ordered]@{Kind='Untracked';Status='??';Path=$text.Substring(2);OriginalPath=$null;Submodule=$null}
        $state.Counts.Untracked++;$state.Counts.Changed++
    }elseif($text.StartsWith('1 ') -or $text.StartsWith('2 ') -or $text.StartsWith('u ')){
        $kind=$text[0];$fields=if($kind -eq '1'){9}elseif($kind -eq '2'){10}else{11}
        $parts=$text.Split([char[]]' ',$fields)
        if($parts.Count -ne $fields -or $parts[1] -notmatch '^[.MADRCUT]{2}$' -or !$parts[-1].Length){throw 'Malformed porcelain v2 entry.'}
        $entry=[ordered]@{Kind=$(if($kind -eq 'u'){'Conflicted'}elseif($kind -eq '2'){'RenamedOrCopied'}else{'Tracked'})
            Status=$parts[1];Path=$parts[-1];OriginalPath=$null;Submodule=$parts[2]}
        $state.Counts.Changed++
        if($kind -eq 'u'){$state.Counts.Conflicted++}
        else{
            if($parts[1][0] -ne '.'){$state.Counts.Staged++}
            if($parts[1][1] -ne '.'){$state.Counts.Unstaged++}
        }
        if($kind -eq '2'){$state.Pending=$entry;if($parts[8].StartsWith('R')){$state.Counts.Renamed++}}
    }elseif($text.StartsWith('! ')){return}
    else{throw 'Unknown porcelain v2 record type.'}
    if(!$entry.Path.Length){throw 'Missing status path.'}
    $entry=[pscustomobject]$entry;if($state.Pending){$state.Pending=$entry};$state.Entries.Add($entry)
}
$complete={
    param($state,$capture)
    if($state.Pending){throw 'Incomplete rename record.'}
    [pscustomobject]@{Branch=$state.Branch;HeadOid=$state.HeadOid;Unborn=$state.Unborn;Detached=$state.Detached
        Upstream=$state.Upstream;Ahead=$state.Ahead;Behind=$state.Behind;Clean=($state.Counts.Changed -eq 0)
        Counts=[pscustomobject]$state.Counts;Entries=$state.Entries.ToArray();Scope=[pscustomobject]$state.Scope
        AnswerComplete=[bool]($capture.SourceComplete -and !$capture.Lossy)}
}
$projection={param($data,$settings) Limit-QuietProjection -Data $data -Property Entries -MaxItems $settings.MaxItems}
$arguments=@('--no-optional-locks','status','--porcelain=v2','-z','--branch','--untracked-files=all','--ignore-submodules=none')
if($paths.Count){$arguments+=@('--')+$paths}
# Version discovery belongs to this AI-authored Git contract, never to the engine.
$execute={
    param($call)
    $version=Invoke-QuietCli -FilePath $call.FilePath -ArgumentList @('--version') -WorkingDirectory $call.WorkingDirectory -Parse {
        param($capture)
        if($capture.Stdout -notmatch '^git version (\S+)'){throw 'Unexpected Git version response.'}
        $Matches[1]
    }
    if($version.Outcome -ne 'Success'){return}
    foreach($source in $version.Internal.Sources.Values){$source.ObservedVersion=$version.Data}
    $status=Invoke-QuietCli -FilePath $call.FilePath -ArgumentList $arguments -WorkingDirectory $call.WorkingDirectory -State $state -OnOutput $parse -Complete $complete -RecordDelimiter ([char]0) -ObservedVersion $version.Data
    if($status.Outcome -ne 'Success'){return}
    $status.Data|Add-Member -NotePropertyName GitVersion -NotePropertyValue $version.Data -Force
    $status.Data
}.GetNewClosure()
New-QuietContract -Id git.status -Execute $execute -Projection $projection -Summary 'Local Git worktree status.' -Documentation @('https://git-scm.com/docs/git-status','https://git-scm.com/docs/git#Documentation/git.txt---version') -SourcePath @($PSCommandPath) -SupportedForms @('git status','git status -- <pathspec>...')