# Shell Integration Reference

How Worktrunk's shell integration works and how to debug issues.

## Why Shell Integration Exists

Subprocesses cannot change the parent shell's current directory. When
`wt switch feature` runs, the `wt` binary runs as a child process and cannot
`cd` the terminal.

Worktrunk solves this with **split directive file passing**: the shell wrapper
creates two temp files, `wt` writes a raw path to one (cd) and shell commands
to the other (`--execute` payloads), and the wrapper applies both after `wt`
exits. The split design eliminates shell injection from cd directives — the CD
file holds a raw path that is never parsed as shell. The wrapper's steps and a
simplified implementation: [How the Shell Wrapper
Works](#how-the-shell-wrapper-works).

## Installation

```bash
# Auto-install for all shells (bash, zsh, fish, nushell (experimental), PowerShell)
wt config shell install

# Or manual installation - add to the shell config:
# bash (~/.bashrc):
eval "$(wt config shell init bash)"

# zsh (~/.zshrc):
eval "$(wt config shell init zsh)"

# fish (~/.config/fish/config.fish):
wt config shell init fish | source

# nushell (experimental) — save to vendor autoload directory:
wt config shell init nu | save -f ($nu.vendor-autoload-dirs | last | path join wt.nu)

# PowerShell ($PROFILE):
Invoke-Expression (& wt config shell init powershell | Out-String)
```

## Checking Status

```bash
# Show shell integration status
wt config show
```

The RUNTIME section shows whether shell integration is active for the current
session.

## Warning Messages

When shell integration isn't working, `wt switch` shows warnings explaining why.

### "shell wrapper is out of date"

**Meaning**: The active shell still has a pre-split wrapper loaded. Current
versions no longer write shell commands to that wrapper's single directive
file, because it mixes trusted directory paths with arbitrary shell.

**Fix**: Run `wt config shell install`, then restart the shell (or reload its
config) to activate the current split-file wrapper.

### "shell integration not installed"

**Meaning**: The current shell's config file doesn't have the
`eval "$(wt config shell init ...)"` line. The current shell is detected from
the process tree (falling back to `$SHELL`), so this refers to the shell wt
was actually invoked from, not necessarily the login shell.

**Fix**: Run `wt config shell install` or add the line manually.

### "shell integration installed but not active"

**Meaning**: Shell integration is configured for the current shell, but the
shell function isn't loaded in this session — usually because the session was
started before installation.

**Fix**: Start a new terminal or run `source ~/.bashrc` (or equivalent). If
the message persists after a restart, `wt config show` reports the detected
shell, `$SHELL`, and per-shell integration status.

### "ran ./path/to/wt; shell integration wraps wt"

**Meaning**: The binary was invoked with an explicit path (like `./target/debug/wt`
or `/usr/local/bin/wt`) instead of just `wt`. The shell wrapper only intercepts
the bare command `wt`.

**Fix**: Use `wt` without a path. For testing dev builds, set `WORKTRUNK_BIN`:
```bash
export WORKTRUNK_BIN=./target/debug/wt
wt switch feature  # Now uses the dev build with shell integration
```

### "ran git wt; running through git prevents cd"

**Meaning**: `git wt` (git alias) was used instead of `wt`. Git runs worktrunk as
a subprocess, bypassing the shell wrapper.

**Fix**: Use `wt` directly instead of `git wt` when directory switching is needed.

### "Alias bypasses shell integration"

**Meaning**: An alias like `alias gwt="/usr/bin/wt"` or `alias gwt="wt.exe"`
points directly to the binary instead of the shell function.

When shell integration is installed, it creates a shell function named `wt` (or
`git-wt`). If the alias points to the binary path, it bypasses this function
and shell integration won't work.

**Examples that bypass** (won't auto-cd):
```bash
alias gwt="/usr/bin/wt"
alias gwt="wt.exe"
alias wt="/path/to/wt"
```

**Fix**: Change the alias to point to the function name instead of the binary:
```bash
alias gwt="wt"       # Good - uses the shell function
alias gwt="git-wt"   # Good - uses the shell function
```

`wt config show` detects these problematic aliases and shows a warning with the
suggested fix.

## How the Shell Wrapper Works

The shell wrapper (installed by `wt config shell install`) defines a shell
function that:

1. Creates two temp files (cd and exec)
2. Sets `WORKTRUNK_DIRECTIVE_CD_FILE` and `WORKTRUNK_DIRECTIVE_EXEC_FILE`
3. Runs the real `wt` binary
4. Reads the CD file with `cd -- "$(< file)"` (raw path, no shell parsing)
5. Sources the EXEC file if non-empty (for `--execute` payloads)
6. Cleans up both temp files

Simplified example (actual wrapper handles completions and edge cases):
```bash
wt() {
    local cd_file exec_file exit_code=0
    cd_file="$(mktemp)"
    exec_file="$(mktemp)"

    WORKTRUNK_DIRECTIVE_CD_FILE="$cd_file" WORKTRUNK_DIRECTIVE_EXEC_FILE="$exec_file" \
        command wt "$@" || exit_code=$?

    if [[ -s "$cd_file" ]]; then
        cd -- "$(<"$cd_file")"
    fi
    if [[ -s "$exec_file" ]]; then
        source "$exec_file"
    fi

    rm -f "$cd_file" "$exec_file"
    return "$exit_code"
}
```

### Directive trust boundary

The CD file contains only a raw path, so Worktrunk can pass it through to
alias and hook subprocesses. The EXEC file contains shell code that the parent
wrapper sources, so Worktrunk removes it from project-defined aliases and
hooks. User-config aliases are the intentional exception: because their
commands are authored by the user, they retain the EXEC file and can run a
nested `wt switch --execute`.

## Debugging Checklist

### 1. Check if wrapper is installed

```bash
# Should show shell function, not binary path
type wt

# Expected output (bash/zsh):
# wt is a function
# wt () { ... }

# If it shows a path like /usr/local/bin/wt, wrapper isn't loaded
```

### 1b. Check if wrapper is installed (PowerShell)

```powershell
# PowerShell: should show Function, not just Application
Get-Command wt -All

# Expected output when wrapper is loaded:
# CommandType  Name  Source
# -----------  ----  ------
# Function     wt
# Application  wt    C:\Users\...\wt.exe

# If only Application appears, wrapper isn't loaded (restart shell)
# If Function appears but integration is still "not active", check the body:
(Get-Command wt -CommandType Function).ScriptBlock | Select-String WORKTRUNK
```

### 2. Check shell config file

```bash
# bash
grep -n "wt config shell init" ~/.bashrc

# zsh
grep -n "wt config shell init" ~/.zshrc

# fish
grep -n "wt config shell init" ~/.config/fish/config.fish
```

Should show the `eval` line with line number.

### 3. Check if directive files are set

```bash
# After running any wt command, these should be unset (temp files deleted)
echo $WORKTRUNK_DIRECTIVE_CD_FILE
echo $WORKTRUNK_DIRECTIVE_EXEC_FILE

# During wt execution, these would be set to temp file paths
```

### 4. Test directive files manually

```bash
# Create temp files and test
export WORKTRUNK_DIRECTIVE_CD_FILE=$(mktemp)
export WORKTRUNK_DIRECTIVE_EXEC_FILE=$(mktemp)
command wt switch feature
cat $WORKTRUNK_DIRECTIVE_CD_FILE     # Should contain: /path/to/worktree (raw path)
cd -- "$(<$WORKTRUNK_DIRECTIVE_CD_FILE)"  # Should cd you there
rm -f $WORKTRUNK_DIRECTIVE_CD_FILE $WORKTRUNK_DIRECTIVE_EXEC_FILE
```

## Common Issues

### Shell integration works in terminal but not in IDE terminal

IDE terminals may use different shell configs. Check:
- VS Code: Settings → Terminal → Integrated → Shell Args
- The IDE terminal might source a different profile

### Completions not working

Completions are installed alongside shell integration. If they're missing:

```bash
# Reinstall (forces regeneration)
wt config shell install

# For zsh, you may need compinit before the wt line:
autoload -Uz compinit && compinit
eval "$(wt config shell init zsh)"
```

### Windows Git Bash issues

Git Bash uses MSYS2, which automatically converts POSIX paths in environment
variables. The directive file path is handled correctly without manual conversion.

If you see path issues, ensure you're using a recent Git for Windows version.

## Environment Variables

| Variable | Purpose |
|----------|---------|
| `WORKTRUNK_DIRECTIVE_CD_FILE` | Set by shell wrapper; wt writes a raw path, wrapper `cd`s to it |
| `WORKTRUNK_DIRECTIVE_EXEC_FILE` | Set by shell wrapper; wt writes shell commands, wrapper sources the file |
| `WORKTRUNK_BIN` | Override binary path (for testing dev builds) |
| `WORKTRUNK_SHELL` | Set by the PowerShell (`powershell`) and fish (`fish`) wrappers; selects how wt escapes the EXEC directive payload for that shell |

## See Also

- `wt config shell --help` — Shell integration commands
- `wt config show` — View current configuration and status
