import type { PwshNativeConfig } from "./config.ts"; export const UTF8_PREFIX = [ "$__pi_utf8 = [System.Text.UTF8Encoding]::new($false)", "[Console]::InputEncoding = $__pi_utf8", "[Console]::OutputEncoding = $__pi_utf8", "$OutputEncoding = $__pi_utf8", "$PSStyle.OutputRendering = 'PlainText'", "$global:LASTEXITCODE = $null", ].join("; ") + "; "; /** * Report the final command's status. A successful final command wins over a * stale LASTEXITCODE; a failed final native command retains its real code; * other PowerShell failures map to 1. * * The leading newline detaches the epilogue from a trailing line comment. The * leading semicolon also prevents a trailing backtick from joining the * epilogue to the user's final command. */ export const EXIT_EPILOGUE = "\n; $__pi_ok = $?; if ($__pi_ok) { exit 0 } elseif ($null -ne $global:LASTEXITCODE -and $global:LASTEXITCODE -ne 0) { exit $global:LASTEXITCODE } else { exit 1 }"; export function buildPowerShellSource(command: string, config: PwshNativeConfig): string { const strict = config.strictMode ? "$ErrorActionPreference = 'Stop'; " : ""; return `${UTF8_PREFIX}${strict}${command}${EXIT_EPILOGUE}`; } export const SOURCE_BOOTSTRAP = "$__pi_source = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String([Console]::In.ReadToEnd())); & ([ScriptBlock]::Create($__pi_source))"; export function buildPowerShellArguments(config: PwshNativeConfig): string[] { const args = ["-NoLogo"]; if (!config.loadProfile) args.push("-NoProfile"); args.push("-NonInteractive"); if (config.executionPolicy) args.push("-ExecutionPolicy", config.executionPolicy); // PowerShell decodes `-Command -` input with the console code page before a // UTF-8 prelude can run. Transporting UTF-8 source as base64 over stdin keeps // the bootstrap ASCII-only, preserves Unicode, and avoids command-line limits. args.push("-Command", SOURCE_BOOTSTRAP); return args; }