Private/Get-GraphPermissionLiteIndex.ps1

function Get-GraphPermissionLiteIndex {
    <#
    .SYNOPSIS
        Loads and caches the self-contained permission -> records lite index.
    .DESCRIPTION
        data/graph-command-permissions-lite.json denormalizes the permission reverse index so
        each permission name maps directly to its matching records (not just ids). This lets
        Get-GraphMapping -Permission work without ever loading the full catalog's id lookup
        table (Get-GraphCatalogIndex).
    #>

    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [switch]$Force
    )

    if (-not $Force -and $script:GraphPermissionLiteCache) {
        return $script:GraphPermissionLiteCache
    }

    $paths = Get-GraphCatalogPath
    if (-not $paths.PermissionsLitePath) {
        throw "GraphShell could not locate graph-command-permissions-lite.json. Run scripts/build-graphshell-lite-indexes.ps1 or set `$env:GRAPHSHELL_CATALOG_PATH."
    }
    Write-Verbose "Loading GraphShell permission lite index from $($paths.PermissionsLitePath)"

    $raw = Get-Content -LiteralPath $paths.PermissionsLitePath -Raw
    $parsed = $raw | ConvertFrom-Json

    $byName = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase)
    foreach ($property in $parsed.permissions.PSObject.Properties) {
        $byName[$property.Name] = $property.Value
    }

    $script:GraphPermissionLiteCache = [pscustomobject]@{
        Source = $parsed.source
        ByName = $byName
        Names  = [string[]]$byName.Keys
    }

    return $script:GraphPermissionLiteCache
}