| 40 | } |
| 41 | |
| 42 | export async function ensureProjectGit(projectRoot: string): Promise<EnsureProjectGitResult> { |
| 43 | const abs = resolve(projectRoot); |
| 44 | const gitPath = resolve(abs, '.git'); |
| 45 | const headPath = resolve(gitPath, 'HEAD'); |
| 46 | |
| 47 | let needsRepair = false; |
| 48 | if (existsSync(gitPath)) { |
| 49 | if (!statSync(gitPath).isDirectory()) { |
| 50 | return { didInit: false }; |
| 51 | } |
| 52 | if (existsSync(headPath)) { |
| 53 | return { didInit: false }; |
| 54 | } |
| 55 | log.info({}, 'detected partial .git/ — running git init to repair'); |
| 56 | needsRepair = true; |
| 57 | } |
| 58 | |
| 59 | let detected: GitDetected; |
| 60 | try { |
| 61 | detected = assertGitAvailable(); |
| 62 | } catch (err) { |
| 63 | if (err instanceof GitNotAvailableError || err instanceof GitTooOldError) { |
| 64 | emitPreflightFailureSpan(err); |
| 65 | log.warn( |
| 66 | { |
| 67 | event: 'git_preflight_fail', |
| 68 | platform: err.platform, |
| 69 | reason: err instanceof GitTooOldError ? 'too_old' : 'not_available', |
| 70 | detectedVersion: err instanceof GitTooOldError ? err.detected : '', |
| 71 | }, |
| 72 | err instanceof GitTooOldError ? 'git binary too old' : 'git binary not found', |
| 73 | ); |
| 74 | } else { |
| 75 | log.warn( |
| 76 | { |
| 77 | event: 'git_preflight_unexpected_error', |
| 78 | message: err instanceof Error ? err.message : String(err), |
| 79 | }, |
| 80 | 'unexpected error during git preflight', |
| 81 | ); |
| 82 | } |
| 83 | throw err; |
| 84 | } |
| 85 | const gitBin = detected.resolvedPath; |
| 86 | |
| 87 | if (!needsRepair && (await isInsideExistingWorkTree(gitBin, abs))) { |
| 88 | return { didInit: false }; |
| 89 | } |
| 90 | |
| 91 | let stderr = ''; |
| 92 | try { |
| 93 | const result = await execFileAsync(gitBin, ['init', '--initial-branch=main', abs]); |
| 94 | stderr = result.stderr ?? ''; |
| 95 | } catch (err) { |
| 96 | const capturedStderr = |
| 97 | err !== null && typeof err === 'object' && 'stderr' in err |
| 98 | ? String((err as { stderr: unknown }).stderr ?? '') |
| 99 | : ''; |