112 lines
4.0 KiB
PowerShell
112 lines
4.0 KiB
PowerShell
# Hook dispatcher: select the PowerShell or Bash implementation from local-env.json.
|
|
param([string]$HookName)
|
|
|
|
$utf8 = New-Object System.Text.UTF8Encoding($false)
|
|
[Console]::InputEncoding = $utf8
|
|
[Console]::OutputEncoding = $utf8
|
|
|
|
function Write-EmptyHookResult {
|
|
[Console]::Out.WriteLine('{}')
|
|
}
|
|
|
|
$inputPayload = [Console]::In.ReadToEnd()
|
|
|
|
try {
|
|
if ([string]::IsNullOrWhiteSpace($HookName) -or $HookName -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$') {
|
|
throw "Invalid hook name."
|
|
}
|
|
|
|
$cursorDir = Split-Path -Parent $PSScriptRoot
|
|
$repoRoot = Split-Path -Parent $cursorDir
|
|
$localEnvPath = Join-Path $cursorDir 'local-env.json'
|
|
$shell = 'powershell'
|
|
|
|
if (Test-Path -LiteralPath $localEnvPath -PathType Leaf) {
|
|
try {
|
|
$config = Get-Content -LiteralPath $localEnvPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
if ($config.shell -is [string] -and -not [string]::IsNullOrWhiteSpace($config.shell)) {
|
|
$shell = $config.shell.Trim().ToLowerInvariant()
|
|
}
|
|
} catch {
|
|
[Console]::Error.WriteLine("[run-hook] Ignoring invalid local-env.json: {0}", $_.Exception.Message)
|
|
}
|
|
}
|
|
|
|
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
$processInfo.UseShellExecute = $false
|
|
$processInfo.CreateNoWindow = $true
|
|
$processInfo.RedirectStandardInput = $true
|
|
$processInfo.RedirectStandardOutput = $true
|
|
$processInfo.RedirectStandardError = $true
|
|
$processInfo.WorkingDirectory = $repoRoot
|
|
|
|
if ($processInfo.PSObject.Properties.Name -contains 'StandardInputEncoding') {
|
|
$processInfo.StandardInputEncoding = $utf8
|
|
$processInfo.StandardOutputEncoding = $utf8
|
|
$processInfo.StandardErrorEncoding = $utf8
|
|
}
|
|
|
|
switch ($shell) {
|
|
{ $_ -in @('powershell', 'powershell.exe', 'pwsh', 'pwsh.exe') } {
|
|
$scriptPath = Join-Path $PSScriptRoot "$HookName.ps1"
|
|
if (-not (Test-Path -LiteralPath $scriptPath -PathType Leaf)) {
|
|
throw "PowerShell hook not found: $HookName"
|
|
}
|
|
$processInfo.FileName = if ($shell -in @('pwsh', 'pwsh.exe')) { 'pwsh' } else { 'powershell' }
|
|
$processInfo.Arguments = "-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$scriptPath`""
|
|
break
|
|
}
|
|
{ $_ -in @('bash', 'bash.exe', 'zsh', 'sh') } {
|
|
$scriptPath = (Join-Path $PSScriptRoot "$HookName.sh") -replace '\\', '/'
|
|
if (-not (Test-Path -LiteralPath $scriptPath -PathType Leaf)) {
|
|
throw "Shell hook not found: $HookName"
|
|
}
|
|
$processInfo.FileName = 'bash'
|
|
$processInfo.Arguments = "`"$scriptPath`""
|
|
break
|
|
}
|
|
default {
|
|
throw "Unsupported shell '$shell'."
|
|
}
|
|
}
|
|
|
|
$process = New-Object System.Diagnostics.Process
|
|
$process.StartInfo = $processInfo
|
|
if (-not $process.Start()) {
|
|
throw "Unable to start hook process."
|
|
}
|
|
|
|
$stdoutTask = $process.StandardOutput.ReadToEndAsync()
|
|
$stderrTask = $process.StandardError.ReadToEndAsync()
|
|
$process.StandardInput.Write($inputPayload)
|
|
$process.StandardInput.Close()
|
|
$process.WaitForExit()
|
|
|
|
$stdout = $stdoutTask.Result
|
|
$stderr = $stderrTask.Result
|
|
if (-not [string]::IsNullOrWhiteSpace($stderr)) {
|
|
[Console]::Error.WriteLine($stderr.TrimEnd())
|
|
}
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Hook exited with code $($process.ExitCode)."
|
|
}
|
|
|
|
$trimmed = $stdout.Trim()
|
|
if ([string]::IsNullOrWhiteSpace($trimmed) -or -not $trimmed.StartsWith('{')) {
|
|
throw "Hook returned an empty or non-object response."
|
|
}
|
|
|
|
$result = $trimmed | ConvertFrom-Json
|
|
$normalized = $result | ConvertTo-Json -Compress -Depth 20
|
|
if ([string]::IsNullOrWhiteSpace($normalized) -or -not $normalized.StartsWith('{')) {
|
|
throw "Hook response is not a JSON object."
|
|
}
|
|
|
|
[Console]::Out.WriteLine($normalized)
|
|
} catch {
|
|
[Console]::Error.WriteLine("[run-hook] {0}", $_.Exception.Message)
|
|
Write-EmptyHookResult
|
|
}
|
|
|
|
exit 0
|