sketch: add patch callback hook to warm codereview cache

When the agent patches a file, concurrently pre-compile test binaries
in the background to speed up future codereview runs.

This helps make codereview runs faster without
pre-flighting everything in the whole repository.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s2a01805b644342f9k
diff --git a/claudetool/codereview/codereview.go b/claudetool/codereview/codereview.go
index d99edff..411195a 100644
--- a/claudetool/codereview/codereview.go
+++ b/claudetool/codereview/codereview.go
@@ -10,6 +10,7 @@
 	"path/filepath"
 	"slices"
 	"strings"
+	"sync"
 
 	"sketch.dev/claudetool"
 )
@@ -22,8 +23,11 @@
 	reviewed        []string     // history of all commits which have been reviewed
 	initialWorktree string       // git worktree at initial commit, absolute path
 	// "Related files" caching
-	processedChangedFileSets map[string]bool   // hash of sorted changedFiles -> processed
-	reportedRelatedFiles     map[string]bool   // file path -> reported
+	processedChangedFileSets map[string]bool // hash of sorted changedFiles -> processed
+	reportedRelatedFiles     map[string]bool // file path -> reported
+	// Pre-warming of Go build/test cache
+	warmMutex      sync.Mutex      // protects warmedPackages map
+	warmedPackages map[string]bool // packages that have been cache warmed
 }
 
 func NewCodeReviewer(ctx context.Context, repoRoot, sketchBaseRef string) (*CodeReviewer, error) {
@@ -32,6 +36,7 @@
 		sketchBaseRef:            sketchBaseRef,
 		processedChangedFileSets: make(map[string]bool),
 		reportedRelatedFiles:     make(map[string]bool),
+		warmedPackages:           make(map[string]bool),
 	}
 	if r.repoRoot == "" {
 		return nil, fmt.Errorf("NewCodeReviewer: repoRoot must be non-empty")
@@ -250,6 +255,9 @@
 }
 
 func (r *CodeReviewer) absPath(relPath string) string {
+	if filepath.IsAbs(relPath) {
+		return relPath
+	}
 	return filepath.Clean(filepath.Join(r.repoRoot, relPath))
 }