param( [switch]$DryRun ) $ErrorActionPreference = "Continue" $script:RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..")) $script:LogPath = Join-Path $script:RepoRoot ".git/graphify-hook.log" function Write-HookLog { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $line = "[$timestamp] $Message" Write-Host $line try { Add-Content -Path $script:LogPath -Value $line -Encoding UTF8 } catch { Write-Host "[graphify hook] Unable to write log: $($_.Exception.Message)" } } function Test-GraphifyPython { param([string]$PythonPath) if ([string]::IsNullOrWhiteSpace($PythonPath)) { return $false } try { & $PythonPath -c "import graphify" *> $null return ($LASTEXITCODE -eq 0) } catch { return $false } } function Get-GraphifyPython { $candidates = @() foreach ($relative in @("Unity/graphify-out/.graphify_python", "graphify-out/.graphify_python")) { $path = Join-Path $script:RepoRoot $relative if (Test-Path $path) { $value = (Get-Content -Raw -Path $path -Encoding UTF8).Trim() if ($value) { $candidates += $value } } } foreach ($command in @("python", "py")) { $cmd = Get-Command $command -ErrorAction SilentlyContinue if ($cmd) { $candidates += $cmd.Source } } foreach ($candidate in $candidates | Select-Object -Unique) { if (Test-GraphifyPython $candidate) { return $candidate } } return $null } function Get-ChangedFiles { $fromEnv = $env:GRAPHIFY_CHANGED if (-not [string]::IsNullOrWhiteSpace($fromEnv)) { return $fromEnv -split "`r?`n" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } } $git = Get-Command git -ErrorAction SilentlyContinue if (-not $git) { return @() } Push-Location $script:RepoRoot try { $files = & git diff --name-only HEAD~1 HEAD 2>$null if (-not $files) { $files = & git diff --name-only HEAD 2>$null } return @($files | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) } finally { Pop-Location } } function Invoke-GraphifyRebuild { param( [string]$Label, [string]$RelativePath, [string]$PythonPath ) $target = Join-Path $script:RepoRoot $RelativePath $graphPath = Join-Path $target "graphify-out/graph.json" if (-not (Test-Path $graphPath)) { Write-HookLog "Skipping ${Label}: no graphify-out/graph.json found." return } if ($DryRun) { Write-HookLog "Dry run: would rebuild $Label graph at $target." return } Write-HookLog "Rebuilding $Label graph at $target." Push-Location $target try { & $PythonPath -c "from pathlib import Path; from graphify.watch import _rebuild_code; _rebuild_code(Path('.'))" *> $null if ($LASTEXITCODE -eq 0) { Write-HookLog "Rebuilt $Label graph." } else { Write-HookLog "Rebuild failed for $Label with exit code $LASTEXITCODE." } } catch { Write-HookLog "Rebuild failed for ${Label}: $($_.Exception.Message)" } finally { Pop-Location } } Set-Location $script:RepoRoot $changedFiles = @(Get-ChangedFiles) if ($changedFiles.Count -eq 0) { Write-HookLog "No changed files detected; nothing to rebuild." exit 0 } $codeExtensions = @( ".cs", ".asmdef", ".shader", ".hlsl", ".cginc", ".py", ".js", ".ts", ".json", ".toml", ".yaml", ".yml" ) $changedCode = @( $changedFiles | Where-Object { $ext = [System.IO.Path]::GetExtension($_).ToLowerInvariant() $codeExtensions -contains $ext } ) if ($changedCode.Count -eq 0) { Write-HookLog "$($changedFiles.Count) changed file(s), but no code/config files for AST graph rebuild." exit 0 } $python = Get-GraphifyPython if (-not $python) { Write-HookLog "No Python interpreter with graphify installed was found." exit 0 } Write-HookLog "$($changedCode.Count) code/config file(s) changed; using Python: $python" $touchesUnity = @($changedCode | Where-Object { $_ -like "Unity/*" -or $_ -like "Unity\*" }).Count -gt 0 Invoke-GraphifyRebuild -Label "root" -RelativePath "." -PythonPath $python if ($touchesUnity) { Invoke-GraphifyRebuild -Label "Unity" -RelativePath "Unity" -PythonPath $python } else { Write-HookLog "Skipping Unity graph: no Unity path changed." }