diff --git a/internal/doctor/branch_check.go b/internal/doctor/branch_check.go index bd3e30d3..353b7dd8 100644 --- a/internal/doctor/branch_check.go +++ b/internal/doctor/branch_check.go @@ -534,10 +534,16 @@ func (c *CloneDivergenceCheck) getCloneInfo(path string) (cloneInfo, error) { // Fetch to make sure we have latest refs (silent, ignore errors) // Use a short timeout to prevent hanging on network issues, SSH prompts, or credential dialogs + // Also disable SSH interactive features to prevent blocking on password/passphrase prompts fetchCtx, fetchCancel := context.WithTimeout(context.Background(), 5*time.Second) defer fetchCancel() cmd = exec.CommandContext(fetchCtx, "git", "fetch", "--quiet") cmd.Dir = path + // Disable SSH password prompts and batch mode - fail fast instead of hanging + cmd.Env = append(os.Environ(), + "GIT_SSH_COMMAND=ssh -o BatchMode=yes -o ConnectTimeout=3", + "GIT_TERMINAL_PROMPT=0", + ) _ = cmd.Run() // Count commits behind origin/main diff --git a/internal/lock/lock.go b/internal/lock/lock.go index af54d694..be28722e 100644 --- a/internal/lock/lock.go +++ b/internal/lock/lock.go @@ -28,10 +28,10 @@ var ( // LockInfo contains information about who holds a lock. type LockInfo struct { - PID int `json:"pid"` + PID int `json:"pid"` AcquiredAt time.Time `json:"acquired_at"` - SessionID string `json:"session_id,omitempty"` - Hostname string `json:"hostname,omitempty"` + SessionID string `json:"session_id,omitempty"` + Hostname string `json:"hostname,omitempty"` } // IsStale checks if the lock is stale (owning process is dead). @@ -194,15 +194,34 @@ func (l *Lock) write(sessionID string) error { // FindAllLocks scans a directory tree for agent.lock files. // Returns a map of worker directory -> LockInfo. +// Skips .git directories and other large irrelevant directories for performance. func FindAllLocks(root string) (map[string]*LockInfo, error) { locks := make(map[string]*LockInfo) + // Directories to skip during walk (these won't contain .runtime/agent.lock files) + skipDirs := map[string]bool{ + ".git": true, + "node_modules": true, + "vendor": true, + "target": true, // Rust/Java build output + "build": true, + "dist": true, + ".gradle": true, + ".m2": true, + "bazel-out": true, + "bazel-bin": true, + } + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return nil // Skip errors } if info.IsDir() { + // Skip irrelevant directories for performance + if skipDirs[info.Name()] { + return filepath.SkipDir + } return nil }