When .gsd is a symlink (e.g., openclip/.gsd -> ~/.gsd/projects/<hash>),
worktrees resolve to ~/.gsd/projects/<hash>/worktrees/<name> instead of
the expected <repo>/.gsd/worktrees/<name>. All worktree detection
functions used the marker /.gsd/worktrees/ which did not match the
resolved path /.gsd/projects/<hash>/worktrees/.
This caused three cascading failures:
1. escapeStaleWorktree failed to detect stale worktree CWD
2. isUnderGsdWorktrees returned false, causing nested worktrees
3. Empty registry was conflated with "all milestones complete"
Changes:
- Add findWorktreeSegment helper matching both direct and symlink layouts
- Refactor detectWorktreeName and resolveProjectRoot to use the helper
- Fix escapeStaleWorktree in auto-worktree-sync.ts for symlink paths
- Fix isUnderGsdWorktrees in auto-start.ts for symlink paths
- Fix resolveCapturesPath in captures.ts for symlink paths
- Distinguish empty registry from all-complete in auto-loop.ts
- Add tests for symlink-resolved path detection