---
source: src/shell/mod.rs
expression: output
---
# worktrunk shell integration for PowerShell
#
# Limitations compared to bash/zsh/fish:
# - Hooks using bash syntax won't work without Git Bash
#
# For full hook compatibility on Windows, install Git for Windows and use bash integration.
# Only initialize if wt is available (in PATH or via WORKTRUNK_BIN)
if ((Get-Command wt -ErrorAction SilentlyContinue) -or $env:WORKTRUNK_BIN) {
# wt wrapper function - uses temp file for directives
#
# IMPORTANT: This function must remain a "simple function" (no [CmdletBinding()] or
# [Parameter()] attributes). Advanced functions add common parameters like -Debug,
# -Verbose, -ErrorAction, etc. that intercept short flags: e.g., -D is consumed as
# -Debug, -V as -Verbose, instead of being passed through to wt.exe. Using $args
# (automatic variable for simple functions) ensures all arguments reach the binary
# unchanged.
function wt {
# Use WORKTRUNK_BIN if set (for testing dev builds), otherwise find via Get-Command
# Select-Object -First 1 handles case where multiple binaries match (e.g., wt.exe from Windows Terminal)
if ($env:WORKTRUNK_BIN) {
$wtBin = $env:WORKTRUNK_BIN
} else {
$wtBin = (Get-Command wt -CommandType Application | Select-Object -First 1).Source
}
$directiveFile = [System.IO.Path]::GetTempFileName()
try {
# Run wt with WORKTRUNK_DIRECTIVE_FILE env var
# WORKTRUNK_SHELL tells the binary to use PowerShell-compatible escaping
$env:WORKTRUNK_DIRECTIVE_FILE = $directiveFile
$env:WORKTRUNK_SHELL = "powershell"
& $wtBin @args
$exitCode = $LASTEXITCODE
}
finally {
Remove-Item Env:\WORKTRUNK_DIRECTIVE_FILE -ErrorAction SilentlyContinue
Remove-Item Env:\WORKTRUNK_SHELL -ErrorAction SilentlyContinue
}
# Execute the directive script if it has content
try {
if ((Test-Path $directiveFile) -and (Get-Item $directiveFile).Length -gt 0) {
$script = Get-Content -Path $directiveFile -Raw
if ($script.Trim()) {
Invoke-Expression $script
# If wt succeeded, use the directive script's exit code
if ($exitCode -eq 0) {
$exitCode = $LASTEXITCODE
}
}
}
}
finally {
# Cleanup even if Invoke-Expression throws
Remove-Item $directiveFile -ErrorAction SilentlyContinue
}
# Propagate exit code so $? and $LASTEXITCODE are consistent for scripts/CI
$global:LASTEXITCODE = $exitCode
if ($exitCode -ne 0) {
# Write error to set $? = $false without throwing
Write-Error "wt exited with code $exitCode" -ErrorAction SilentlyContinue
}
return $exitCode
}
# Tab completion - generate clap's completer script and eval it
# This registers Register-ArgumentCompleter with proper handling
# Use WORKTRUNK_BIN if set (for testing), otherwise find via Get-Command
if ($env:WORKTRUNK_BIN) {
$wtBinForComplete = $env:WORKTRUNK_BIN
} else {
$wtBinForComplete = (Get-Command wt -CommandType Application | Select-Object -First 1).Source
}
$env:COMPLETE = "powershell"
try {
# Capture output first, then pipe - avoids "Cannot run a document in the middle of a pipeline"
# error that can occur in some PowerShell configurations/terminals
$completionScript = & $wtBinForComplete 2>$null
if ($completionScript) {
$completionScript | Out-String | Invoke-Expression
}
}
catch {
# Completion registration is optional - wrapper function still works without it
}
finally {
Remove-Item Env:\COMPLETE -ErrorAction SilentlyContinue
}
}