The conversation viewer's 'uncommitted changes' widget only ever saw work done
in a main checkout: the transcript-replay path (editsdiff) rejected every path
under ~/worktrees/<dir> and ~/projects/<slug>, so a conversation working in a
worktree — the normal case — showed nothing until its branch merged.
- backend/worktreediff.py: diff the worktree for real. A worktree's .git file
points at a host path, so it maps the host repo root onto the mounted one
(PROJECTS_DIR/<slug> or REPO_DIR) and drives git with an explicit
--git-dir/--work-tree pair; returns 'git diff HEAD' plus untracked files,
with a 1.5s TTL cache so an SSE ping costs one round of git calls.
- /api/conversation-uncommitted-diff prefers it, keeping only the replayed
files that fall outside the worktree's repo; the replay stays the fallback
once a worktree is torn down.
- editsdiff: normalise ~/worktrees/<dir>/… and ~/projects/<slug>/… onto the
repo-relative paths each repo token's git commands use, and drop __pycache__
and unexpanded-tilde noise.
- UI: the Changes row shows the branch, DiffView a branch chip; diff-blob
serves image blobs from the worktree copy.