@fern-api/replay 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -7
- package/dist/cli.cjs +3500 -3312
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +2016 -1829
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +197 -135
- package/dist/index.d.ts +197 -135
- package/dist/index.js +1982 -1795
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/git/GitClient.ts","../src/HybridReconstruction.ts","../src/PatchApplyTheirs.ts","../src/index.ts","../src/credentials.ts","../src/git/CommitDetection.ts","../src/LockfileManager.ts","../src/ReplayDetector.ts","../src/ReplayApplicator.ts","../src/conflict-utils.ts","../src/ThreeWayMerge.ts","../src/ReplayCommitter.ts","../src/ReplayService.ts","../src/PatchRegionDiff.ts","../src/FernignoreMigrator.ts","../src/commands/bootstrap.ts","../src/commands/forget.ts","../src/commands/reset.ts","../src/commands/resolve.ts","../src/commands/status.ts"],"sourcesContent":["import { type SimpleGit, simpleGit } from \"simple-git\";\nimport type { CommitInfo } from \"../types.js\";\n\nexport class GitClient {\n private git: SimpleGit;\n private repoPath: string;\n\n constructor(repoPath: string) {\n this.repoPath = repoPath;\n this.git = simpleGit(repoPath);\n }\n\n async exec(args: string[]): Promise<string> {\n return this.git.raw(args);\n }\n\n async execWithInput(args: string[], input: string): Promise<string> {\n // simple-git's raw() doesn't support stdin directly,\n // so we use spawn for commands that need stdin (e.g. git am)\n const { spawn } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const proc = spawn(\"git\", args, { cwd: this.repoPath });\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data: Buffer) => {\n stdout += data.toString();\n });\n proc.stderr.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdout);\n } else {\n reject(new Error(`git ${args.join(\" \")} failed (code ${code}): ${stderr}`));\n }\n });\n\n proc.stdin.write(input);\n proc.stdin.end();\n });\n }\n\n async formatPatch(commitSha: string): Promise<string> {\n return this.exec([\"format-patch\", \"-1\", commitSha, \"--stdout\"]);\n }\n\n async applyPatch(patchContent: string): Promise<void> {\n await this.execWithInput([\"am\", \"--3way\"], patchContent);\n }\n\n async getTreeHash(commitSha: string): Promise<string> {\n return (await this.exec([\"rev-parse\", `${commitSha}^{tree}`])).trim();\n }\n\n async showFile(treeish: string, filePath: string): Promise<string | null> {\n try {\n return await this.exec([\"show\", `${treeish}:${filePath}`]);\n } catch {\n return null;\n }\n }\n\n async getCommitInfo(commitSha: string): Promise<CommitInfo> {\n const format = \"%H%x00%an%x00%ae%x00%s\";\n const output = await this.exec([\"log\", \"-1\", `--format=${format}`, commitSha]);\n const [sha, authorName, authorEmail, message] = output.trim().split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n }\n\n async getCommitParents(commitSha: string): Promise<string[]> {\n const output = await this.exec([\"rev-parse\", `${commitSha}^@`]);\n return output.trim().split(\"\\n\").filter(Boolean);\n }\n\n /**\n * Detects renames and copies between two trees.\n *\n * Both `R` (rename) and `C` (copy) entries are returned as `{from, to}` pairs.\n * Copies are treated as rename-equivalent because the generator may produce the\n * new path while the old path remains in the tree (e.g., imperfect cleanup,\n * customer edits at the old path, or test helpers that only write new files).\n * Callers that care about \"is the source still present\" should verify via\n * `showFile(toTree, from)`.\n */\n async detectRenames(fromTree: string, toTree: string): Promise<Array<{ from: string; to: string }>> {\n try {\n // --find-copies (-C) catches the case where the generator writes the new path\n // but leaves the old path in the tree (e.g., when the generator's cleanup step\n // didn't run, or customer edits at the old path kept it present). Rename\n // detection alone requires the old path to be deleted; copy detection does not.\n const output = await this.exec([\n \"diff\", \"--find-renames\", \"--find-copies\", \"--name-status\", fromTree, toTree\n ]);\n const renames: Array<{ from: string; to: string }> = [];\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Lines look like: R095\\told/path.ts\\tnew/path.ts (rename, 95% similarity)\n // or: C095\\tsrc/path.ts\\tnew/path.ts (copy, 95% similarity)\n if (line.startsWith(\"R\") || line.startsWith(\"C\")) {\n const parts = line.split(\"\\t\");\n if (parts.length >= 3) {\n renames.push({ from: parts[1]!, to: parts[2]! });\n }\n }\n }\n return renames;\n } catch {\n return [];\n }\n }\n\n async isAncestor(commit: string, descendant: string): Promise<boolean> {\n try {\n const mergeBase = (await this.exec([\"merge-base\", commit, descendant])).trim();\n return mergeBase === commit;\n } catch {\n // No common ancestor (e.g., orphan branches)\n return false;\n }\n }\n\n async commitExists(sha: string): Promise<boolean> {\n try {\n const type = await this.exec([\"cat-file\", \"-t\", sha]);\n return type.trim() === \"commit\";\n } catch {\n return false;\n }\n }\n\n async treeExists(treeHash: string): Promise<boolean> {\n try {\n const type = await this.exec([\"cat-file\", \"-t\", treeHash]);\n return type.trim() === \"tree\";\n } catch {\n return false;\n }\n }\n\n async getCommitBody(commitSha: string): Promise<string> {\n return this.exec([\"log\", \"-1\", \"--format=%B\", commitSha]);\n }\n\n getRepoPath(): string {\n return this.repoPath;\n }\n}\n","/**\n * Hybrid BASE reconstruction for ghost commits.\n *\n * When a patch's base generation tree is unreachable (GC'd after squash merge,\n * shallow clone), we reconstruct BASE and THEIRS from the unified diff and\n * the current OURS content on disk.\n *\n * The unified diff encodes:\n * - BASE = context lines + removed lines\n * - THEIRS = context lines + added lines\n *\n * By matching context lines against OURS, we anchor hunks to positions in the\n * current file and fill gaps with OURS content, producing hybrid BASE and\n * THEIRS suitable for threeWayMerge().\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DiffHunk {\n /** 1-based line number in the old (BASE) file where this hunk starts */\n oldStart: number;\n /** Number of lines in the old (BASE) file this hunk spans */\n oldCount: number;\n /** 1-based line number in the new (THEIRS) file where this hunk starts */\n newStart: number;\n /** Number of lines in the new (THEIRS) file this hunk spans */\n newCount: number;\n /** Ordered entries: context lines, removed lines, added lines */\n lines: HunkLine[];\n}\n\nexport type HunkLine =\n | { type: \"context\"; content: string }\n | { type: \"remove\"; content: string }\n | { type: \"add\"; content: string };\n\nexport interface LocatedHunk {\n hunk: DiffHunk;\n /** 0-based index in OURS lines where this hunk's context starts */\n oursOffset: number;\n /** Number of OURS lines this hunk covers */\n oursSpan: number;\n}\n\nexport interface ReconstructionResult {\n base: string;\n theirs: string;\n}\n\n// ---------------------------------------------------------------------------\n// 1. Hunk Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a unified diff (for a single file) into structured hunks.\n * Input should start with `diff --git` and contain `@@` hunk headers.\n */\nexport function parseHunks(fileDiff: string): DiffHunk[] {\n const lines = fileDiff.split(\"\\n\");\n const hunks: DiffHunk[] = [];\n let currentHunk: DiffHunk | null = null;\n\n for (const line of lines) {\n const headerMatch = line.match(\n /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/\n );\n if (headerMatch) {\n if (currentHunk) {\n hunks.push(currentHunk);\n }\n currentHunk = {\n oldStart: parseInt(headerMatch[1]!, 10),\n oldCount: headerMatch[2] != null ? parseInt(headerMatch[2], 10) : 1,\n newStart: parseInt(headerMatch[3]!, 10),\n newCount: headerMatch[4] != null ? parseInt(headerMatch[4], 10) : 1,\n lines: []\n };\n continue;\n }\n\n if (!currentHunk) continue;\n\n // Skip metadata lines\n if (\n line.startsWith(\"diff --git\") ||\n line.startsWith(\"index \") ||\n line.startsWith(\"---\") ||\n line.startsWith(\"+++\") ||\n line.startsWith(\"old mode\") ||\n line.startsWith(\"new mode\") ||\n line.startsWith(\"similarity index\") ||\n line.startsWith(\"rename from\") ||\n line.startsWith(\"rename to\") ||\n line.startsWith(\"new file mode\") ||\n line.startsWith(\"deleted file mode\")\n ) {\n continue;\n }\n\n if (line === \"\\\\") {\n continue;\n }\n\n if (line.startsWith(\"-\")) {\n currentHunk.lines.push({ type: \"remove\", content: line.slice(1) });\n } else if (line.startsWith(\"+\")) {\n currentHunk.lines.push({ type: \"add\", content: line.slice(1) });\n } else if (line.startsWith(\" \") || line === \"\") {\n // Context line. A bare empty string is a context line for an empty line\n // (unified diff uses \" \" prefix but trailing whitespace stripping may remove it).\n currentHunk.lines.push({\n type: \"context\",\n content: line.startsWith(\" \") ? line.slice(1) : line\n });\n }\n }\n\n if (currentHunk) {\n hunks.push(currentHunk);\n }\n\n return hunks;\n}\n\n// ---------------------------------------------------------------------------\n// 2. Context Matcher\n// ---------------------------------------------------------------------------\n\nfunction extractLeadingContext(hunk: DiffHunk): string[] {\n const result: string[] = [];\n for (const line of hunk.lines) {\n if (line.type !== \"context\") break;\n result.push(line.content);\n }\n return result;\n}\n\nfunction extractTrailingContext(hunk: DiffHunk): string[] {\n const result: string[] = [];\n for (let i = hunk.lines.length - 1; i >= 0; i--) {\n if (hunk.lines[i]!.type !== \"context\") break;\n result.unshift(hunk.lines[i]!.content);\n }\n return result;\n}\n\nfunction countOursLinesBeforeTrailing(hunk: DiffHunk): number {\n let count = 0;\n const trailingStart = findTrailingContextStart(hunk);\n for (let i = 0; i < trailingStart; i++) {\n if (hunk.lines[i]!.type === \"context\") count++;\n }\n return count;\n}\n\nfunction findTrailingContextStart(hunk: DiffHunk): number {\n let i = hunk.lines.length - 1;\n while (i >= 0 && hunk.lines[i]!.type === \"context\") {\n i--;\n }\n return i + 1;\n}\n\nfunction matchesAt(needle: string[], haystack: string[], offset: number): boolean {\n for (let i = 0; i < needle.length; i++) {\n if (haystack[offset + i] !== needle[i]) return false;\n }\n return true;\n}\n\n/**\n * Find a sequence of context lines in OURS, starting search near `hint`.\n * Returns 0-based index of the first matching line, or -1 if not found.\n */\nfunction findContextInOurs(\n contextLines: string[],\n oursLines: string[],\n minIndex: number,\n hint: number\n): number {\n const SEARCH_WINDOW = 200;\n const maxStart = oursLines.length - contextLines.length;\n\n const clampedHint = Math.max(minIndex, Math.min(hint, maxStart));\n\n // Check hint position first, then expand outward symmetrically\n if (clampedHint >= minIndex && clampedHint <= maxStart) {\n if (matchesAt(contextLines, oursLines, clampedHint)) {\n return clampedHint;\n }\n }\n for (let delta = 1; delta <= SEARCH_WINDOW; delta++) {\n for (const sign of [1, -1] as const) {\n const idx = clampedHint + delta * sign;\n if (idx < minIndex || idx > maxStart) continue;\n if (matchesAt(contextLines, oursLines, idx)) {\n return idx;\n }\n }\n }\n\n return -1;\n}\n\n/**\n * Compute how many lines this hunk spans in OURS.\n */\nfunction computeOursSpan(\n hunk: DiffHunk,\n oursLines: string[],\n oursOffset: number\n): number {\n const leading = extractLeadingContext(hunk);\n const trailing = extractTrailingContext(hunk);\n\n if (trailing.length === 0) {\n const contextCount = hunk.lines.filter(\n (l) => l.type === \"context\"\n ).length;\n return Math.min(contextCount, oursLines.length - oursOffset);\n }\n\n // Find trailing context starting after leading context\n const searchStart = oursOffset + leading.length;\n for (let i = searchStart; i <= oursLines.length - trailing.length; i++) {\n if (matchesAt(trailing, oursLines, i)) {\n return i + trailing.length - oursOffset;\n }\n }\n\n // Trailing context not found — fall back to context-only estimate\n const contextCount = hunk.lines.filter(\n (l) => l.type === \"context\"\n ).length;\n return Math.min(contextCount, oursLines.length - oursOffset);\n}\n\n/**\n * Locate each hunk's position in OURS by matching context lines.\n * Returns null if any hunk cannot be located.\n */\nexport function locateHunksInOurs(\n hunks: DiffHunk[],\n oursLines: string[]\n): LocatedHunk[] | null {\n const located: LocatedHunk[] = [];\n let minOursIndex = 0;\n\n for (const hunk of hunks) {\n const contextLines = extractLeadingContext(hunk);\n let oursOffset: number;\n\n if (contextLines.length > 0) {\n const found = findContextInOurs(\n contextLines,\n oursLines,\n minOursIndex,\n hunk.newStart - 1\n );\n if (found === -1) {\n // Try trailing context as fallback\n const trailingContext = extractTrailingContext(hunk);\n if (trailingContext.length > 0) {\n const trailingFound = findContextInOurs(\n trailingContext,\n oursLines,\n minOursIndex,\n hunk.newStart - 1\n );\n if (trailingFound === -1) return null;\n const nonTrailingCount = countOursLinesBeforeTrailing(hunk);\n oursOffset = trailingFound - nonTrailingCount;\n if (oursOffset < minOursIndex) return null;\n } else {\n return null;\n }\n } else {\n oursOffset = found;\n }\n } else if (hunk.oldStart === 1 && hunk.oldCount === 0) {\n // Pure addition at start of file (or to empty file)\n oursOffset = 0;\n } else {\n // No context lines — use @@ header as best guess\n oursOffset = Math.max(hunk.newStart - 1, minOursIndex);\n }\n\n const oursSpan = computeOursSpan(hunk, oursLines, oursOffset);\n\n located.push({ hunk, oursOffset, oursSpan });\n minOursIndex = oursOffset + oursSpan;\n }\n\n return located;\n}\n\n// ---------------------------------------------------------------------------\n// 3. Assembler\n// ---------------------------------------------------------------------------\n\n/**\n * Assemble hybridBASE and hybridTHEIRS from located hunks and OURS.\n *\n * In gaps between hunks, BASE and THEIRS both get OURS content (3-way merge\n * treats gaps as \"no change\"). In hunk regions, BASE = context + removed,\n * THEIRS = context + added.\n */\nexport function assembleHybrid(\n locatedHunks: LocatedHunk[],\n oursLines: string[]\n): ReconstructionResult {\n const baseLines: string[] = [];\n const theirsLines: string[] = [];\n let oursCursor = 0;\n\n for (const { hunk, oursOffset, oursSpan } of locatedHunks) {\n // Gap before this hunk: fill with OURS content\n if (oursOffset > oursCursor) {\n const gapLines = oursLines.slice(oursCursor, oursOffset);\n baseLines.push(...gapLines);\n theirsLines.push(...gapLines);\n }\n\n // Hunk region: extract BASE lines and THEIRS lines from the diff\n for (const line of hunk.lines) {\n switch (line.type) {\n case \"context\":\n baseLines.push(line.content);\n theirsLines.push(line.content);\n break;\n case \"remove\":\n baseLines.push(line.content);\n break;\n case \"add\":\n theirsLines.push(line.content);\n break;\n }\n }\n\n oursCursor = oursOffset + oursSpan;\n }\n\n // Trailing gap after last hunk\n if (oursCursor < oursLines.length) {\n const gapLines = oursLines.slice(oursCursor);\n baseLines.push(...gapLines);\n theirsLines.push(...gapLines);\n }\n\n return {\n base: baseLines.join(\"\\n\"),\n theirs: theirsLines.join(\"\\n\")\n };\n}\n\n// ---------------------------------------------------------------------------\n// 4. Top-Level Entry Point\n// ---------------------------------------------------------------------------\n\n/**\n * Attempt to reconstruct BASE and THEIRS from a unified diff and OURS content.\n * Used when the patch's base generation tree is unreachable (ghost commit).\n *\n * Returns null if reconstruction fails (context mismatch, new/deleted file).\n */\nexport function reconstructFromGhostPatch(\n fileDiff: string,\n ours: string\n): ReconstructionResult | null {\n const hunks = parseHunks(fileDiff);\n\n if (hunks.length === 0) {\n return null;\n }\n\n // Pure new-file diff — use extractNewFileFromPatch instead\n const isPureAddition = hunks.every(\n (h) => h.oldCount === 0 && h.lines.every((l) => l.type !== \"remove\")\n );\n if (isPureAddition) {\n return null;\n }\n\n // Pure deletion\n const isPureDeletion = hunks.every(\n (h) => h.newCount === 0 && h.lines.every((l) => l.type !== \"add\")\n );\n if (isPureDeletion) {\n const baseLines: string[] = [];\n for (const hunk of hunks) {\n for (const line of hunk.lines) {\n if (line.type === \"context\" || line.type === \"remove\") {\n baseLines.push(line.content);\n }\n }\n }\n return {\n base: baseLines.join(\"\\n\"),\n theirs: \"\"\n };\n }\n\n const oursLines = ours.split(\"\\n\");\n const located = locateHunksInOurs(hunks, oursLines);\n\n if (!located) {\n return null;\n }\n\n return assembleHybrid(located, oursLines);\n}\n","import { mkdtemp, mkdir, writeFile, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { GitClient } from \"./git/GitClient.js\";\n\n/**\n * Apply a patch's `patch_content` to a base content string, returning the\n * post-apply (THEIRS) content.\n *\n * Free-function counterpart to `ReplayApplicator.applyPatchToContent`,\n * usable from `ReplayService.migratePatchesToSnapshot` without the\n * applicator's instance state. Creates its own temporary git repo each\n * call — fine for the one-shot migration path; not a hot loop.\n *\n * Returns `null` when the patch can't apply against the base (line\n * anchors don't match, malformed diff, or git apply rejects). Callers\n * fall back to a different THEIRS source.\n */\nexport async function applyPatchToContent(\n base: string,\n patchContent: string,\n filePath: string,\n): Promise<string | null> {\n const fileDiff = extractFileDiff(patchContent, filePath);\n if (!fileDiff) return null;\n\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-migrate-\"));\n const tempGit = new GitClient(tempDir);\n try {\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"migrate@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay Migration\"]);\n await tempGit.exec([\"config\", \"commit.gpgSign\", \"false\"]);\n\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, base);\n\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `base for ${filePath}`, \"--allow-empty\"]);\n\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n return await readFile(tempFilePath, \"utf-8\");\n } catch {\n return null;\n } finally {\n await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/**\n * Extract the diff hunks for `filePath` from a multi-file unified-diff\n * patch. Returns the slice starting at the file's `diff --git` header\n * up to the next `diff --git` (or end of input). Mirrors the logic in\n * `ReplayApplicator.extractFileDiff` — kept here for reuse without\n * exposing the private method.\n */\nfunction extractFileDiff(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const out: string[] = [];\n let inTarget = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTarget) break;\n const match = line.match(/^diff --git a\\/.+ b\\/(.+)$/);\n if (match && match[1] === filePath) {\n inTarget = true;\n out.push(line);\n }\n continue;\n }\n if (inTarget) out.push(line);\n }\n return out.length > 0 ? out.join(\"\\n\") + \"\\n\" : null;\n}\n","export type {\n GenerationLock,\n GenerationRecord,\n StoredPatch,\n CustomizationsConfig,\n MoveDeclaration,\n ReplayResult,\n FileResult,\n ConflictRegion,\n ConflictReason,\n ConflictMetadata,\n MergeResult,\n CommitInfo,\n ReplayConfig,\n} from \"./types.js\";\n\nexport {\n CREDENTIAL_PATTERNS,\n SENSITIVE_FILE_PATTERNS,\n isSensitiveFile,\n scanForCredentials,\n type CredentialPattern,\n} from \"./credentials.js\";\n\nexport { GitClient } from \"./git/GitClient.js\";\nexport {\n isGenerationCommit,\n isReplayCommit,\n isRevertCommit,\n parseRevertedSha,\n parseRevertedMessage,\n FERN_BOT_NAME,\n FERN_BOT_EMAIL,\n FERN_BOT_LOGIN,\n} from \"./git/CommitDetection.js\";\nexport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nexport { ReplayDetector, type DetectionResult } from \"./ReplayDetector.js\";\nexport { threeWayMerge } from \"./ThreeWayMerge.js\";\nexport { ReplayApplicator } from \"./ReplayApplicator.js\";\nexport { ReplayCommitter, type CommitOptions } from \"./ReplayCommitter.js\";\nexport {\n ReplayService,\n type ReplayReport,\n type ReplayOptions,\n type ApplyOptions,\n type ReplayPreparation,\n type ConflictDetail,\n type UnresolvedPatchInfo,\n} from \"./ReplayService.js\";\nexport { FernignoreMigrator, type MigrationAnalysis, type MigrationResult } from \"./FernignoreMigrator.js\";\nexport {\n bootstrap, type BootstrapOptions, type BootstrapResult,\n forget, type ForgetOptions, type ForgetResult, type MatchedPatch, type DiffStat,\n reset, type ResetOptions, type ResetResult,\n resolve, type ResolveOptions, type ResolveResult,\n status, type StatusResult, type StatusPatch, type StatusGeneration,\n} from \"./commands/index.js\";\n","/**\n * Credential detection patterns for the replay pipeline.\n *\n * Two-layer defense against credential leaks in .fern/replay.lock:\n * Layer 1 — file-level: SENSITIVE_FILE_PATTERNS blocks entire files (.env, .pem, etc.)\n * Layer 2 — content-level: CREDENTIAL_PATTERNS catches inline secrets in any file\n *\n * These patterns mirror the invariant assertions in __tests__/invariants/i4-credential-containment.ts.\n * If they diverge, the invariant tests independently catch real leaks.\n *\n * @security FER-9807\n */\n\nexport interface CredentialPattern {\n name: string;\n re: RegExp;\n}\n\nexport const CREDENTIAL_PATTERNS: ReadonlyArray<CredentialPattern> = [\n { name: \"PRIVATE KEY block\", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },\n { name: \"OPENSSH key\", re: /-----BEGIN OPENSSH PRIVATE KEY-----/ },\n { name: \"RSA key\", re: /-----BEGIN RSA PRIVATE KEY-----/ },\n { name: \"CERTIFICATE\", re: /-----BEGIN CERTIFICATE-----/ },\n { name: \"TOKEN=\", re: /\\bTOKEN\\s*=\\s*[\"']?[A-Za-z0-9._\\-+/=]{10,}/ },\n { name: \"api_key=\", re: /\\bapi[_-]?key\\s*=\\s*[\"']?[A-Za-z0-9._\\-+/=]{10,}/i },\n { name: \"password=\", re: /\\bpassword\\s*=\\s*[\"']?[^\\s\"']{6,}/i },\n { name: \"AWS_SECRET_ACCESS_KEY\", re: /AWS_SECRET_ACCESS_KEY/ },\n { name: \"JWT (eyJ...)\", re: /\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b/ },\n];\n\nexport const SENSITIVE_FILE_PATTERNS: ReadonlyArray<RegExp> = [\n /(^|\\/)\\.env(\\.[^/]+)?$/,\n /\\.pem$/,\n /\\.key$/,\n /\\.pkce_state\\.json$/,\n /(^|\\/)id_rsa$/,\n /(^|\\/)id_ed25519$/,\n];\n\n/** Check if a file path matches any sensitive file pattern. */\nexport function isSensitiveFile(filePath: string): boolean {\n return SENSITIVE_FILE_PATTERNS.some((re) => re.test(filePath));\n}\n\n/** Scan content for credential patterns. Returns matched pattern names. */\nexport function scanForCredentials(content: string): string[] {\n const matches: string[] = [];\n for (const { name, re } of CREDENTIAL_PATTERNS) {\n if (re.test(content)) {\n matches.push(name);\n }\n }\n return matches;\n}\n","import type { CommitInfo } from \"../types.js\";\n\n// Constants from Fern's PR #11502\nexport const FERN_BOT_NAME = \"fern-api\";\nexport const FERN_BOT_EMAIL = \"115122769+fern-api[bot]@users.noreply.github.com\";\nexport const FERN_BOT_LOGIN = \"fern-api[bot]\";\n\n// Fern-support commits (via bot account) are excluded from generation detection.\nconst FERN_SUPPORT_NAMES = [\"fern-support\", \"Fern Support\"];\n\nexport function isGenerationCommit(commit: CommitInfo): boolean {\n const isFernSupport = FERN_SUPPORT_NAMES.includes(commit.authorName);\n\n const isBotAuthor =\n !isFernSupport &&\n (commit.authorLogin === FERN_BOT_LOGIN ||\n commit.authorEmail === FERN_BOT_EMAIL ||\n commit.authorName === FERN_BOT_NAME);\n\n const hasGenerationMarker =\n commit.message.startsWith(\"[fern-generated]\") ||\n commit.message.startsWith(\"[fern-replay]\") ||\n commit.message.startsWith(\"[fern-autoversion]\") ||\n commit.message.includes(\"Generated by Fern\") ||\n commit.message.includes(\"\\u{1F916} Generated with Fern\") ||\n // Squash merge of a Fern-generated PR uses the PR title as commit message.\n // The default PR title is \"SDK Generation\" (from GithubStep's commitMessage default).\n // GitHub appends \"(#N)\" for the PR number, e.g. \"SDK Generation (#70)\".\n commit.message.startsWith(\"SDK Generation\");\n\n return isBotAuthor || hasGenerationMarker;\n}\n\nexport function isReplayCommit(commit: CommitInfo): boolean {\n return commit.message.startsWith(\"[fern-replay]\");\n}\n\n/** Check if a commit message matches git's standard revert format: Revert \"...\" */\nexport function isRevertCommit(message: string): boolean {\n return /^Revert \".+\"$/.test(message);\n}\n\n/** Extract the reverted commit SHA from a full commit body containing \"This reverts commit SHA.\" */\nexport function parseRevertedSha(fullBody: string): string | undefined {\n const match = fullBody.match(/This reverts commit ([0-9a-f]{40})\\./);\n return match?.[1];\n}\n\n/** Extract the original commit message from a revert subject like 'Revert \"original message\"' */\nexport function parseRevertedMessage(subject: string): string | undefined {\n const match = subject.match(/^Revert \"(.+)\"$/);\n return match?.[1];\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { stringify, parse } from \"yaml\";\nimport { isSensitiveFile, scanForCredentials } from \"./credentials.js\";\nimport type {\n GenerationLock,\n GenerationRecord,\n StoredPatch,\n CustomizationsConfig,\n} from \"./types.js\";\n\nconst LOCKFILE_HEADER = \"# DO NOT EDIT MANUALLY - Managed by Fern Replay\\n\";\n\nexport class LockfileNotFoundError extends Error {\n constructor(path: string) {\n super(`Lockfile not found: ${path}`);\n this.name = \"LockfileNotFoundError\";\n }\n}\n\nexport class LockfileManager {\n private outputDir: string;\n private lock: GenerationLock | null = null;\n readonly warnings: string[] = [];\n\n constructor(outputDir: string) {\n this.outputDir = outputDir;\n }\n\n get lockfilePath(): string {\n return join(this.outputDir, \".fern\", \"replay.lock\");\n }\n\n get customizationsPath(): string {\n return join(this.outputDir, \".fern\", \"replay.yml\");\n }\n\n exists(): boolean {\n return existsSync(this.lockfilePath);\n }\n\n read(): GenerationLock {\n if (this.lock) {\n return this.lock;\n }\n try {\n const content = readFileSync(this.lockfilePath, \"utf-8\");\n this.lock = parse(content) as GenerationLock;\n return this.lock;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === \"ENOENT\"\n ) {\n throw new LockfileNotFoundError(this.lockfilePath);\n }\n throw error;\n }\n }\n\n initialize(firstGeneration: GenerationRecord): void {\n this.initializeInMemory(firstGeneration);\n this.save();\n }\n\n /**\n * Set up in-memory lock state without writing to disk.\n * Useful for bootstrap dry-run where we need state for detection\n * but don't want to persist anything.\n */\n initializeInMemory(firstGeneration: GenerationRecord): void {\n this.lock = {\n version: \"1.0\",\n generations: [firstGeneration],\n current_generation: firstGeneration.commit_sha,\n patches: [],\n };\n }\n\n save(): void {\n if (!this.lock) {\n throw new Error(\"No lockfile data to save. Call read() or initialize() first.\");\n }\n\n // Clear warnings from any previous save() call to prevent accumulation.\n this.warnings.length = 0;\n\n // Layer 2 credential safety net: scan all patches before writing.\n // Strips ENTIRE patches that contain credential content (in either\n // `patch_content` or `theirs_snapshot`) or reference sensitive files.\n // Snapshot scanning is essential — snapshots store full file content,\n // so they're strictly more credential-rich than the diff alone.\n // Without scanning snapshots, a customer-edited config with a\n // committed token would leak into `.fern/replay.lock` via the\n // snapshot field even though the patch_content scan caught nothing.\n //\n // Note: if a patch modifies both a sensitive file and a legitimate file, the entire\n // patch is dropped. This is a deliberate safety trade-off — partial redaction risks\n // leaving credential context that regex didn't catch. The customer gets a warning.\n const cleanPatches: StoredPatch[] = [];\n for (const patch of this.lock.patches) {\n const diffMatches = scanForCredentials(patch.patch_content);\n const snapshotMatches: string[] = [];\n if (patch.theirs_snapshot) {\n for (const content of Object.values(patch.theirs_snapshot)) {\n const m = scanForCredentials(content);\n for (const x of m) {\n if (!snapshotMatches.includes(x)) snapshotMatches.push(x);\n }\n }\n }\n const credentialMatches = [...diffMatches, ...snapshotMatches.filter((m) => !diffMatches.includes(m))];\n const sensitiveFiles = patch.files.filter((f) => isSensitiveFile(f));\n\n if (credentialMatches.length > 0 || sensitiveFiles.length > 0) {\n const reasons: string[] = [];\n if (credentialMatches.length > 0) {\n reasons.push(`credential patterns: ${credentialMatches.join(\", \")}`);\n }\n if (sensitiveFiles.length > 0) {\n reasons.push(`sensitive files: ${sensitiveFiles.join(\", \")}`);\n }\n this.warnings.push(\n `Patch ${patch.id} removed from lockfile: ${reasons.join(\"; \")}. ` +\n `This prevents credential exposure in committed lockfiles.`\n );\n } else {\n cleanPatches.push(patch);\n }\n }\n this.lock.patches = cleanPatches;\n\n const dir = dirname(this.lockfilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const yaml = stringify(this.lock, {\n lineWidth: 0,\n blockQuote: \"literal\",\n });\n const content = LOCKFILE_HEADER + yaml;\n // Atomic write: write to temp file then rename (rename is atomic on most filesystems)\n const tmpPath = this.lockfilePath + \".tmp\";\n writeFileSync(tmpPath, content, \"utf-8\");\n renameSync(tmpPath, this.lockfilePath);\n }\n\n addGeneration(record: GenerationRecord): void {\n this.ensureLoaded();\n this.lock!.generations.push(record);\n this.lock!.current_generation = record.commit_sha;\n }\n\n addPatch(patch: StoredPatch): void {\n this.ensureLoaded();\n this.lock!.patches.push(patch);\n }\n\n updatePatch(\n patchId: string,\n updates: Partial<Pick<StoredPatch, \"base_generation\" | \"patch_content\" | \"content_hash\" | \"files\" | \"status\" | \"user_owned\" | \"theirs_snapshot\">>,\n ): void {\n this.ensureLoaded();\n const patch = this.lock!.patches.find((p) => p.id === patchId);\n if (!patch) {\n throw new Error(`Patch not found: ${patchId}`);\n }\n Object.assign(patch, updates);\n }\n\n removePatch(patchId: string): void {\n this.ensureLoaded();\n this.lock!.patches = this.lock!.patches.filter((p) => p.id !== patchId);\n }\n\n clearPatches(): void {\n this.ensureLoaded();\n this.lock!.patches = [];\n }\n\n addForgottenHash(hash: string): void {\n this.ensureLoaded();\n if (!this.lock!.forgotten_hashes) {\n this.lock!.forgotten_hashes = [];\n }\n if (!this.lock!.forgotten_hashes.includes(hash)) {\n this.lock!.forgotten_hashes.push(hash);\n }\n }\n\n getUnresolvedPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches.filter((p) => p.status === \"unresolved\");\n }\n\n getResolvingPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches.filter((p) => p.status === \"resolving\");\n }\n\n markPatchUnresolved(patchId: string): void {\n this.updatePatch(patchId, { status: \"unresolved\" });\n }\n\n markPatchResolved(\n patchId: string,\n updates: Pick<StoredPatch, \"patch_content\" | \"content_hash\" | \"base_generation\" | \"files\" | \"theirs_snapshot\">,\n ): void {\n this.ensureLoaded();\n const patch = this.lock!.patches.find((p) => p.id === patchId);\n if (!patch) {\n throw new Error(`Patch not found: ${patchId}`);\n }\n delete patch.status;\n Object.assign(patch, updates);\n }\n\n getPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches;\n }\n\n setReplaySkippedAt(timestamp: string): void {\n this.ensureLoaded();\n this.lock!.replay_skipped_at = timestamp;\n }\n\n clearReplaySkippedAt(): void {\n this.ensureLoaded();\n delete this.lock!.replay_skipped_at;\n }\n\n isReplaySkipped(): boolean {\n this.ensureLoaded();\n return this.lock!.replay_skipped_at != null;\n }\n\n getGeneration(commitSha: string): GenerationRecord | undefined {\n this.ensureLoaded();\n return this.lock!.generations.find((g) => g.commit_sha === commitSha);\n }\n\n getCustomizationsConfig(): CustomizationsConfig {\n if (!existsSync(this.customizationsPath)) {\n return {};\n }\n const content = readFileSync(this.customizationsPath, \"utf-8\");\n return (parse(content) as CustomizationsConfig) ?? {};\n }\n\n private ensureLoaded(): void {\n if (!this.lock) {\n throw new Error(\"No lockfile loaded. Call read() or initialize() first.\");\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { isSensitiveFile } from \"./credentials.js\";\nimport { isBinaryFile } from \"./ReplayApplicator.js\";\nimport { isGenerationCommit, isRevertCommit, parseRevertedMessage, parseRevertedSha } from \"./git/CommitDetection.js\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport type { CommitInfo, GenerationLock, GenerationRecord, StoredPatch } from \"./types.js\";\n\ntype MergeCompositePatchInput = {\n mergeCommit: CommitInfo;\n firstParent: string;\n lastGen: GenerationRecord;\n lock: GenerationLock;\n};\n\n// Infrastructure files managed by the generation pipeline, not user code.\n// Changes to these should never be captured as customization patches.\nconst INFRASTRUCTURE_FILES = new Set([\".fernignore\"]);\n\n/**\n * Parse the `diff --git a/<p> b/<p>` headers out of a `git format-patch` blob\n * and classify each file as a creation (`new file mode …`), deletion\n * (`deleted file mode …`), or neither (modify / rename / chmod).\n *\n * Only handles the unquoted `a/…` `b/…` form — git quotes paths that contain\n * control characters or non-UTF-8 bytes (`\"a/weird\\tname.txt\"`), which the\n * parser skips. SDK files don't contain such characters in practice; if that\n * assumption is ever violated, quoted headers yield `currentPath = null` and\n * are silently ignored (false negative, never a false positive).\n */\nfunction parsePatchFileHeaders(patchContent: string): Array<{ path: string; isCreate: boolean; isDelete: boolean }> {\n const results: Array<{ path: string; isCreate: boolean; isDelete: boolean }> = [];\n let currentPath: string | null = null;\n let currentIsCreate = false;\n let currentIsDelete = false;\n\n const flush = () => {\n if (currentPath !== null) {\n results.push({ path: currentPath, isCreate: currentIsCreate, isDelete: currentIsDelete });\n }\n };\n\n for (const line of patchContent.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n flush();\n currentPath = null;\n currentIsCreate = false;\n currentIsDelete = false;\n // Unquoted form: \"diff --git a/<path> b/<path>\". Non-greedy matching\n // handles paths with spaces (e.g. \"sdk files/helper.py\") in the common\n // case. Pathological paths containing the literal substring \" b/\" are\n // mis-parsed; see the docstring for the safety argument (false\n // negatives are harmless, false positives are impossible).\n const match = line.match(/^diff --git a\\/(.+?) b\\/(.+?)$/);\n if (match) {\n // Track both sides — rename commits have a != b. Creations and\n // deletions always have a == b, so we record the (post-rename)\n // \"b\" path which is what `patch.files` will contain.\n currentPath = match[2] ?? null;\n }\n } else if (currentPath !== null) {\n if (line.startsWith(\"new file mode \")) {\n currentIsCreate = true;\n } else if (line.startsWith(\"deleted file mode \")) {\n currentIsDelete = true;\n }\n }\n }\n flush();\n return results;\n}\n\nexport interface DetectionResult {\n patches: StoredPatch[];\n revertedPatchIds: string[];\n}\n\nexport class ReplayDetector {\n private git: GitClient;\n private lockManager: LockfileManager;\n private sdkOutputDir: string;\n readonly warnings: string[] = [];\n\n constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.sdkOutputDir = sdkOutputDir;\n }\n\n async detectNewPatches(): Promise<DetectionResult> {\n const lock = this.lockManager.read();\n const lastGen = this.getLastGeneration(lock);\n if (!lastGen) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const exists = await this.git.commitExists(lastGen.commit_sha);\n if (!exists) {\n this.warnings.push(\n `Generation commit ${lastGen.commit_sha.slice(0, 7)} not found in git history. ` +\n `Falling back to alternate detection.`\n );\n return this.detectPatchesViaTreeDiff(lastGen, /* commitKnownMissing */ true);\n }\n\n // Non-linear history (e.g. squash merge): walk merge-base..HEAD and\n // filter generation commits per-commit, the same way the linear path\n // does. FER-10201 — the prior `detectPatchesViaTreeDiff` composite\n // shortcut had no commit awareness, so a `[fern-autoversion]` step\n // subsumed by a squash-merge would surface as a \"customer\n // customization\" with the placeholder→semver swap baked in.\n const isAncestor = await this.git.isAncestor(lastGen.commit_sha, \"HEAD\");\n if (!isAncestor) {\n return this.detectPatchesViaMergeBase(lastGen, lock);\n }\n\n return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);\n }\n\n /**\n * FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.\n *\n * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous\n * `[fern-generated]`) is orphaned but still in git's object database. The\n * merge-base is the commit on main from which the bot's branch was created —\n * a reachable ancestor of HEAD. Walking that range and classifying each\n * commit via `isGenerationCommit` mirrors the linear path and eliminates\n * the bug class where pipeline-driven changes (autoversion, replay,\n * generation) get bundled as customer customizations.\n *\n * Falls through to the legacy composite path when no common ancestor exists\n * (truly disjoint history — orphan branches with no shared root).\n */\n private async detectPatchesViaMergeBase(\n lastGen: GenerationRecord,\n lock: GenerationLock,\n ): Promise<DetectionResult> {\n let mergeBase = \"\";\n try {\n mergeBase = (\n await this.git.exec([\"merge-base\", lastGen.commit_sha, \"HEAD\"])\n ).trim();\n } catch {\n // `git merge-base` exits non-zero when there's no common ancestor.\n }\n if (!mergeBase) {\n this.warnings.push(\n `No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. ` +\n `Falling back to composite tree-diff detection.`\n );\n return this.detectPatchesViaTreeDiff(lastGen, /* commitKnownMissing */ false);\n }\n return this.detectPatchesInRange(mergeBase, lastGen, lock);\n }\n\n /**\n * FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one\n * `StoredPatch` per customer commit. Body shared by the linear path\n * (rangeStart = lastGen.commit_sha) and the merge-base path.\n *\n * Patch `base_generation` is always `lastGen.commit_sha` — the\n * lockfile-tracked reference the applicator uses to fetch base file\n * content, regardless of where the walk actually started.\n */\n private async detectPatchesInRange(\n rangeStart: string,\n lastGen: GenerationRecord,\n lock: GenerationLock,\n ): Promise<DetectionResult> {\n const log = await this.git.exec([\n \"log\",\n \"--first-parent\",\n \"--format=%H%x00%an%x00%ae%x00%s\",\n `${rangeStart}..HEAD`,\n \"--\",\n this.sdkOutputDir\n ]);\n\n if (!log.trim()) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const commits = this.parseGitLog(log);\n const newPatches: StoredPatch[] = [];\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n\n for (const commit of commits) {\n if (isGenerationCommit(commit)) {\n continue;\n }\n\n if (lock.patches.find((p) => p.original_commit === commit.sha)) {\n continue;\n }\n\n const parents = await this.git.getCommitParents(commit.sha);\n\n if (parents.length > 1) {\n // Merge commit: produce a single composite patch via tree diff\n const compositePatch = await this.createMergeCompositePatch({\n mergeCommit: commit,\n firstParent: parents[0]!,\n lastGen,\n lock,\n });\n if (compositePatch) {\n newPatches.push(compositePatch);\n }\n continue;\n }\n\n let patchContent: string;\n try {\n patchContent = await this.git.formatPatch(commit.sha);\n } catch {\n this.warnings.push(\n `Could not generate patch for commit ${commit.sha.slice(0, 7)} — ` +\n `it may be unreachable in a shallow clone. Skipping.`\n );\n continue;\n }\n\n let contentHash = this.computeContentHash(patchContent);\n if (lock.patches.find((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n\n const allFiles = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n // .fern/ is managed by the replay system itself, not by the user.\n // Matching the filter in detectPatchesViaTreeDiff + createMergeCompositePatch\n // so the three detection paths agree.\n .filter((f) => !f.startsWith(\".fern/\"));\n\n const sensitiveFiles = allFiles.filter((f) => isSensitiveFile(f));\n const files = allFiles.filter((f) => !isSensitiveFile(f));\n\n if (sensitiveFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from patch for commit ${commit.sha.slice(0, 7)}: ` +\n `${sensitiveFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n\n // Regenerate patch content scoped to non-sensitive files only.\n // Recompute content hash to match the actual stored content.\n if (files.length > 0) {\n const parentSha = parents[0];\n if (parentSha) {\n try {\n patchContent = await this.git.exec([\"diff\", parentSha, commit.sha, \"--\", ...files]);\n } catch {\n continue;\n }\n if (!patchContent.trim()) continue;\n contentHash = this.computeContentHash(patchContent);\n }\n }\n }\n\n // Skip patches that only touch infrastructure/sensitive files\n if (files.length === 0) {\n continue;\n }\n\n // Snapshot THEIRS from the customer's commit tree (post-edit content).\n const theirsSnapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(commit.sha, file).catch(() => null);\n if (content != null) theirsSnapshot[file] = content;\n }\n\n newPatches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: lastGen.commit_sha,\n files,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(patchContent) ? { user_owned: true } : {})\n });\n }\n\n // FER-9805 — collapse zero-net-change files on the linear path.\n // On merge commits, createMergeCompositePatch already diffs\n // firstParent..mergeCommit so transient files net out naturally. On\n // linear history each commit becomes its own patch, so a file\n // created in commit A and deleted in commit B survives as two\n // patches whose cumulative diff is empty. This filter drops such\n // patches before they reach the lockfile — also closing the\n // linear-path half of FER-9807 (a committed-then-deleted .env or\n // .pem would otherwise leak its contents verbatim into replay.lock).\n const survivingPatches = await this.collapseNetZeroFiles(newPatches);\n\n // Reverse so patches apply in chronological order (oldest first)\n survivingPatches.reverse();\n\n // Reconcile revert commits: match against existing and newly-detected patches.\n // Uses a Set for revertedPatchIds to avoid duplicate counting when multiple\n // reverts target the same patch.\n const revertedPatchIdSet = new Set<string>();\n const revertIndicesToRemove = new Set<number>();\n\n for (let i = 0; i < survivingPatches.length; i++) {\n const patch = survivingPatches[i]!;\n if (!isRevertCommit(patch.original_message)) continue;\n\n // Get full commit body for SHA extraction. May fail in shallow clones\n // or if the commit was GC'd — fall back to message-only matching.\n let body = \"\";\n try {\n body = await this.git.getCommitBody(patch.original_commit);\n } catch {\n // Shallow clone or unreachable commit — message matching only\n }\n const revertedSha = parseRevertedSha(body);\n const revertedMessage = parseRevertedMessage(patch.original_message);\n\n // Try to match against existing lockfile patches\n let matchedExisting = false;\n if (revertedSha) {\n const existing = lock.patches.find((p) => p.original_commit === revertedSha);\n if (existing) {\n revertedPatchIdSet.add(existing.id);\n revertIndicesToRemove.add(i);\n matchedExisting = true;\n }\n }\n if (!matchedExisting && revertedMessage) {\n const existing = lock.patches.find((p) => p.original_message === revertedMessage);\n if (existing) {\n revertedPatchIdSet.add(existing.id);\n revertIndicesToRemove.add(i);\n matchedExisting = true;\n }\n }\n\n if (matchedExisting) continue;\n\n // Try to match against newly-detected patches in the same run\n let matchedNew = false;\n if (revertedSha) {\n const idx = survivingPatches.findIndex(\n (p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_commit === revertedSha\n );\n if (idx !== -1) {\n revertIndicesToRemove.add(i);\n revertIndicesToRemove.add(idx);\n matchedNew = true;\n }\n }\n if (!matchedNew && revertedMessage) {\n const idx = survivingPatches.findIndex(\n (p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_message === revertedMessage\n );\n if (idx !== -1) {\n revertIndicesToRemove.add(i);\n revertIndicesToRemove.add(idx);\n }\n }\n\n // Unmatched revert: the original commit predates replay (e.g. .fernignore era).\n // A revert is never a customization — drop it so it doesn't become a patch.\n if (!matchedExisting && !matchedNew) {\n revertIndicesToRemove.add(i);\n }\n }\n\n const filteredPatches = survivingPatches.filter((_, i) => !revertIndicesToRemove.has(i));\n return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };\n }\n\n /**\n * Compute content hash for deduplication.\n *\n * Produces a format-agnostic hash so both `git format-patch` output\n * (email-wrapped) and plain `git diff` output hash to the same value\n * when the underlying diff hunks are identical.\n *\n * Normalization:\n * 1. Strip email wrapper: everything before the first `diff --git` line\n * (From:, Subject:, Date:, diffstat, blank separators).\n * 2. Strip `index` lines (blob SHA pairs change across rebases).\n * 3. Strip trailing git version marker (`-- \\n<version>`).\n *\n * This ensures content hashes match across the no-patches and normal-\n * regeneration flows, which store formatPatch and git-diff formats\n * respectively (FER-9850, D5-D9).\n */\n computeContentHash(patchContent: string): string {\n const lines = patchContent.split(\"\\n\");\n\n // Strip email wrapper: everything before the first 'diff --git'\n const diffStart = lines.findIndex((l) => l.startsWith(\"diff --git \"));\n const relevantLines = diffStart > 0 ? lines.slice(diffStart) : lines;\n\n const normalized = relevantLines\n .filter((line) => !line.startsWith(\"index \"))\n .join(\"\\n\")\n // Strip trailing git version marker (\"-- \\n2.x.x\")\n .replace(/\\n-- \\n[\\d]+\\.[\\d]+[^\\n]*\\s*$/, \"\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\n }\n\n /**\n * FER-9805 — Drop patches whose files were transiently created and then\n * deleted within the current linear detection window, and are absent from\n * HEAD at the end of the window.\n *\n * Rationale: on a merge commit, createMergeCompositePatch already diffs\n * firstParent..mergeCommit so net-zero files never enter the composite. On\n * linear history each commit becomes its own patch, so a file that was\n * briefly added and later removed survives as a create+delete pair whose\n * cumulative diff is empty. We drop such patches before they reach the\n * lockfile.\n *\n * A file is \"transient\" when:\n * 1. some patch in the window sets `new file mode` for it (a creation), AND\n * 2. some patch in the window sets `deleted file mode` for it (a deletion), AND\n * 3. it is absent from HEAD's tree.\n *\n * The HEAD guard (#3) prevents false positives when a file is deleted\n * and then recreated with different content — the cumulative diff of\n * such a pair is non-empty and must be preserved.\n *\n * This only drops patches whose `files` are a subset of the transient\n * set. A partial-transient patch (one that touches a transient file\n * alongside a persistent one) is left unmodified; surgical stripping of\n * single files from a multi-file patch would require a follow-up that\n * regenerates the patch content via `git format-patch -- <files>`. No\n * current failing test exercises this, and leaving the patch intact\n * preserves today's behaviour. TODO(FER-9805): revisit if a future\n * adversarial test demands per-file stripping.\n */\n private async collapseNetZeroFiles(patches: StoredPatch[]): Promise<StoredPatch[]> {\n if (patches.length === 0) return patches;\n\n type FileState = { created: boolean; deleted: boolean };\n const stateByFile = new Map<string, FileState>();\n\n for (const patch of patches) {\n for (const header of parsePatchFileHeaders(patch.patch_content)) {\n if (!header.isCreate && !header.isDelete) continue;\n const prior = stateByFile.get(header.path) ?? { created: false, deleted: false };\n if (header.isCreate) prior.created = true;\n if (header.isDelete) prior.deleted = true;\n stateByFile.set(header.path, prior);\n }\n }\n\n // No file has both a create and a delete event in the window → nothing to collapse.\n let anyCandidate = false;\n for (const state of stateByFile.values()) {\n if (state.created && state.deleted) { anyCandidate = true; break; }\n }\n if (!anyCandidate) return patches;\n\n const headFiles = await this.listHeadFiles();\n\n const transient = new Set<string>();\n for (const [file, state] of stateByFile) {\n if (state.created && state.deleted && !headFiles.has(file)) {\n transient.add(file);\n }\n }\n\n if (transient.size === 0) return patches;\n\n return patches.filter((patch) => !patch.files.every((f) => transient.has(f)));\n }\n\n /**\n * List every tracked path at HEAD (one `git ls-tree -r` invocation).\n * Returns an empty Set if HEAD is unborn or the invocation fails — the\n * caller then treats every candidate as \"not in HEAD\" and may collapse\n * more aggressively. On typical SDK repos this is a single sub-10ms call.\n */\n private async listHeadFiles(): Promise<Set<string>> {\n try {\n const out = await this.git.exec([\"ls-tree\", \"-r\", \"--name-only\", \"HEAD\"]);\n return new Set(out.split(\"\\n\").map((l) => l.trim()).filter(Boolean));\n } catch {\n return new Set();\n }\n }\n\n /**\n * Create a single composite patch for a merge commit by diffing the merge\n * commit against its first parent. This captures the net change of the\n * entire merged branch as one patch, eliminating accumulator chaining and\n * zero-net-change ghost conflicts.\n */\n private async createMergeCompositePatch(\n input: MergeCompositePatchInput\n ): Promise<StoredPatch | null> {\n const { mergeCommit, firstParent, lastGen, lock } = input;\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n\n // Diff first parent against merge commit to get net change of the branch\n const filesOutput = await this.git.exec([\n \"diff\", \"--name-only\", firstParent, mergeCommit.sha\n ]);\n const allMergeFiles = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n .filter((f) => !f.startsWith(\".fern/\"));\n\n const sensitiveMergeFiles = allMergeFiles.filter((f) => isSensitiveFile(f));\n const files = allMergeFiles.filter((f) => !isSensitiveFile(f));\n\n if (sensitiveMergeFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from merge patch for commit ${mergeCommit.sha.slice(0, 7)}: ` +\n `${sensitiveMergeFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n }\n\n if (files.length === 0) return null;\n\n const diff = await this.git.exec([\n \"diff\", firstParent, mergeCommit.sha, \"--\", ...files\n ]);\n if (!diff.trim()) return null;\n\n const contentHash = this.computeContentHash(diff);\n if (lock.patches.some((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {\n return null;\n }\n\n // Snapshot THEIRS from the merge commit's tree (post-merge content).\n const theirsSnapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(mergeCommit.sha, file).catch(() => null);\n if (content != null) theirsSnapshot[file] = content;\n }\n\n return {\n id: `patch-merge-${mergeCommit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: mergeCommit.sha,\n original_message: mergeCommit.message,\n original_author: `${mergeCommit.authorName} <${mergeCommit.authorEmail}>`,\n base_generation: lastGen.commit_sha,\n files,\n patch_content: diff,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(diff) ? { user_owned: true } : {})\n };\n }\n\n /**\n * Detect patches via tree diff for non-linear history. Returns a composite patch.\n * Revert reconciliation is skipped here because tree-diff produces a single composite\n * patch from the aggregate diff — individual revert commits are not distinguishable.\n */\n private async detectPatchesViaTreeDiff(\n lastGen: GenerationRecord,\n commitKnownMissing: boolean\n ): Promise<DetectionResult> {\n // Use commit_sha if reachable, fall back to tree_hash for unreachable commits.\n // git diff accepts both commit and tree objects as arguments.\n const diffBase = await this.resolveDiffBase(lastGen, commitKnownMissing);\n if (!diffBase) {\n // Both commit and tree are gone (aggressive GC). Fall back to scanning\n // all commits from HEAD and filtering against known lockfile patches.\n return this.detectPatchesViaCommitScan();\n }\n\n // Get changed files first, then filter before computing the diff\n const filesOutput = await this.git.exec([\"diff\", \"--name-only\", diffBase, \"HEAD\"]);\n const allTreeFiles = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n .filter((f) => !f.startsWith(\".fern/\"));\n\n const sensitiveTreeFiles = allTreeFiles.filter((f) => isSensitiveFile(f));\n const files = allTreeFiles.filter((f) => !isSensitiveFile(f));\n\n if (sensitiveTreeFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from composite patch: ` +\n `${sensitiveTreeFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n }\n\n if (files.length === 0) return { patches: [], revertedPatchIds: [] };\n\n // Compute diff only for the filtered files\n const diff = await this.git.exec([\"diff\", diffBase, \"HEAD\", \"--\", ...files]);\n if (!diff.trim()) return { patches: [], revertedPatchIds: [] };\n\n const contentHash = this.computeContentHash(diff);\n\n // Dedup against existing patches and forgotten hashes — if an existing patch\n // already captures this content, or it was explicitly forgotten, skip it.\n const lock = this.lockManager.read();\n if (lock.patches.some((p) => p.content_hash === contentHash) || (lock.forgotten_hashes ?? []).includes(contentHash)) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const headSha = (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n\n // Snapshot THEIRS from HEAD (the diff is diffBase → HEAD).\n const theirsSnapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(\"HEAD\", file).catch(() => null);\n if (content != null) theirsSnapshot[file] = content;\n }\n\n const compositePatch: StoredPatch = {\n id: `patch-composite-${headSha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: headSha,\n original_message: \"Customer customizations (composite)\",\n original_author: \"composite\",\n // Use diffBase when commit is unreachable — the applicator needs a reachable\n // reference to find base file content. diffBase may be the tree_hash.\n base_generation: commitKnownMissing ? diffBase : lastGen.commit_sha,\n files,\n patch_content: diff,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(diff) ? { user_owned: true } : {})\n };\n\n return { patches: [compositePatch], revertedPatchIds: [] };\n }\n\n /**\n * Last-resort detection when both generation commit and tree are unreachable.\n * Scans all commits from HEAD, filters against known lockfile patches, and\n * skips creation-only commits (squashed history after force push).\n *\n * Detected patches use the commit's parent as base_generation so the applicator\n * can find base file content from the parent's tree (which IS reachable).\n */\n private async detectPatchesViaCommitScan(): Promise<DetectionResult> {\n const lock = this.lockManager.read();\n const log = await this.git.exec([\n \"log\",\n \"--max-count=200\",\n \"--format=%H%x00%an%x00%ae%x00%s\",\n \"HEAD\",\n \"--\",\n this.sdkOutputDir\n ]);\n\n if (!log.trim()) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const commits = this.parseGitLog(log);\n const newPatches: StoredPatch[] = [];\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n const existingHashes = new Set(lock.patches.map((p) => p.content_hash));\n const existingCommits = new Set(lock.patches.map((p) => p.original_commit));\n\n for (const commit of commits) {\n if (isGenerationCommit(commit)) {\n continue;\n }\n\n const parents = await this.git.getCommitParents(commit.sha);\n if (parents.length > 1) {\n continue;\n }\n\n if (existingCommits.has(commit.sha)) {\n continue;\n }\n\n let patchContent: string;\n try {\n patchContent = await this.git.formatPatch(commit.sha);\n } catch {\n continue;\n }\n\n let contentHash = this.computeContentHash(patchContent);\n if (existingHashes.has(contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n // Skip creation-only commits (all diffs are new-file additions).\n // After force push, squashed commits create all files from scratch — these\n // aren't user customizations, they're history-rewriting artifacts.\n if (this.isCreationOnlyPatch(patchContent)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n const allScanFiles = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f));\n\n const sensitiveScanFiles = allScanFiles.filter((f) => isSensitiveFile(f));\n const files = allScanFiles.filter((f) => !isSensitiveFile(f));\n\n if (sensitiveScanFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from patch for commit ${commit.sha.slice(0, 7)}: ` +\n `${sensitiveScanFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n\n // Regenerate patch content scoped to non-sensitive files only.\n // Recompute content hash to match the actual stored content.\n if (files.length > 0) {\n if (parents.length === 0) {\n continue;\n }\n try {\n patchContent = await this.git.exec([\"diff\", parents[0]!, commit.sha, \"--\", ...files]);\n } catch {\n continue;\n }\n if (!patchContent.trim()) continue;\n contentHash = this.computeContentHash(patchContent);\n }\n }\n\n if (files.length === 0) {\n continue;\n }\n\n // Use the parent commit as base_generation so the applicator can find\n // base file content from the parent's tree (which IS reachable).\n // Root commits (no parents) can't use this strategy — skip them.\n if (parents.length === 0) {\n continue;\n }\n const parentSha = parents[0]!;\n\n // Note: user_owned is not tagged here because `isCreationOnlyPatch`\n // already short-circuits creation-only patches above. Any patch that\n // reaches this push is by definition NOT creation-only. Per-file\n // tree/patch_content fallbacks in `ReplayService.isFileUserOwned`\n // handle classification downstream.\n const theirsSnapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(commit.sha, file).catch(() => null);\n if (content != null) theirsSnapshot[file] = content;\n }\n newPatches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: parentSha,\n files,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {})\n });\n }\n\n newPatches.reverse();\n return { patches: newPatches, revertedPatchIds: [] };\n }\n\n /**\n * Check if a format-patch consists entirely of new-file creations.\n * Used to identify squashed commits after force push, which create all files\n * from scratch (--- /dev/null) rather than modifying existing files.\n */\n private isCreationOnlyPatch(patchContent: string): boolean {\n const diffOldHeaders = patchContent.split(\"\\n\").filter((l) => l.startsWith(\"--- \"));\n if (diffOldHeaders.length === 0) {\n return false;\n }\n return diffOldHeaders.every((l) => l === \"--- /dev/null\");\n }\n\n /**\n * Resolve the best available diff base for a generation record.\n * Prefers commit_sha, falls back to tree_hash for unreachable commits.\n * When commitKnownMissing is true, skips the redundant commitExists check.\n */\n private async resolveDiffBase(gen: GenerationRecord, commitKnownMissing: boolean): Promise<string | null> {\n if (!commitKnownMissing && await this.git.commitExists(gen.commit_sha)) {\n return gen.commit_sha;\n }\n if (await this.git.treeExists(gen.tree_hash)) {\n return gen.tree_hash;\n }\n return null;\n }\n\n private parseGitLog(log: string): CommitInfo[] {\n return log\n .trim()\n .split(\"\\n\")\n .map((line) => {\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n });\n }\n\n private getLastGeneration(lock: GenerationLock) {\n return lock.generations.find((g) => g.commit_sha === lock.current_generation);\n }\n}\n","import { mkdir, mkdtemp, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, extname, join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { stripConflictMarkers } from \"./conflict-utils.js\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport { threeWayMerge } from \"./ThreeWayMerge.js\";\nimport type {\n ConflictMetadata,\n ConflictReason,\n FileResult,\n GenerationRecord,\n ReplayResult,\n StoredPatch\n} from \"./types.js\";\n\nconst BINARY_EXTENSIONS = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".bmp\",\n \".ico\",\n \".webp\",\n \".svg\",\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".zip\",\n \".gz\",\n \".tar\",\n \".bz2\",\n \".7z\",\n \".rar\",\n \".jar\",\n \".war\",\n \".ear\",\n \".class\",\n \".exe\",\n \".dll\",\n \".so\",\n \".dylib\",\n \".o\",\n \".a\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".otf\",\n \".mp3\",\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wav\",\n \".flac\",\n \".sqlite\",\n \".db\",\n \".pyc\",\n \".pyo\",\n \".DS_Store\"\n]);\n\nexport class ReplayApplicator {\n private git: GitClient;\n private lockManager: LockfileManager;\n private outputDir: string;\n private renameCache = new Map<string, Array<{ from: string; to: string }>>();\n private treeExistsCache = new Map<string, boolean>();\n private fileTheirsAccumulator = new Map<\n string,\n {\n content: string;\n baseGeneration: string;\n }\n >();\n\n /**\n * Apply mode for the current `applyPatches` invocation. Set at the start\n * of `applyPatches`, read by `mergeFile` to decide:\n * - whether to skip the intra-loop marker strip (kept in `applyPatches`)\n * - whether to populate the accumulator after a conflicted merge\n * (resolve mode populates so subsequent patches on the same file\n * can use patch A's THEIRS as a structurally-correct merge base\n * when their diff was authored against post-A structure)\n * - whether to retry THEIRS reconstruction against the accumulator\n * when the BASE-relative reconstruction produced markers from a\n * cross-patch context mismatch\n */\n private currentApplyMode: \"replay\" | \"resolve\" = \"replay\";\n\n /**\n * Set of files that appear in 2+ patches in the current `applyPatches`\n * invocation. Computed at the top of `applyPatches`. Read by `mergeFile`\n * and `populateAccumulatorForPatch` to decide whether to use the patch's\n * `theirs_snapshot` directly as THEIRS (snapshot-as-primary) or fall\n * back to line-anchored reconstruction (FER-9525 cross-patch isolation).\n *\n * Snapshot-as-primary is correct when the patch owns its file (no other\n * patch in this run touches it): the snapshot is what the customer\n * intends for that file post-regen, regardless of generator structural\n * changes that would invalidate the diff's line anchors.\n *\n * When a file IS shared, snapshots are CUMULATIVE across the patches\n * touching it (each one's snapshot includes prior patches' contributions).\n * Using a later patch's cumulative snapshot as its individual THEIRS\n * would propagate prior patches' edits into the merge — surfacing nested\n * conflicts at regions the patch alone never touched. Reconstruction\n * via `applyPatchToContent` is required there.\n */\n private sharedFiles = new Set<string>();\n\n constructor(git: GitClient, lockManager: LockfileManager, outputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.outputDir = outputDir;\n }\n\n /**\n * Resolve the GenerationRecord for a patch's base_generation.\n * Falls back to constructing an ad-hoc record from the commit's tree\n * when base_generation isn't a tracked generation (commit-scan patches).\n */\n private async resolveBaseGeneration(baseGeneration: string): Promise<GenerationRecord | undefined> {\n const gen = this.lockManager.getGeneration(baseGeneration);\n if (gen) return gen;\n try {\n const treeHash = await this.git.getTreeHash(baseGeneration);\n return {\n commit_sha: baseGeneration,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: \"unknown\",\n generator_versions: {}\n };\n } catch {\n return undefined;\n }\n }\n\n /** Reset inter-patch accumulator for a new cycle. */\n private resetAccumulator(): void {\n this.fileTheirsAccumulator.clear();\n }\n\n /**\n * @internal Test-only.\n * Returns a defensive copy of the inter-patch accumulator. Used by the\n * adversarial test suite (FER-9791) to assert invariant I2: after every\n * applied patch, the accumulator has an entry for each file the patch\n * touched, and the entry's content matches on-disk.\n */\n getAccumulatorSnapshot(): ReadonlyMap<string, { content: string; baseGeneration: string }> {\n const snapshot = new Map<string, { content: string; baseGeneration: string }>();\n for (const [path, entry] of this.fileTheirsAccumulator) {\n snapshot.set(path, { content: entry.content, baseGeneration: entry.baseGeneration });\n }\n return snapshot;\n }\n\n /**\n * Apply all patches, returning results for each.\n * Skips patches that match exclude patterns in replay.yml\n *\n * `applyMode` controls the post-conflict marker strategy:\n * - `\"replay\"` (default): strip conflict markers from disk between\n * iterations whenever a later patch touches the same file. Lets the\n * follow-up patch's `git apply --3way` see clean OURS content,\n * which is what the silent-loss fix (PR #73) relies on. The replay\n * pipeline calls `revertConflictingFiles` after the loop to clean\n * any markers that survive.\n * - `\"resolve\"`: keep markers on disk. The resolve command needs the\n * customer to see them. Slow-path 3-way merge naturally preserves\n * A's markers and B's clean writes when their regions don't overlap;\n * when they do overlap, the customer gets nested markers and\n * resolves manually. Either way they aren't silently dropped.\n */\n async applyPatches(\n patches: StoredPatch[],\n opts?: { applyMode?: \"replay\" | \"resolve\" }\n ): Promise<ReplayResult[]> {\n const applyMode = opts?.applyMode ?? \"replay\";\n this.currentApplyMode = applyMode;\n this.resetAccumulator(); // Clear accumulator for this apply cycle\n\n // Compute set of files shared by 2+ patches in this run. Used to\n // gate snapshot-as-primary in mergeFile/populateAccumulatorForPatch.\n // See `sharedFiles` field doc for the FER-9525 rationale.\n const fileFreq = new Map<string, number>();\n for (const p of patches) {\n for (const f of p.files) {\n fileFreq.set(f, (fileFreq.get(f) ?? 0) + 1);\n }\n }\n this.sharedFiles = new Set(\n Array.from(fileFreq.entries())\n .filter(([, n]) => n > 1)\n .map(([f]) => f)\n );\n\n const results: ReplayResult[] = [];\n\n for (let i = 0; i < patches.length; i++) {\n const patch = patches[i]!;\n\n if (this.isExcluded(patch)) {\n results.push({\n patch,\n status: \"skipped\",\n method: \"git-am\"\n });\n continue;\n }\n\n const result = await this.applyPatchWithFallback(patch);\n results.push(result);\n\n // Strip conflict markers from files that a later patch will also\n // touch. This prevents marker cascade into the next patch's OURS\n // while preserving markers on files only this patch touches (needed\n // by the resolve workflow for user resolution). Only fires in\n // replay mode — resolve mode keeps markers on disk so the customer\n // can see and edit them.\n if (applyMode !== \"resolve\" && result.status === \"conflict\" && result.fileResults) {\n // Later patches list original (pre-rename) paths in their files array.\n const laterFiles = new Set<string>();\n for (let j = i + 1; j < patches.length; j++) {\n for (const f of patches[j]!.files) {\n laterFiles.add(f);\n }\n }\n\n // Build reverse rename map: resolved path → original path.\n // fileResult.file is the resolved path, but laterFiles has originals.\n const resolvedToOriginal = new Map<string, string>();\n if (result.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(result.resolvedFiles)) {\n resolvedToOriginal.set(resolved, orig);\n }\n }\n\n for (const fileResult of result.fileResults) {\n if (fileResult.status !== \"conflict\") continue;\n // Check both resolved and original paths against later patches\n const originalPath = resolvedToOriginal.get(fileResult.file) ?? fileResult.file;\n if (laterFiles.has(fileResult.file) || laterFiles.has(originalPath)) {\n const filePath = join(this.outputDir, fileResult.file);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const stripped = stripConflictMarkers(content);\n await writeFile(filePath, stripped);\n } catch {\n // File doesn't exist or can't be read — skip\n }\n }\n }\n }\n }\n\n return results;\n }\n\n /**\n * Populate accumulator after git apply succeeds, AND collect per-file\n * results including any \"dropped context lines\" — lines that were\n * present in BASE and THEIRS (unchanged context) but absent from the\n * final on-disk state because OURS deleted them. This is the fast-path\n * counterpart to ThreeWayMerge.computeDroppedContextLines used by the\n * 3-way slow path; both must surface the same warning.\n */\n private async populateAccumulatorForPatch(\n patch: StoredPatch,\n baseGen: GenerationRecord | undefined,\n currentTreeHash: string\n ): Promise<FileResult[]> {\n const fileResults: FileResult[] = [];\n if (!baseGen) return fileResults;\n\n // Create temp git repo to apply patches to base content\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-acc-\"));\n const { GitClient } = await import(\"./git/GitClient.js\");\n const tempGit = new GitClient(tempDir);\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"replay@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay\"]);\n\n try {\n for (const filePath of patch.files) {\n if (isBinaryFile(filePath)) continue;\n\n const resolvedPath = await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);\n\n const base = await this.git.showFile(baseGen.tree_hash, filePath);\n\n // For non-shared-file patches, the stored snapshot IS this\n // patch's THEIRS for the accumulator (individual contribution\n // by definition: only this patch touches the file). Skip\n // reconstruction. For shared-file patches, fall back to\n // line-anchored reconstruction so the accumulator entry is\n // each patch's INDIVIDUAL contribution (FER-9525 cross-patch\n // isolation). See `mergeFile` for the full rationale.\n const snapshotForFile =\n patch.theirs_snapshot?.[resolvedPath] ?? patch.theirs_snapshot?.[filePath];\n const fileIsShared =\n this.sharedFiles.has(resolvedPath) || this.sharedFiles.has(filePath);\n const theirs = !fileIsShared && snapshotForFile != null\n ? snapshotForFile\n : await this.applyPatchToContent(base, patch.patch_content, filePath, tempGit, tempDir);\n\n // For user-created files (base=null), applyPatchToContent may return null\n // for modification diffs. Fall back to reading the on-disk content that\n // git apply --3way just wrote successfully.\n const finalOnDisk = await readFile(join(this.outputDir, resolvedPath), \"utf-8\").catch(() => null);\n const effectiveTheirs = theirs ?? finalOnDisk;\n if (effectiveTheirs != null) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: effectiveTheirs,\n baseGeneration: patch.base_generation\n });\n }\n\n // Detect lines that were in BOTH base and theirs but absent\n // from the final on-disk state — silently dropped by OURS.\n if (base != null && effectiveTheirs != null && finalOnDisk != null) {\n const dropped = computeDroppedContextLinesForFile(base, effectiveTheirs, finalOnDisk);\n if (dropped.length > 0) {\n fileResults.push({\n file: resolvedPath,\n status: \"merged\",\n droppedContextLines: dropped\n });\n }\n }\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\n return fileResults;\n }\n\n private async applyPatchWithFallback(patch: StoredPatch): Promise<ReplayResult> {\n // Resolve all file paths to check accumulator (need baseGen for resolution)\n const baseGen = await this.resolveBaseGeneration(patch.base_generation);\n const lock = this.lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n const currentTreeHash = currentGen?.tree_hash ?? baseGen?.tree_hash ?? \"\";\n\n // Check if any file in this patch needs accumulation\n // If so, skip fast path to ensure we benefit from pre-merge logic\n const needsAccumulation = await Promise.all(\n patch.files.map(async (f) => {\n if (!baseGen) return false;\n const resolved = await this.resolveFilePath(f, baseGen.tree_hash, currentTreeHash);\n return this.fileTheirsAccumulator.has(resolved);\n })\n ).then((results) => results.some(Boolean));\n\n // Pre-compute resolved paths. If the tree-level rename/copy detection says\n // a file moved but the patch content itself doesn't describe the rename,\n // this is a GENERATOR rename and the git-apply fast path is unsafe: it would\n // apply the content diff against the original path (even if still on disk)\n // rather than the resolved new path. The 3-way merge path uses `resolvedPath`\n // for OURS and for the output write, so it handles this correctly.\n //\n // USER renames (patch contains `rename from`/`rename to` headers) go through\n // the fast path because git apply handles those natively — skipping the fast\n // path there would break user-rename scenarios.\n const resolvedFiles: Record<string, string> = {};\n for (const filePath of patch.files) {\n const resolvedPath = baseGen\n ? await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash)\n : filePath;\n if (resolvedPath !== filePath) {\n resolvedFiles[filePath] = resolvedPath;\n }\n }\n const patchIsRenameAware = /^rename from /m.test(patch.patch_content);\n const hasGeneratorRename = Object.keys(resolvedFiles).length > 0 && !patchIsRenameAware;\n\n // Strategy 1: Try git apply --3way (skip if accumulation needed or a generator rename was detected)\n if (!needsAccumulation && !hasGeneratorRename) {\n // Snapshot files before git apply (may leave conflict markers on failure)\n const snapshots = new Map<string, string | null>();\n for (const filePath of patch.files) {\n const fullPath = join(this.outputDir, filePath);\n snapshots.set(filePath, await readFile(fullPath, \"utf-8\").catch(() => null));\n }\n\n try {\n await this.git.execWithInput([\"apply\", \"--3way\"], patch.patch_content);\n\n // Success! Populate accumulator so subsequent patches on these files\n // will skip fast path and use the pre-merge logic instead.\n // Also collect per-file results (notably droppedContextLines).\n const fastPathFileResults = await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);\n\n return {\n patch,\n status: \"applied\",\n method: \"git-am\",\n ...(fastPathFileResults.length > 0 && { fileResults: fastPathFileResults }),\n ...(Object.keys(resolvedFiles).length > 0 && { resolvedFiles })\n };\n } catch {\n // git apply --3way failed and may have left conflict markers on disk\n // Restore files from snapshot to undo any corruption before fallback\n for (const [filePath, content] of snapshots) {\n const fullPath = join(this.outputDir, filePath);\n if (content != null) {\n await writeFile(fullPath, content);\n } else {\n // Delete files created by the failed git apply that didn't exist before\n await unlink(fullPath).catch(() => {});\n }\n }\n }\n }\n\n // Strategy 2: Fall back to file-by-file 3-way merge (uses accumulator)\n return this.applyWithThreeWayMerge(patch);\n }\n\n private async applyWithThreeWayMerge(patch: StoredPatch): Promise<ReplayResult> {\n const fileResults: FileResult[] = [];\n const resolvedFiles: Record<string, string> = {};\n\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-\"));\n const { GitClient } = await import(\"./git/GitClient.js\");\n const tempGit = new GitClient(tempDir);\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"replay@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay\"]);\n\n try {\n for (const filePath of patch.files) {\n if (isBinaryFile(filePath)) {\n fileResults.push({\n file: filePath,\n status: \"skipped\",\n reason: \"binary-file\"\n });\n continue;\n }\n const result = await this.mergeFile(patch, filePath, tempGit, tempDir);\n if (result.file !== filePath) {\n resolvedFiles[filePath] = result.file;\n }\n fileResults.push(result);\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\n\n const conflictFiles = fileResults.filter((r) => r.status === \"conflict\");\n const hasConflicts = conflictFiles.length > 0;\n\n // Aggregate conflict reason from file-level to patch-level\n const conflictReason: ConflictReason | undefined = hasConflicts\n ? conflictFiles.some((f) => f.conflictReason === \"base-generation-mismatch\")\n ? \"base-generation-mismatch\"\n : conflictFiles[0]?.conflictReason\n : undefined;\n\n return {\n patch,\n status: hasConflicts ? \"conflict\" : \"applied\",\n method: \"3way-merge\",\n fileResults,\n conflictReason,\n ...(Object.keys(resolvedFiles).length > 0 && { resolvedFiles })\n };\n }\n\n private async mergeFile(\n patch: StoredPatch,\n filePath: string,\n tempGit: GitClient,\n tempDir: string\n ): Promise<FileResult> {\n try {\n const baseGen = await this.resolveBaseGeneration(patch.base_generation);\n if (!baseGen) {\n return { file: filePath, status: \"skipped\", reason: \"base-generation-not-found\" };\n }\n\n // Resolve file path in case the generator renamed it between generations\n const lock = this.lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n const currentTreeHash = currentGen?.tree_hash ?? baseGen.tree_hash;\n const resolvedPath = await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);\n\n // Build conflict metadata for this file (used if conflict occurs)\n const metadata: ConflictMetadata = {\n patchId: patch.id,\n patchMessage: patch.original_message,\n baseGeneration: patch.base_generation,\n currentGeneration: lock.current_generation\n };\n\n // BASE: pristine state from when user made their edit (old path)\n let base = await this.git.showFile(baseGen.tree_hash, filePath);\n\n // If BASE is null, check if this file is the target of a rename in the patch.\n // Rename diffs (e.g., git mv old new) have the content at the old path.\n let renameSourcePath: string | undefined;\n if (!base) {\n const renameSource = this.extractRenameSource(patch.patch_content, filePath);\n if (renameSource) {\n base = await this.git.showFile(baseGen.tree_hash, renameSource);\n renameSourcePath = renameSource;\n }\n }\n\n // OURS: current generated state on disk (resolved/new path)\n const oursPath = join(this.outputDir, resolvedPath);\n const ours = await readFile(oursPath, \"utf-8\").catch(() => null);\n\n // Ghost commit reconstruction: if base tree is unreachable (GC'd after\n // squash merge, shallow clone), reconstruct hybrid BASE and THEIRS from\n // the unified diff's context/removed/added lines matched against OURS.\n let ghostReconstructed = false;\n let theirs: string | null = null;\n\n if (!base && ours && !renameSourcePath) {\n const treeReachable = await this.isTreeReachable(baseGen.tree_hash);\n if (!treeReachable) {\n const fileDiff = this.extractFileDiff(patch.patch_content, filePath);\n if (fileDiff) {\n const { reconstructFromGhostPatch } = await import(\"./HybridReconstruction.js\");\n const result = reconstructFromGhostPatch(fileDiff, ours);\n if (result) {\n base = result.base;\n theirs = result.theirs;\n ghostReconstructed = true;\n }\n }\n }\n }\n\n // THEIRS: user's version.\n //\n // **Snapshot-as-primary** when the patch owns its file (no other\n // patch in this run touches it): the stored `theirs_snapshot`\n // IS the customer's intent for the file post-regen. Using it\n // directly bypasses line-anchored reconstruction and survives\n // generator structural changes that would invalidate the diff's\n // line anchors. This is the architectural fix for the silent-\n // loss class of bugs.\n //\n // **Reconstruction-as-primary** when the patch shares its file\n // with another patch in this run (FER-9525 cross-patch\n // isolation). Snapshots from commit trees are CUMULATIVE\n // across the patches touching a shared file, so using a later\n // patch's snapshot as its individual THEIRS would propagate\n // prior patches' edits into the merge — surfacing nested\n // conflicts at regions the patch alone never touched. The\n // line-anchored diff produces each patch's INDIVIDUAL\n // contribution, which is what the cross-patch flow needs.\n //\n // For shared-file patches, snapshot is still used as a narrow\n // markers-only fallback: when reconstruction produces\n // marker-laden content (cross-patch context mismatch where the\n // diff applies fuzzy-cleanly but yields stale-base markers),\n // snapshot rescues. The pure-null-return case (strict context\n // mismatch — patch can't apply against this base at all) is\n // left as \"skipped\" so legacy paths (PR #73's by-association\n // gate, accumulator fallback) handle recovery with their\n // established UX.\n const snapshotForFile =\n patch.theirs_snapshot?.[resolvedPath] ?? patch.theirs_snapshot?.[filePath];\n const fileIsShared =\n this.sharedFiles.has(resolvedPath) || this.sharedFiles.has(filePath);\n const useSnapshotAsPrimary = !fileIsShared && snapshotForFile != null;\n\n if (!ghostReconstructed) {\n if (useSnapshotAsPrimary) {\n // Snapshot IS THEIRS. Skip the brittle reconstruction\n // step entirely. 3-way merge below uses BASE → snapshot\n // for \"what the customer changed\", which works on\n // content (not line anchors) and survives generator\n // structural changes.\n theirs = snapshotForFile;\n } else {\n theirs = await this.applyPatchToContent(\n base,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir,\n renameSourcePath\n );\n const reconstructionHasMarkers = theirs != null\n && (theirs.includes(\"<<<<<<< Generated\") || theirs.includes(\">>>>>>> Your customization\"));\n const baseHadMarkers = base != null\n && (base.includes(\"<<<<<<< Generated\") || base.includes(\">>>>>>> Your customization\"));\n if (reconstructionHasMarkers && !baseHadMarkers && snapshotForFile != null) {\n theirs = snapshotForFile;\n }\n }\n }\n\n // Detect markers that bled into THEIRS from a cross-patch context\n // mismatch: the patch's diff was authored against post-A state but\n // we tried to apply it to gen-anchor BASE. When this happens AND a\n // prior patch's accumulator entry is available with the right\n // base_generation, we want the accumulator fallback below to retry\n // against the accumulator. Treat THEIRS as null in that case so\n // the existing fallback logic fires naturally.\n //\n // Only skip outright (with `stale-conflict-markers`) when there's\n // no accumulator to fall back on — that's the original\n // \"stale markers from a crashed run\" case.\n const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);\n if (theirs) {\n const theirsHasMarkers = theirs.includes(\"<<<<<<< Generated\") || theirs.includes(\">>>>>>> Your customization\");\n const baseHasMarkers = base != null && (base.includes(\"<<<<<<< Generated\") || base.includes(\">>>>>>> Your customization\"));\n if (theirsHasMarkers && !baseHasMarkers) {\n if (accumulatorEntry) {\n // Accumulator-based fallback below will try against\n // post-prior-patch state.\n theirs = null;\n } else {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"stale-conflict-markers\"\n };\n }\n }\n }\n\n // Fall back to accumulator as merge base for incremental patches.\n let useAccumulatorAsMergeBase = false;\n\n if (accumulatorEntry && (theirs == null || base == null)) {\n theirs = await this.applyPatchToContent(\n accumulatorEntry.content,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir\n );\n if (theirs != null) {\n useAccumulatorAsMergeBase = true;\n } else if (await this.isPatchAlreadyApplied(\n patch.patch_content,\n filePath,\n accumulatorEntry.content,\n tempGit,\n tempDir\n )) {\n // The patch's additions are already present in the accumulator.\n // This happens when preGenerationRebase's content refresh absorbs a\n // new user commit into an existing patch, and detectNewPatches also\n // creates a separate patch for that same commit. The effective\n // THEIRS is the accumulator content itself — no further apply needed.\n theirs = accumulatorEntry.content;\n useAccumulatorAsMergeBase = true;\n }\n }\n\n // Check again after accumulator fallback — git apply --3way against\n // accumulated content can also produce conflict markers.\n if (theirs) {\n const theirsHasMarkers = theirs.includes(\"<<<<<<< Generated\") || theirs.includes(\">>>>>>> Your customization\");\n const accBaseHasMarkers = accumulatorEntry != null &&\n (accumulatorEntry.content.includes(\"<<<<<<< Generated\") || accumulatorEntry.content.includes(\">>>>>>> Your customization\"));\n if (theirsHasMarkers && !accBaseHasMarkers && !(base != null && (base.includes(\"<<<<<<< Generated\") || base.includes(\">>>>>>> Your customization\")))) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"stale-conflict-markers\"\n };\n }\n }\n\n // Pre-merge with accumulated customizations (skip when accumulator is merge base).\n let effective_theirs = theirs;\n let baseMismatchSkipped = false;\n\n if (theirs != null && base != null && !useAccumulatorAsMergeBase) {\n if (accumulatorEntry && accumulatorEntry.baseGeneration === patch.base_generation) {\n // Pre-merge: combine previous customizations with current patch\n try {\n const preMerged = threeWayMerge(base, accumulatorEntry.content, theirs);\n\n if (!preMerged.hasConflicts) {\n // Clean merge - use the combined result\n effective_theirs = preMerged.content;\n } else {\n // Pre-merge has conflicts - skip accumulator for this patch\n // to avoid nested conflict markers. User patches conflict\n // with each other and require manual resolution.\n effective_theirs = theirs;\n }\n } catch {\n // If pre-merge fails unexpectedly, fall back to current_theirs\n effective_theirs = theirs;\n }\n } else if (accumulatorEntry) {\n // Base generations differ - accumulator pre-merge skipped.\n // The main merge below will still run, but if it conflicts\n // we flag it as a base-generation-mismatch.\n baseMismatchSkipped = true;\n }\n }\n\n // Handle new files (user created, didn't exist in generation)\n if (base == null && ours == null && effective_theirs != null) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: effective_theirs,\n baseGeneration: patch.base_generation\n });\n const outDir = dirname(oursPath);\n await mkdir(outDir, { recursive: true });\n await writeFile(oursPath, effective_theirs);\n return { file: resolvedPath, status: \"merged\", reason: \"new-file\" };\n }\n\n // Handle new file created by both user and generator (conflict)\n if (base == null && ours != null && effective_theirs != null && !useAccumulatorAsMergeBase) {\n const merged = threeWayMerge(\"\", ours, effective_theirs);\n const outDir = dirname(oursPath);\n await mkdir(outDir, { recursive: true });\n await writeFile(oursPath, merged.content);\n if (merged.hasConflicts) {\n return {\n file: resolvedPath,\n status: \"conflict\",\n conflicts: merged.conflicts,\n conflictReason: \"new-file-both\",\n conflictMetadata: metadata\n };\n }\n // Populate accumulator so subsequent patches on this user-created\n // file have a base state to reconstruct THEIRS against. Without\n // this, the next patch's fast-path (git apply --3way) hits\n // \"already exists\" on new-file mode, falls through to slow path,\n // and sees an empty accumulator — invariant I2 fails.\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: merged.content,\n baseGeneration: patch.base_generation\n });\n return { file: resolvedPath, status: \"merged\" };\n }\n\n if (effective_theirs == null) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"missing-content\"\n };\n }\n\n if ((base == null && !useAccumulatorAsMergeBase) || ours == null) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"missing-content\"\n };\n }\n\n // Perform 3-way merge.\n // For incremental patches, use the accumulated state as the merge base\n // so the diff is computed relative to prior patches, not the raw generation.\n const mergeBase = useAccumulatorAsMergeBase && accumulatorEntry ? accumulatorEntry.content : base;\n if (mergeBase == null) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"missing-content\"\n };\n }\n const merged = threeWayMerge(mergeBase, ours, effective_theirs);\n\n // Write result to the resolved (current) path\n const outDir = dirname(oursPath);\n await mkdir(outDir, { recursive: true });\n await writeFile(oursPath, merged.content);\n\n // Update accumulator after merge so subsequent patches on the\n // same file have a structurally-correct THEIRS to anchor their\n // diff against.\n //\n // FER-9525 guard: in REPLAY mode, skip on conflict — the next\n // iteration's intra-loop strip will reset disk to OURS, and a\n // poisoned accumulator entry could cause the next patch to see\n // false conflicts on regions it never touched.\n //\n // RESOLVE mode: populate even on conflict. We store the clean\n // `effective_theirs` (NOT `merged.content` with markers), so\n // there's no marker poisoning. A follow-up patch whose diff was\n // authored against post-this-patch structure NEEDS this entry\n // to anchor against — without it the follow-up's THEIRS\n // reconstruction fails (cross-patch context mismatch produces\n // markers that get filtered out, and the patch's additive\n // content never reaches disk). The \"spurious cross-region\n // conflicts\" concern that motivated FER-9525 is muted in\n // resolve mode because the customer is going to manually\n // resolve A's region anyway.\n const populateAccumulator =\n effective_theirs != null &&\n (!merged.hasConflicts || this.currentApplyMode === \"resolve\");\n if (populateAccumulator) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: effective_theirs!,\n baseGeneration: patch.base_generation\n });\n }\n\n if (merged.hasConflicts) {\n return {\n file: resolvedPath,\n status: \"conflict\",\n conflicts: merged.conflicts,\n conflictReason: baseMismatchSkipped ? \"base-generation-mismatch\" : \"same-line-edit\",\n conflictMetadata: metadata\n };\n }\n\n return {\n file: resolvedPath,\n status: \"merged\",\n ...(merged.droppedContextLines && merged.droppedContextLines.length > 0\n ? { droppedContextLines: merged.droppedContextLines }\n : {})\n };\n } catch (error) {\n return {\n file: filePath,\n status: \"skipped\",\n reason: `error: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n }\n\n private async isTreeReachable(treeHash: string): Promise<boolean> {\n let result = this.treeExistsCache.get(treeHash);\n if (result === undefined) {\n result = await this.git.treeExists(treeHash);\n this.treeExistsCache.set(treeHash, result);\n }\n return result;\n }\n\n private isExcluded(patch: StoredPatch): boolean {\n const config = this.lockManager.getCustomizationsConfig();\n if (!config.exclude) return false;\n\n return patch.files.some((file) => config.exclude!.some((pattern) => minimatch(file, pattern)));\n }\n\n private async resolveFilePath(filePath: string, baseTreeHash: string, currentTreeHash: string): Promise<string> {\n // Priority 1: Manual moves from replay.yml\n const config = this.lockManager.getCustomizationsConfig();\n if (config.moves) {\n for (const move of config.moves) {\n if (minimatch(filePath, move.from) || filePath === move.from) {\n // For exact matches, replace directly\n if (filePath === move.from) {\n return move.to;\n }\n // For glob matches, replace the matching prefix\n // e.g., from: \"src/api/**\" to: \"src/resources/**\"\n // filePath: \"src/api/client.ts\" → \"src/resources/client.ts\"\n const fromBase = move.from.replace(/\\*\\*.*$/, \"\");\n const toBase = move.to.replace(/\\*\\*.*$/, \"\");\n if (filePath.startsWith(fromBase)) {\n return toBase + filePath.slice(fromBase.length);\n }\n }\n }\n }\n\n // Priority 2: Git rename detection (cached per tree pair)\n const cacheKey = `${baseTreeHash}:${currentTreeHash}`;\n let renames = this.renameCache.get(cacheKey);\n if (!renames) {\n renames = await this.git.detectRenames(baseTreeHash, currentTreeHash);\n this.renameCache.set(cacheKey, renames);\n }\n\n const gitRename = renames.find((r) => r.from === filePath);\n if (gitRename) {\n return gitRename.to;\n }\n\n // Priority 3: No rename detected\n return filePath;\n }\n\n private async applyPatchToContent(\n base: string | null,\n patchContent: string,\n filePath: string,\n tempGit: GitClient,\n tempDir: string,\n sourceFilePath?: string\n ): Promise<string | null> {\n if (!base) {\n // New file - extract content directly from patch\n return this.extractNewFileFromPatch(patchContent, filePath);\n }\n\n // Extract only the diff for this specific file\n const fileDiff = this.extractFileDiff(patchContent, filePath);\n if (!fileDiff) return null;\n\n try {\n if (sourceFilePath) {\n // Rename case: write base at the OLD path, apply the rename diff,\n // then read from the NEW path (filePath).\n const tempSourcePath = join(tempDir, sourceFilePath);\n await mkdir(dirname(tempSourcePath), { recursive: true });\n await writeFile(tempSourcePath, base);\n\n await tempGit.exec([\"add\", sourceFilePath]);\n await tempGit.exec([\n \"commit\",\n \"-m\",\n `base for rename ${sourceFilePath} -> ${filePath}`,\n \"--allow-empty\"\n ]);\n\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n const tempTargetPath = join(tempDir, filePath);\n return await readFile(tempTargetPath, \"utf-8\");\n }\n\n // Normal case: write base at filePath, apply diff, read back\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, base);\n\n // Stage and commit so git apply has a clean base\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `base for ${filePath}`, \"--allow-empty\"]);\n\n // Apply this file's diff\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n return await readFile(tempFilePath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n /**\n * Detects whether a patch's additions are already present in `content`.\n * Uses `git apply --reverse --check` — if the reverse patch applies cleanly,\n * the forward patch is effectively a no-op (its +lines are already there and\n * its -lines are already gone). Used to distinguish \"patch already applied\"\n * from \"patch base mismatch\" after a forward-apply fails.\n */\n private async isPatchAlreadyApplied(\n patchContent: string,\n filePath: string,\n content: string,\n tempGit: GitClient,\n tempDir: string\n ): Promise<boolean> {\n const fileDiff = this.extractFileDiff(patchContent, filePath);\n if (!fileDiff) return false;\n try {\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, content);\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `check already-applied ${filePath}`, \"--allow-empty\"]);\n await tempGit.execWithInput([\"apply\", \"--reverse\", \"--check\", \"--allow-empty\"], fileDiff);\n return true;\n } catch {\n return false;\n }\n }\n\n private extractFileDiff(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const diffLines: string[] = [];\n let inTargetFile = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) {\n // Hit the next file's diff, stop collecting\n break;\n }\n if (isDiffLineForFile(line, filePath)) {\n inTargetFile = true;\n diffLines.push(line);\n }\n continue;\n }\n\n if (inTargetFile) {\n diffLines.push(line);\n }\n }\n\n return diffLines.length > 0 ? diffLines.join(\"\\n\") + \"\\n\" : null;\n }\n\n private extractRenameSource(patchContent: string, targetFilePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n let inTargetFile = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) break; // past the target block\n inTargetFile = isDiffLineForFile(line, targetFilePath);\n continue;\n }\n if (!inTargetFile) continue;\n\n // Stop at first hunk — rename headers appear before @@\n if (line.startsWith(\"@@\")) break;\n\n if (line.startsWith(\"rename from \")) {\n return line.slice(\"rename from \".length);\n }\n }\n\n return null;\n }\n\n private extractNewFileFromPatch(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const addedLines: string[] = [];\n let inTargetFile = false;\n let inHunk = false;\n let isNewFile = false;\n let noTrailingNewline = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) break; // hit next file's diff\n inTargetFile = isDiffLineForFile(line, filePath);\n inHunk = false;\n isNewFile = false;\n continue;\n }\n if (!inTargetFile) continue;\n\n if (!inHunk) {\n if (line === \"--- /dev/null\" || line.startsWith(\"new file mode\")) {\n isNewFile = true;\n }\n }\n\n if (line.startsWith(\"@@\")) {\n if (!isNewFile) return null; // modification diff, not a new-file creation\n inHunk = true;\n continue;\n }\n if (!inHunk) continue;\n\n if (line === \"\\\\") {\n noTrailingNewline = true;\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n addedLines.push(line.slice(1));\n }\n }\n\n if (addedLines.length === 0) return null;\n return addedLines.join(\"\\n\") + (noTrailingNewline ? \"\" : \"\\n\");\n }\n}\n\nexport function isBinaryFile(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n}\n\n/**\n * Lines present in BOTH base and theirs (unchanged context in customer's\n * THEIRS) but absent from finalContent. Mirrors the slow-path detection in\n * ThreeWayMerge.computeDroppedContextLines so the warning surfaces\n * regardless of whether `git apply --3way` (fast path) or per-file diff3\n * (slow path) produced finalContent. Order preserved per first occurrence\n * in `base`. Multi-occurrence lines are reported as dropped when their\n * multiplicity decreased.\n */\nfunction computeDroppedContextLinesForFile(\n base: string,\n theirs: string,\n finalContent: string\n): string[] {\n const baseLines = base.split(\"\\n\");\n const theirsLines = theirs.split(\"\\n\");\n const finalLines = finalContent.split(\"\\n\");\n\n const baseCounts = new Map<string, number>();\n const theirsCounts = new Map<string, number>();\n const finalCounts = new Map<string, number>();\n\n for (const l of baseLines) baseCounts.set(l, (baseCounts.get(l) ?? 0) + 1);\n for (const l of theirsLines) theirsCounts.set(l, (theirsCounts.get(l) ?? 0) + 1);\n for (const l of finalLines) finalCounts.set(l, (finalCounts.get(l) ?? 0) + 1);\n\n const dropped: string[] = [];\n const seen = new Set<string>();\n for (const line of baseLines) {\n if (seen.has(line)) continue;\n const inBase = baseCounts.get(line) ?? 0;\n const inTheirs = theirsCounts.get(line) ?? 0;\n const inFinal = finalCounts.get(line) ?? 0;\n if (inBase > 0 && inTheirs > 0 && inFinal < Math.min(inBase, inTheirs)) {\n dropped.push(line);\n seen.add(line);\n }\n }\n return dropped;\n}\n\n/**\n * Check if a `diff --git` line targets the given file path.\n * Uses a regex anchored to the line format to avoid substring false positives\n * (e.g., `lib/foo.ts` matching `b/lib/foo.ts-backup`).\n */\nfunction isDiffLineForFile(diffLine: string, filePath: string): boolean {\n const match = diffLine.match(/^diff --git a\\/.+ b\\/(.+)$/);\n return match !== null && match[1] === filePath;\n}\n","/**\n * Strip conflict markers from file content, keeping the OURS (Generated) side.\n *\n * Two-pass parser that only recognizes replay-specific markers:\n * Opener: \"<<<<<<< Generated\"\n * Separator: \"=======\"\n * Closer: \">>>>>>> Your customization\"\n *\n * Pass 1: Scan for complete valid triplets (opener + separator + closer).\n * Nested openers abandon the current triplet.\n * Pass 2: Build output keeping OURS lines, skipping THEIRS and marker lines.\n */\n\nconst CONFLICT_OPENER = \"<<<<<<< Generated\";\nconst CONFLICT_SEPARATOR = \"=======\";\nconst CONFLICT_CLOSER = \">>>>>>> Your customization\";\n\ninterface ConflictRange {\n start: number;\n separator: number;\n end: number;\n}\n\nfunction trimCR(line: string): string {\n return line.endsWith(\"\\r\") ? line.slice(0, -1) : line;\n}\n\nfunction findConflictRanges(lines: string[]): ConflictRange[] {\n const ranges: ConflictRange[] = [];\n let i = 0;\n while (i < lines.length) {\n if (trimCR(lines[i]) === CONFLICT_OPENER) {\n let separatorIdx = -1;\n let j = i + 1;\n let found = false;\n while (j < lines.length) {\n const trimmed = trimCR(lines[j]);\n if (trimmed === CONFLICT_OPENER) {\n break; // nested opener, abandon current triplet\n }\n if (separatorIdx === -1 && trimmed === CONFLICT_SEPARATOR) {\n separatorIdx = j;\n } else if (separatorIdx !== -1 && trimmed === CONFLICT_CLOSER) {\n ranges.push({ start: i, separator: separatorIdx, end: j });\n i = j;\n found = true;\n break;\n }\n j++;\n }\n if (!found) {\n i++;\n continue;\n }\n }\n i++;\n }\n return ranges;\n}\n\nexport function stripConflictMarkers(content: string): string {\n const lines = content.split(/\\r?\\n/);\n const ranges = findConflictRanges(lines);\n\n if (ranges.length === 0) {\n return content;\n }\n\n const result: string[] = [];\n let rangeIdx = 0;\n\n for (let i = 0; i < lines.length; i++) {\n if (rangeIdx < ranges.length) {\n const range = ranges[rangeIdx];\n if (i === range.start) {\n continue;\n }\n if (i > range.start && i < range.separator) {\n result.push(lines[i]);\n continue;\n }\n if (i === range.separator) {\n continue;\n }\n if (i > range.separator && i < range.end) {\n continue;\n }\n if (i === range.end) {\n rangeIdx++;\n continue;\n }\n }\n result.push(lines[i]);\n }\n\n return result.join(\"\\n\");\n}\n\nexport function hasConflictMarkers(content: string): boolean {\n const lines = content.split(/\\r?\\n/);\n return findConflictRanges(lines).length > 0;\n}\n","import { diff3Merge, diffPatch } from \"node-diff3\";\nimport type { IPatchRes } from \"node-diff3\";\nimport type { ConflictRegion, MergeResult } from \"./types.js\";\n\n/**\n * Performs a 3-way merge using the diff3 algorithm.\n *\n * @param base - The common ancestor (pristine generated state user edited against)\n * @param ours - The new generated version\n * @param theirs - The user's customized version\n * @returns MergeResult with content, conflict flag, and conflict regions\n */\nexport function threeWayMerge(base: string, ours: string, theirs: string): MergeResult {\n const baseLines = base.split(\"\\n\");\n const oursLines = ours.split(\"\\n\");\n const theirsLines = theirs.split(\"\\n\");\n\n const regions = diff3Merge(oursLines, baseLines, theirsLines);\n\n const outputLines: string[] = [];\n const conflicts: ConflictRegion[] = [];\n let currentLine = 1;\n\n for (const region of regions) {\n if (region.ok) {\n outputLines.push(...region.ok);\n currentLine += region.ok.length;\n } else if (region.conflict) {\n // Attempt to resolve false conflicts caused by adjacent non-overlapping changes.\n // node-diff3 groups adjacent edits into one conflict region even when the\n // generator and user changed completely different lines within that region.\n const resolved = tryResolveConflict(\n region.conflict.a, // ours (generator)\n region.conflict.o, // base\n region.conflict.b // theirs (user)\n );\n\n if (resolved !== null) {\n outputLines.push(...resolved);\n currentLine += resolved.length;\n } else {\n const startLine = currentLine;\n\n outputLines.push(\"<<<<<<< Generated\");\n outputLines.push(...region.conflict.a);\n outputLines.push(\"=======\");\n outputLines.push(...region.conflict.b);\n outputLines.push(\">>>>>>> Your customization\");\n\n // Total lines in conflict block: 3 markers + a.length + b.length\n // endLine is the line number of the \">>>>>>>\" marker\n const conflictLines = region.conflict.a.length + region.conflict.b.length + 3;\n conflicts.push({\n startLine,\n endLine: startLine + conflictLines - 1,\n ours: region.conflict.a,\n theirs: region.conflict.b\n });\n\n currentLine += conflictLines;\n }\n }\n }\n\n const result: MergeResult = {\n content: outputLines.join(\"\\n\"),\n hasConflicts: conflicts.length > 0,\n conflicts\n };\n\n // Detect lines that were unchanged context in the customer's THEIRS but\n // got silently deleted by the generator. Only meaningful when no\n // conflicts surfaced — when conflicts exist, the customer already has a\n // marker to review. We compare against the lines diff3 actually emitted,\n // which means a deleted-once-but-still-present-elsewhere line counts as\n // dropped if its multiplicity decreased; that's accurate for the auth0\n // case (each wiring line is a unique signature).\n if (conflicts.length === 0) {\n const dropped = computeDroppedContextLines(baseLines, theirsLines, outputLines);\n if (dropped.length > 0) {\n result.droppedContextLines = dropped;\n }\n }\n\n return result;\n}\n\n/**\n * Lines present in BOTH base and theirs but absent from the merge output.\n * These are lines the customer's THEIRS treated as context (didn't edit);\n * OURS deleted; diff3 sided with the deletion. Returns empty array when\n * none. Order preserved per first occurrence in `base`.\n */\nfunction computeDroppedContextLines(\n baseLines: string[],\n theirsLines: string[],\n mergedLines: string[]\n): string[] {\n const baseCounts = countLines(baseLines);\n const theirsCounts = countLines(theirsLines);\n const mergedCounts = countLines(mergedLines);\n\n const dropped: string[] = [];\n const seen = new Set<string>();\n\n for (const line of baseLines) {\n if (seen.has(line)) continue;\n const inBase = baseCounts.get(line) ?? 0;\n const inTheirs = theirsCounts.get(line) ?? 0;\n const inMerged = mergedCounts.get(line) ?? 0;\n\n // Line was in BOTH base and theirs (unchanged context) AND its\n // multiplicity went down in the merge. The deletion came from OURS.\n if (inBase > 0 && inTheirs > 0 && inMerged < Math.min(inBase, inTheirs)) {\n dropped.push(line);\n seen.add(line);\n }\n }\n\n return dropped;\n}\n\nfunction countLines(lines: string[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const line of lines) {\n counts.set(line, (counts.get(line) ?? 0) + 1);\n }\n return counts;\n}\n\n/**\n * Attempts to resolve a false conflict by checking if ours and theirs\n * changed non-overlapping lines within the conflict region's base.\n * Returns merged lines if resolvable, or null for a real conflict.\n */\nfunction tryResolveConflict(\n oursLines: string[],\n baseLines: string[],\n theirsLines: string[]\n): string[] | null {\n if (baseLines.length === 0) {\n return null;\n }\n\n const oursPatches = diffPatch(baseLines, oursLines);\n const theirsPatches = diffPatch(baseLines, theirsLines);\n\n if (oursPatches.length === 0) return theirsLines;\n if (theirsPatches.length === 0) return oursLines;\n\n if (patchesOverlap(oursPatches, theirsPatches)) {\n return null;\n }\n\n return applyBothPatches(baseLines, oursPatches, theirsPatches);\n}\n\n/**\n * Checks if any patch ranges overlap in base coordinates.\n */\nfunction patchesOverlap(\n oursPatches: IPatchRes<string>[],\n theirsPatches: IPatchRes<string>[]\n): boolean {\n for (const op of oursPatches) {\n const oStart = op.buffer1.offset;\n const oEnd = oStart + op.buffer1.length;\n for (const tp of theirsPatches) {\n const tStart = tp.buffer1.offset;\n const tEnd = tStart + tp.buffer1.length;\n\n // Both are pure insertions at the same point\n if (op.buffer1.length === 0 && tp.buffer1.length === 0 && oStart === tStart) {\n return true;\n }\n // Insertion at the exact boundary of a deletion/replacement.\n // Example: generator deletes lines [0,2) and user inserts at offset 2.\n // The insertion's surrounding context has been rewritten, so splicing\n // both into base would produce a semantically broken result (e.g. user\n // content appended after a file-deletion). Treating this as overlap is\n // conservative — it keeps the conflict for manual resolution rather than\n // silently producing a bad merge.\n if (tp.buffer1.length === 0 && tStart === oEnd) {\n return true;\n }\n if (op.buffer1.length === 0 && oStart === tEnd) {\n return true;\n }\n // Standard range overlap\n if (oStart < tEnd && tStart < oEnd) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Applies both sets of non-overlapping patches to base.\n * Patches are sorted by descending offset and applied via splice\n * to avoid index invalidation.\n */\nfunction applyBothPatches(\n baseLines: string[],\n oursPatches: IPatchRes<string>[],\n theirsPatches: IPatchRes<string>[]\n): string[] {\n const allPatches = [\n ...oursPatches.map(p => ({\n offset: p.buffer1.offset,\n length: p.buffer1.length,\n replacement: p.buffer2.chunk,\n })),\n ...theirsPatches.map(p => ({\n offset: p.buffer1.offset,\n length: p.buffer1.length,\n replacement: p.buffer2.chunk,\n })),\n ];\n\n allPatches.sort((a, b) => b.offset - a.offset);\n\n const result = [...baseLines];\n for (const p of allPatches) {\n result.splice(p.offset, p.length, ...p.replacement);\n }\n return result;\n}\n","import type { GitClient } from \"./git/GitClient.js\";\nimport type { GenerationRecord, StoredPatch } from \"./types.js\";\n\nexport interface CommitOptions {\n cliVersion: string;\n generatorVersions: Record<string, string>;\n baseBranchHead?: string;\n}\n\nexport class ReplayCommitter {\n private git: GitClient;\n private outputDir: string;\n\n constructor(git: GitClient, outputDir: string) {\n this.git = git;\n this.outputDir = outputDir;\n }\n\n async commitGeneration(message: string, options?: CommitOptions): Promise<string> {\n await this.stageAll();\n\n if (!(await this.hasStagedChanges())) {\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n let fullMessage = `[fern-generated] ${message}\\n\\nGenerated by Fern`;\n\n if (options?.cliVersion) {\n fullMessage += `\\nCLI Version: ${options.cliVersion}`;\n }\n\n if (options?.generatorVersions && Object.keys(options.generatorVersions).length > 0) {\n fullMessage += \"\\nGenerators:\";\n for (const [name, version] of Object.entries(options.generatorVersions)) {\n fullMessage += `\\n - ${name}: ${version}`;\n }\n }\n\n await this.git.exec([\"commit\", \"-m\", fullMessage]);\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n async commitReplay(\n _patchCount: number,\n patches?: StoredPatch[],\n message?: string,\n options?: {\n buckets?: {\n applied: StoredPatch[];\n unresolved: StoredPatch[];\n absorbed: StoredPatch[];\n };\n }\n ): Promise<string> {\n await this.stageAll();\n\n if (!(await this.hasStagedChanges())) {\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n let fullMessage = message ?? `[fern-replay] Applied customizations`;\n\n const buckets = options?.buckets;\n if (buckets) {\n // Honest, bucketed body so the customer can tell at a glance\n // which patches truly applied, which need their attention via\n // `fern replay resolve`, and which the generator now emits\n // natively. Empty buckets are omitted.\n if (buckets.applied.length > 0) {\n fullMessage += `\\n\\nPatches applied (${buckets.applied.length}):`;\n for (const p of buckets.applied) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n }\n if (buckets.unresolved.length > 0) {\n fullMessage += `\\n\\nPatches with unresolved conflicts (${buckets.unresolved.length}):`;\n for (const p of buckets.unresolved) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n fullMessage += `\\n Run \\`fern-replay resolve\\` to apply these customizations.`;\n }\n if (buckets.absorbed.length > 0) {\n fullMessage += `\\n\\nPatches absorbed by generator (${buckets.absorbed.length}):`;\n for (const p of buckets.absorbed) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n fullMessage += `\\n The generator now produces these customizations natively.`;\n }\n } else if (patches && patches.length > 0) {\n // Legacy flat-list path (used by `commands/resolve.ts` after\n // hand-resolution and by tests that don't pass buckets). Every\n // patch is presumed applied at this point.\n fullMessage += \"\\n\\nPatches replayed:\";\n for (const patch of patches) {\n fullMessage += `\\n - ${patch.id}: ${patch.original_message}`;\n }\n }\n\n await this.git.exec([\"commit\", \"-m\", fullMessage]);\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n async createGenerationRecord(options?: CommitOptions): Promise<GenerationRecord> {\n const commitSha = (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n const treeHash = await this.getTreeHash(commitSha);\n\n return {\n commit_sha: commitSha,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: options?.cliVersion ?? \"unknown\",\n generator_versions: options?.generatorVersions ?? {},\n base_branch_head: options?.baseBranchHead\n };\n }\n\n async stageAll(): Promise<void> {\n await this.git.exec([\"add\", \"-A\", this.outputDir]);\n }\n\n async hasStagedChanges(): Promise<boolean> {\n const output = await this.git.exec([\"diff\", \"--cached\", \"--name-only\"]);\n return output.trim().length > 0;\n }\n\n async getTreeHash(commitSha: string): Promise<string> {\n return this.git.getTreeHash(commitSha);\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { readFile as readFileAsync } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { isGenerationCommit, isRevertCommit, parseRevertedMessage } from \"./git/CommitDetection.js\";\nimport { GitClient } from \"./git/GitClient.js\";\nimport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nimport { ReplayApplicator, isBinaryFile } from \"./ReplayApplicator.js\";\nimport { ReplayCommitter } from \"./ReplayCommitter.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { stripConflictMarkers } from \"./conflict-utils.js\";\nimport { computePerPatchDiffWithFallback, synthesizeNewFileDiff, unifiedDiff } from \"./PatchRegionDiff.js\";\nimport type { FileResult, GenerationRecord, ReplayConfig, ReplayResult, StoredPatch } from \"./types.js\";\n\nexport interface ConflictDetail {\n patchId: string;\n patchMessage: string;\n reason?: string;\n files: FileResult[];\n /** Files that applied cleanly in a patch that also had conflicts. */\n cleanFiles?: string[];\n}\n\nexport interface UnresolvedPatchInfo {\n patchId: string;\n patchMessage: string;\n files: string[];\n conflictDetails: FileResult[];\n}\n\nexport interface ReplayReport {\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\";\n patchesDetected: number;\n patchesApplied: number;\n patchesWithConflicts: number;\n patchesSkipped: number;\n patchesAbsorbed?: number;\n patchesRepointed?: number;\n patchesContentRebased?: number;\n patchesKeptAsUserOwned?: number;\n patchesPartiallyApplied?: number;\n patchesConflictResolved?: number;\n patchesReverted?: number;\n patchesRefreshed?: number;\n conflicts: FileResult[];\n conflictDetails?: ConflictDetail[];\n /** Patches that conflicted and need local resolution via `fern-replay resolve` */\n unresolvedPatches?: UnresolvedPatchInfo[];\n wouldApply?: StoredPatch[];\n warnings?: string[];\n}\n\nexport interface ReplayOptions {\n /** Log what would happen but don't modify anything */\n dryRun?: boolean;\n /** Write files and stage changes, but don't commit */\n stageOnly?: boolean;\n /** CLI version for commit metadata */\n cliVersion?: string;\n /** Generator versions for commit metadata */\n generatorVersions?: Record<string, string>;\n /** Commit generation + update lockfile, skip detection/application */\n skipApplication?: boolean;\n /** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */\n baseBranchHead?: string;\n}\n\n/**\n * Options honored by `applyPreparedReplay()`. `cliVersion`, `generatorVersions`,\n * `baseBranchHead`, `dryRun`, and `skipApplication` were all captured in phase 1\n * and re-supplying them here is meaningless.\n */\nexport interface ApplyOptions {\n /** Write files and stage changes, but don't commit */\n stageOnly?: boolean;\n}\n\n/**\n * Opaque handle returned by `prepareReplay()`. Consumed by `applyPreparedReplay()`\n * to complete the run.\n *\n * Contract for consumers (e.g., generator-cli pipeline inserting AutoVersionStep):\n *\n * - Between `prepareReplay` and `applyPreparedReplay`, HEAD is at the new\n * `[fern-generated]` commit (unless `_prepared.terminal === true`, e.g. dry-run).\n * - Consumers MAY land additional commits on HEAD between phases. `applyPatches`\n * runs against current HEAD at phase-2 call time, so mid-phase commits are\n * respected. `rebasePatches` uses `currentGenerationSha` (the pure `[fern-generated]`\n * SHA), NOT HEAD — mid-phase commits do not retarget patches' `base_generation`.\n * - The service instance is single-use across the phase boundary: do not call\n * other service methods (`syncFromDivergentMerge`, another `prepareReplay`, etc.)\n * between phases. In-memory lockfile and warning state would be corrupted.\n * - If the caller's mid-phase work throws or `applyPreparedReplay` is never called,\n * the repo is left with the new `[fern-generated]` commit but a stale lockfile.\n * Consumers MUST either (a) still call `applyPreparedReplay` so the lockfile\n * advances, or (b) reset HEAD to `previousGenerationSha` and surface the failure.\n *\n * To decide whether to run autoversion between phases, use:\n * prep.previousGenerationSha != null && prep.flow !== \"skip-application\"\n */\nexport interface ReplayPreparation {\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\";\n /** lockfile.current_generation from BEFORE this run; null iff no prior generation exists */\n previousGenerationSha: string | null;\n /** SHA of the new [fern-generated] commit created by prepareReplay (or HEAD for dry-run terminals) */\n currentGenerationSha: string;\n /** options.baseBranchHead passed through */\n baseBranchHead: string | null;\n /** @internal Opaque state consumed by applyPreparedReplay */\n readonly _prepared: InternalPreparationState;\n}\n\n/** @internal */\ninterface InternalPreparationState {\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\";\n /** true → applyPreparedReplay returns preparedReport without disk/git work (dry-run path) */\n terminal: boolean;\n preparedReport?: ReplayReport;\n /** post-preGenRebase, post-detection, post-absorption (references, not copies) */\n patchesToApply: StoredPatch[];\n /** subset of patchesToApply that were freshly detected this cycle (vs already in the lockfile) */\n newPatchIds: Set<string>;\n preRebaseCounts?: { conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number };\n /** detector warnings snapshotted at end of phase 1 */\n detectorWarnings: string[];\n revertedCount: number;\n /** [fern-generated] SHA; passed to rebasePatches as currentGenSha */\n genSha: string;\n /** cached phase-1 options for constructing the final ReplayReport in phase 2 */\n optionsSnapshot?: ReplayOptions;\n}\n\nexport class ReplayService {\n private git: GitClient;\n private detector: ReplayDetector;\n private applicator: ReplayApplicator;\n private committer: ReplayCommitter;\n private lockManager: LockfileManager;\n private outputDir: string;\n /** @internal Test-only. Captures the last ReplayResult[] returned from applicator.applyPatches(). */\n private _lastApplyResults: ReplayResult[] = [];\n /**\n * Service-level warnings accumulated during a single runReplay() call.\n * Merged with `detector.warnings` into `ReplayReport.warnings` by each flow handler.\n * Populated by `isFileUserOwned` when a patch's base generation tree is unreachable\n * (shallow clone / aggressive `git gc --prune`) and we fall back to a conservative\n * heuristic. Cleared at the top of `runReplay()`.\n */\n private warnings: string[] = [];\n\n /**\n * @internal Test-only accessor.\n * Returns the ReplayApplicator instance used for the last run. Tests use this\n * to inspect the inter-patch accumulator after runReplay() completes (FER-9791, I2).\n */\n get applicatorRef(): ReplayApplicator {\n return this.applicator;\n }\n\n /**\n * @internal Test-only accessor.\n * Returns the ReplayResult[] from the most recent applyPatches() call. Tests use\n * this to filter applied-vs-conflicted-vs-absorbed patches for invariant assertions\n * (FER-9791). Returns an empty array if no patches have been applied yet.\n */\n getLastResults(): ReadonlyArray<ReplayResult> {\n return this._lastApplyResults;\n }\n\n constructor(outputDir: string, _config: ReplayConfig) {\n const git = new GitClient(outputDir);\n this.git = git;\n this.outputDir = outputDir;\n this.lockManager = new LockfileManager(outputDir);\n this.detector = new ReplayDetector(git, this.lockManager, outputDir);\n this.applicator = new ReplayApplicator(git, this.lockManager, outputDir);\n this.committer = new ReplayCommitter(git, outputDir);\n }\n\n /**\n * Phase 1 of the two-phase replay flow. Runs preGenerationRebase (when applicable),\n * detects new patches, and creates the `[fern-generated]` commit. Leaves HEAD at\n * the generation commit (or unchanged for dry-run).\n *\n * Does NOT apply patches — the returned handle must be passed to\n * `applyPreparedReplay()` to complete the run. No disk writes to the lockfile\n * happen here; lockfile persistence is deferred to phase 2.\n *\n * Callers may land additional commits on HEAD between `prepareReplay` and\n * `applyPreparedReplay` (e.g., `[fern-autoversion]`).\n */\n async prepareReplay(options?: ReplayOptions): Promise<ReplayPreparation> {\n // Reset per-run state so warnings from prior invocations don't leak.\n // Both the service-level and detector-level warnings must be cleared —\n // today's atomic runReplay only clears service warnings, but the two-phase\n // API enlarges the observability window so we tighten this (FER-10001).\n this.warnings = [];\n this.detector.warnings.length = 0;\n\n if (options?.skipApplication) {\n return this._prepareSkipApplication(options);\n }\n\n const flow = this.determineFlow();\n\n switch (flow) {\n case \"first-generation\":\n return this._prepareFirstGeneration(options);\n case \"no-patches\":\n return this._prepareNoPatchesRegeneration(options);\n case \"normal-regeneration\":\n return this._prepareNormalRegeneration(options);\n }\n }\n\n /**\n * Phase 2 of the two-phase replay flow. Applies patches, rebases them against\n * the generation, saves the lockfile, and commits `[fern-replay]` (or stages\n * under `stageOnly`). Operates on HEAD at call time — mid-phase commits are\n * respected.\n *\n * For terminal handles (dry-run, first-gen has no patch work, skip-app does\n * its own post-commit logic), this returns the precomputed report.\n */\n async applyPreparedReplay(\n prep: ReplayPreparation,\n options?: ApplyOptions\n ): Promise<ReplayReport> {\n if (prep._prepared.terminal) {\n // Dry-run path: report was fully built in phase 1 and no disk/git work\n // is needed in phase 2.\n return prep._prepared.preparedReport!;\n }\n\n switch (prep._prepared.flow) {\n case \"first-generation\":\n return this._applyFirstGeneration(prep);\n case \"skip-application\":\n return this._applySkipApplication(prep, options);\n case \"no-patches\":\n return this._applyNoPatchesRegeneration(prep, options);\n case \"normal-regeneration\":\n return this._applyNormalRegeneration(prep, options);\n }\n }\n\n /**\n * Backwards-compatible atomic entry point. Composes `prepareReplay` + `applyPreparedReplay`.\n * Behavior is byte-identical to the pre-split implementation for all existing callers.\n */\n async runReplay(options?: ReplayOptions): Promise<ReplayReport> {\n const prep = await this.prepareReplay(options);\n return this.applyPreparedReplay(prep, options);\n }\n\n /**\n * Sync the lockfile after a divergent PR was squash-merged.\n * Call this BEFORE runReplay() when the CLI detects a merged divergent PR.\n *\n * After updating the generation record, re-detects customer patches via\n * tree diff between the generation tag (pure generation tree) and HEAD\n * (which includes customer customizations after squash merge). This ensures\n * patches survive the squash merge → regenerate cycle even when the lockfile\n * was restored from the base branch during conflict PR creation.\n */\n async syncFromDivergentMerge(\n generationCommitSha: string,\n options?: { cliVersion?: string; generatorVersions?: Record<string, string>; baseBranchHead?: string }\n ): Promise<void> {\n const treeHash = await this.git.getTreeHash(generationCommitSha);\n const timestamp = (await this.git.exec([\"log\", \"-1\", \"--format=%aI\", generationCommitSha])).trim();\n\n const record: GenerationRecord = {\n commit_sha: generationCommitSha,\n tree_hash: treeHash,\n timestamp,\n cli_version: options?.cliVersion ?? \"unknown\",\n generator_versions: options?.generatorVersions ?? {},\n base_branch_head: options?.baseBranchHead\n };\n\n let resolvedPatches: StoredPatch[] | undefined;\n\n if (!this.lockManager.exists()) {\n this.lockManager.initializeInMemory(record);\n } else {\n this.lockManager.read();\n // Preserve unresolved patches — they represent conflicts that the\n // customer hasn't resolved yet. Since we strip conflict markers from\n // committed files, these patches won't appear in the tree diff.\n const unresolvedPatches = [\n ...this.lockManager.getUnresolvedPatches(),\n ...this.lockManager.getResolvingPatches(),\n ];\n // Snapshot resolved patches before clearing — if re-detection fails,\n // we restore them to prevent silent data loss (FER-9547).\n resolvedPatches = this.lockManager.getPatches().filter(p => p.status == null);\n this.lockManager.addGeneration(record);\n this.lockManager.clearPatches();\n\n // Re-add unresolved patches so they carry through the squash merge.\n for (const patch of unresolvedPatches) {\n this.lockManager.addPatch(patch);\n }\n }\n\n // Re-detect customer patches via tree diff. The generation tag has the\n // pure generation tree, so any differences between it and HEAD represent\n // customer customizations that survived the squash merge.\n try {\n const { patches: redetectedPatches } = await this.detector.detectNewPatches();\n if (redetectedPatches.length > 0) {\n // Remove preserved unresolved patches that overlap with\n // re-detected ones (customer resolved them before merging).\n const redetectedFiles = new Set(redetectedPatches.flatMap((p) => p.files));\n const currentPatches = this.lockManager.getPatches();\n for (const patch of currentPatches) {\n if (patch.status != null && patch.files.some((f) => redetectedFiles.has(f))) {\n this.lockManager.removePatch(patch.id);\n }\n }\n\n for (const patch of redetectedPatches) {\n this.lockManager.addPatch(patch);\n }\n }\n } catch (error) {\n // Re-detection failed — restore resolved patches so they aren't\n // permanently lost. The normal replay flow will still attempt detection.\n for (const patch of resolvedPatches ?? []) {\n this.lockManager.addPatch(patch);\n }\n this.detector.warnings.push(\n `Patch re-detection failed after divergent merge sync. ` +\n `${(resolvedPatches ?? []).length} previously resolved patch(es) preserved. ` +\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n this.lockManager.save();\n this.detector.warnings.push(...this.lockManager.warnings);\n }\n\n private determineFlow(): \"first-generation\" | \"no-patches\" | \"normal-regeneration\" {\n try {\n const lock = this.lockManager.read();\n return lock.patches.length === 0 ? \"no-patches\" : \"normal-regeneration\";\n } catch (error) {\n if (error instanceof LockfileNotFoundError) {\n return \"first-generation\";\n }\n throw error;\n }\n }\n\n private firstGenerationReport(): ReplayReport {\n return {\n flow: \"first-generation\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: []\n };\n }\n\n private async _prepareFirstGeneration(options?: ReplayOptions): Promise<ReplayPreparation> {\n if (options?.dryRun) {\n // Dry-run may be called on a repo with no commits yet (truly first-gen).\n // `git rev-parse HEAD` fails in that case; fall back to empty string.\n const headSha = await this.git.exec([\"rev-parse\", \"HEAD\"]).then((s) => s.trim()).catch(() => \"\");\n return {\n flow: \"first-generation\",\n previousGenerationSha: null,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n flow: \"first-generation\",\n terminal: true,\n preparedReport: this.firstGenerationReport(),\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [],\n revertedCount: 0,\n genSha: headSha,\n optionsSnapshot: options\n }\n };\n }\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead\n }\n : undefined;\n\n await this.committer.commitGeneration(\"Initial SDK generation\", commitOpts);\n const genRecord = await this.committer.createGenerationRecord(commitOpts);\n // Phase 1: in-memory only. Disk save deferred to _applyFirstGeneration.\n this.lockManager.initializeInMemory(genRecord);\n\n return {\n flow: \"first-generation\",\n previousGenerationSha: null,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n flow: \"first-generation\",\n terminal: false,\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [],\n revertedCount: 0,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options\n }\n };\n }\n\n private async _applyFirstGeneration(_prep: ReplayPreparation): Promise<ReplayReport> {\n // Save the in-memory lockfile to disk. Matches today's behavior of\n // `lockManager.initialize(genRecord)` which internally calls save().\n // No replay commit in first-gen — the lockfile file lands untracked\n // and is committed by the next cycle's [fern-replay] commit.\n this.lockManager.save();\n return this.firstGenerationReport();\n }\n\n /**\n * Skip-application mode phase 1: commit the generation and update the\n * in-memory lockfile, but don't detect or apply patches. Sets a marker\n * so the next normal run skips revert detection in preGenerationRebase().\n *\n * Disk save is deferred to `_applySkipApplication`.\n */\n private async _prepareSkipApplication(options?: ReplayOptions): Promise<ReplayPreparation> {\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead\n }\n : undefined;\n\n await this.committer.commitGeneration(\"Update SDK (replay skipped)\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n await this.cleanupStaleConflictMarkers();\n\n const genRecord = await this.committer.createGenerationRecord(commitOpts);\n\n let previousGenerationSha: string | null = null;\n try {\n const lock = this.lockManager.read();\n previousGenerationSha = lock.current_generation ?? null;\n this.lockManager.addGeneration(genRecord);\n } catch (error) {\n if (error instanceof LockfileNotFoundError) {\n this.lockManager.initializeInMemory(genRecord);\n } else {\n throw error;\n }\n }\n\n this.lockManager.setReplaySkippedAt(new Date().toISOString());\n\n return {\n flow: \"skip-application\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n flow: \"skip-application\",\n terminal: false,\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [],\n revertedCount: 0,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options\n }\n };\n }\n\n private async _applySkipApplication(\n _prep: ReplayPreparation,\n options?: ApplyOptions\n ): Promise<ReplayReport> {\n this.lockManager.save();\n const credentialWarnings = [...this.lockManager.warnings];\n\n // Commit the lockfile update so it's pushed with the branch.\n // Without this, the marker and generation record stay in the\n // working tree and are lost when GithubStep pushes.\n if (!options?.stageOnly) {\n await this.committer.commitReplay(0);\n } else {\n await this.committer.stageAll();\n }\n\n return {\n flow: \"skip-application\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: [],\n warnings: credentialWarnings.length > 0 ? credentialWarnings : undefined\n };\n }\n\n private async _prepareNoPatchesRegeneration(options?: ReplayOptions): Promise<ReplayPreparation> {\n const preLock = this.lockManager.read();\n const previousGenerationSha = preLock.current_generation ?? null;\n\n let { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();\n // Snapshot of warnings available at detection time. Re-merged with\n // service-level warnings (populated during rebase) when the final report\n // is built in phase 2.\n const detectorWarnings = [...this.detector.warnings];\n\n if (options?.dryRun) {\n const dryRunWarnings = [...detectorWarnings, ...this.warnings];\n const preparedReport: ReplayReport = {\n flow: \"no-patches\",\n patchesDetected: newPatches.length,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n patchesReverted: revertedPatchIds.length,\n conflicts: [],\n wouldApply: newPatches,\n warnings: dryRunWarnings.length > 0 ? dryRunWarnings : undefined\n };\n const headSha = await this.git.exec([\"rev-parse\", \"HEAD\"]).then((s) => s.trim()).catch(() => \"\");\n return {\n flow: \"no-patches\",\n previousGenerationSha,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n flow: \"no-patches\",\n terminal: true,\n preparedReport,\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings,\n revertedCount: revertedPatchIds.length,\n genSha: headSha,\n optionsSnapshot: options\n }\n };\n }\n\n // Pre-apply absorption: drop patches whose net customer effect (from\n // currentGen → HEAD) on all of their files is empty. This mirrors the\n // empty-diff branch of preGenerationRebase which runs only on the\n // normal-regeneration path — without this, flows diverge when the\n // applicator cannot fully cancel a create+delete sequence (FER-9810, D4).\n {\n const preCurrentGen = preLock.current_generation;\n const uniqueFiles = [...new Set(newPatches.flatMap((p) => p.files))];\n const absorbedFiles = new Set<string>();\n for (const file of uniqueFiles) {\n const diff = await this.git\n .exec([\"diff\", preCurrentGen, \"HEAD\", \"--\", file])\n .catch(() => null);\n if (diff !== null && !diff.trim()) {\n absorbedFiles.add(file);\n }\n }\n if (absorbedFiles.size > 0) {\n newPatches = newPatches.filter(\n (p) => p.files.length === 0 || !p.files.every((f) => absorbedFiles.has(f))\n );\n }\n }\n\n // Remove reverted patches from lockfile (after dry-run check to avoid mutating state)\n for (const id of revertedPatchIds) {\n try { this.lockManager.removePatch(id); } catch {}\n }\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead\n }\n : undefined;\n\n await this.committer.commitGeneration(\"Update SDK\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n await this.cleanupStaleConflictMarkers();\n\n const genRecord = await this.committer.createGenerationRecord(commitOpts);\n\n // Add generation to lockfile BEFORE applying patches so the applicator\n // can read the current generation's tree hash for rename detection.\n this.lockManager.addGeneration(genRecord);\n\n return {\n flow: \"no-patches\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n flow: \"no-patches\",\n terminal: false,\n patchesToApply: newPatches,\n newPatchIds: new Set(newPatches.map((p) => p.id)),\n detectorWarnings,\n revertedCount: revertedPatchIds.length,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options\n }\n };\n }\n\n private async _applyNoPatchesRegeneration(\n prep: ReplayPreparation,\n options?: ApplyOptions\n ): Promise<ReplayReport> {\n const newPatches = prep._prepared.patchesToApply;\n const detectorWarnings = prep._prepared.detectorWarnings;\n const genSha = prep._prepared.genSha;\n\n let results: ReplayResult[] = [];\n if (newPatches.length > 0) {\n results = await this.applicator.applyPatches(newPatches);\n this._lastApplyResults = results;\n\n // Surface \"dropped context line\" warnings — see _applyNormalRegeneration.\n this.recordDroppedContextLineWarnings(results);\n\n // Strip conflict markers from conflicting files so the commit is clean.\n this.revertConflictingFiles(results);\n\n // Mark conflict patches as unresolved on the patch objects before adding to lockfile.\n for (const result of results) {\n if (result.status === \"conflict\") {\n result.patch.status = \"unresolved\";\n }\n }\n }\n\n // Rebase cleanly applied patches to the current generation.\n // This prevents recurring conflicts on subsequent regenerations.\n const rebaseCounts = await this.rebasePatches(results, genSha);\n\n // Save lockfile BEFORE commit — lockfile is source of truth.\n for (const patch of newPatches) {\n if (!rebaseCounts.absorbedPatchIds.has(patch.id)) {\n this.lockManager.addPatch(patch);\n }\n }\n this.lockManager.save();\n this.warnings.push(...this.lockManager.warnings);\n\n // Preserve today's L422 guard: when no new patches were detected, neither\n // commitReplay nor stageAll runs. The in-memory `addGeneration` still\n // happened in phase 1; the save just above persisted it.\n if (newPatches.length > 0) {\n if (!options?.stageOnly) {\n // Count only cleanly applied patches for the commit message.\n const appliedCount = results.filter((r) => r.status === \"applied\").length;\n const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, newPatches);\n await this.committer.commitReplay(appliedCount, newPatches, undefined, { buckets });\n } else {\n await this.committer.stageAll();\n }\n }\n\n const warnings = [...detectorWarnings, ...this.warnings];\n return this.buildReport(\n \"no-patches\",\n newPatches,\n results,\n prep._prepared.optionsSnapshot,\n warnings,\n rebaseCounts,\n undefined,\n prep._prepared.revertedCount\n );\n }\n\n private async _prepareNormalRegeneration(options?: ReplayOptions): Promise<ReplayPreparation> {\n const preLock = this.lockManager.read();\n const previousGenerationSha = preLock.current_generation ?? null;\n\n if (options?.dryRun) {\n const existingPatches = this.lockManager.getPatches();\n const { patches: newPatches, revertedPatchIds: dryRunReverted } = await this.detector.detectNewPatches();\n const warnings = [...this.detector.warnings, ...this.warnings];\n const allPatches = [...existingPatches, ...newPatches];\n const preparedReport: ReplayReport = {\n flow: \"normal-regeneration\",\n patchesDetected: allPatches.length,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n patchesReverted: dryRunReverted.length,\n conflicts: [],\n wouldApply: allPatches,\n warnings: warnings.length > 0 ? warnings : undefined\n };\n const headSha = await this.git.exec([\"rev-parse\", \"HEAD\"]).then((s) => s.trim()).catch(() => \"\");\n return {\n flow: \"normal-regeneration\",\n previousGenerationSha,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n flow: \"normal-regeneration\",\n terminal: true,\n preparedReport,\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [...this.detector.warnings],\n revertedCount: dryRunReverted.length,\n genSha: headSha,\n optionsSnapshot: options\n }\n };\n }\n\n // Pre-generation rebase: update stale/modified patches while HEAD has customer code.\n let existingPatches = this.lockManager.getPatches();\n const preRebasePatchIds = new Set(existingPatches.map((p) => p.id));\n const preRebaseCounts = await this.preGenerationRebase(existingPatches);\n\n // Track which patches preGenRebase removed (user reverted → empty diff).\n // These are needed to reconcile re-detected commits and revert commits after detection.\n const postRebasePatchIds = new Set(this.lockManager.getPatches().map((p) => p.id));\n const removedByPreRebase = existingPatches.filter(\n (p) => preRebasePatchIds.has(p.id) && !postRebasePatchIds.has(p.id)\n );\n\n // Dedup patches by content hash after pre-generation rebase.\n //\n // **Consolidation, not preservation.** When two patches have\n // byte-identical `patch_content`, they encode the SAME customer-side\n // delta — neither captures its individual contribution. Applying\n // both back-to-back at the next regen produces duplicated additions\n // (e.g., the same wiring lines spliced into `__all__` twice) and\n // syntactic corruption. The customer's *file* breaks, regardless of\n // how clean the lockfile bookkeeping looks.\n //\n // PR #74's earlier \"preserve both with warning\" rule prioritized\n // provenance preservation over functional correctness — empirically\n // it produced the corruption we're now fixing. Per replay's actual\n // contract (the customer's code stays in the file across N regens,\n // automatically), the right move is to consolidate to ONE canonical\n // patch (the most-recently-seen, by `patchesToCommit` order) and\n // remove the others. Per-commit attribution is recoverable from\n // `git log -- <file>`; corrupted code is not.\n //\n // True duplicates (rebase converging two incremental patches) are\n // a special case of \"same content_hash\" — consolidating them is\n // also right; nothing changes for those tests.\n existingPatches = this.lockManager.getPatches();\n const seenHashes = new Map<string, string>();\n for (const p of existingPatches) {\n const priorPatchId = seenHashes.get(p.content_hash);\n if (priorPatchId !== undefined) {\n this.lockManager.removePatch(p.id);\n this.warnings.push(\n `Consolidated patch ${p.id} (commit ${(p.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into prior patch ${priorPatchId}: byte-identical patch_content. ` +\n `Per-commit attribution preserved in git log; lockfile collapsed to avoid duplicate-apply corruption on next regen.`\n );\n } else {\n seenHashes.set(p.content_hash, p.id);\n }\n }\n existingPatches = this.lockManager.getPatches();\n\n let { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();\n // Snapshot of detector warnings; merged with service-level warnings\n // (populated by preGenerationRebase + rebasePatches) when the final\n // report is built in phase 2.\n const detectorWarnings = [...this.detector.warnings];\n\n // Post-detection reconciliation for patches removed by preGenerationRebase.\n // When a user does git revert on a tracked customization, preGenRebase sees an\n // empty diff and removes the patch. detectNewPatches then re-detects both the\n // original commit AND the revert commit as new patches (since the lockfile no\n // longer tracks the original). We need to:\n // 1. Filter out re-detected originals (already handled by preGenRebase removal)\n // 2. Filter out their corresponding revert commits\n if (removedByPreRebase.length > 0) {\n const removedOriginalCommits = new Set(removedByPreRebase.map((p) => p.original_commit));\n const removedOriginalMessages = new Set(removedByPreRebase.map((p) => p.original_message));\n\n newPatches = newPatches.filter((p) => {\n // Filter out re-detected originals\n if (removedOriginalCommits.has(p.original_commit)) return false;\n // Filter out revert commits matching removed patches\n if (isRevertCommit(p.original_message)) {\n const revertedMsg = parseRevertedMessage(p.original_message);\n if (revertedMsg && removedOriginalMessages.has(revertedMsg)) return false;\n }\n return true;\n });\n }\n\n // Remove reverted patches from lockfile and filter from existing\n for (const id of revertedPatchIds) {\n try { this.lockManager.removePatch(id); } catch {}\n }\n const revertedSet = new Set(revertedPatchIds);\n existingPatches = existingPatches.filter((p) => !revertedSet.has(p.id));\n\n const allPatches = [...existingPatches, ...newPatches];\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead\n }\n : undefined;\n\n await this.committer.commitGeneration(\"Update SDK\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n // HEAD is now the [fern-generated] commit with clean generated content.\n await this.cleanupStaleConflictMarkers();\n\n const genRecord = await this.committer.createGenerationRecord(commitOpts);\n\n // Add generation to lockfile BEFORE applying patches so the applicator\n // can read the current generation's tree hash for rename detection.\n this.lockManager.addGeneration(genRecord);\n\n return {\n flow: \"normal-regeneration\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n flow: \"normal-regeneration\",\n terminal: false,\n patchesToApply: allPatches,\n newPatchIds: new Set(newPatches.map((p) => p.id)),\n preRebaseCounts,\n detectorWarnings,\n revertedCount: revertedPatchIds.length,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options\n }\n };\n }\n\n private async _applyNormalRegeneration(\n prep: ReplayPreparation,\n options?: ApplyOptions\n ): Promise<ReplayReport> {\n const allPatches = prep._prepared.patchesToApply;\n const newPatchIds = prep._prepared.newPatchIds;\n const detectorWarnings = prep._prepared.detectorWarnings;\n const genSha = prep._prepared.genSha;\n\n const results = await this.applicator.applyPatches(allPatches);\n this._lastApplyResults = results;\n\n // Surface \"dropped context line\" warnings — lines that appeared as\n // unchanged context in customer's THEIRS but were silently deleted by\n // the new generator output. diff3 sided with the deletion correctly,\n // but the customer should know so they can re-add intentionally-kept\n // lines if needed. See ThreeWayMerge.computeDroppedContextLines.\n this.recordDroppedContextLineWarnings(results);\n\n // Strip conflict markers from conflicting files so the commit is clean.\n // Keeps the Generated (OURS) side, preserving clean patches' changes.\n this.revertConflictingFiles(results);\n\n // Mark conflict patches as unresolved on the patch objects before adding to lockfile.\n // For new patches, this object mutation is what persists — they're appended to\n // the lockfile via addPatch() below, carrying the status through.\n for (const result of results) {\n if (result.status === \"conflict\") {\n result.patch.status = \"unresolved\";\n }\n }\n\n // Rebase cleanly applied patches to the current generation.\n const rebaseCounts = await this.rebasePatches(results, genSha);\n\n // Save lockfile BEFORE commit — lockfile is source of truth.\n const newPatches = allPatches.filter((p) => newPatchIds.has(p.id));\n for (const patch of newPatches) {\n if (!rebaseCounts.absorbedPatchIds.has(patch.id)) {\n this.lockManager.addPatch(patch);\n }\n }\n\n // Also mark existing (non-new) conflict patches as unresolved in the lockfile.\n // This is a DISTINCT mutation path from the object mutation above — existing\n // patches are already in the lockfile, and we need `updatePatch(id, {status})`\n // to flag them. The try/catch handles the new-patch case where the id is not\n // yet in the lockfile (object mutation above already set the status).\n for (const result of results) {\n if (result.status === \"conflict\") {\n try {\n this.lockManager.markPatchUnresolved(result.patch.id);\n } catch {\n // New patches already have status set via the object mutation above\n }\n }\n }\n\n this.lockManager.save();\n this.warnings.push(...this.lockManager.warnings);\n\n if (options?.stageOnly) {\n await this.committer.stageAll();\n } else {\n // Always commit to persist the lockfile (which tracks unresolved patches).\n // Count only cleanly applied patches for the commit message.\n const appliedCount = results.filter((r) => r.status === \"applied\").length;\n const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, allPatches);\n await this.committer.commitReplay(appliedCount, allPatches, undefined, { buckets });\n }\n\n const warnings = [...detectorWarnings, ...this.warnings];\n return this.buildReport(\n \"normal-regeneration\",\n allPatches,\n results,\n prep._prepared.optionsSnapshot,\n warnings,\n rebaseCounts,\n prep._prepared.preRebaseCounts,\n prep._prepared.revertedCount\n );\n }\n\n /**\n * Rebase cleanly applied patches so they are relative to the current generation.\n * This prevents recurring conflicts on subsequent regenerations.\n * Returns the number of patches rebased.\n */\n private async rebasePatches(\n results: ReplayResult[],\n currentGenSha: string\n ): Promise<{\n absorbed: number;\n repointed: number;\n contentRebased: number;\n keptAsUserOwned: number;\n absorbedPatchIds: Set<string>;\n }> {\n let absorbed = 0;\n let repointed = 0;\n let contentRebased = 0;\n let keptAsUserOwned = 0;\n // Track content hashes seen this rebase cycle. When two patches end\n // up with byte-identical post-rebase patch_content, they encode the\n // SAME customer-side delta — applying both back-to-back would corrupt\n // the file via duplicate-apply. Consolidate to one (the first seen)\n // and remove the rest. Per-commit attribution is recoverable from\n // `git log`. Map value is the surviving patch's id, used in the\n // consolidation warning.\n const seenContentHashes = new Map<string, string>();\n const absorbedPatchIds = new Set<string>();\n // Cache once — used per patch below to classify protected vs non-protected files.\n const fernignorePatterns = this.readFernignorePatterns();\n\n // Pre-pass: Update patch.files with resolved (renamed) paths from application.\n // This ensures downstream operations (user-owned check, git diff, git show)\n // use the current file paths rather than stale pre-rename paths.\n for (const result of results) {\n if (result.resolvedFiles && Object.keys(result.resolvedFiles).length > 0) {\n const patch = result.patch;\n const updatedFiles = patch.files.map((f) => result.resolvedFiles![f] ?? f);\n patch.files = updatedFiles;\n try {\n this.lockManager.updatePatch(patch.id, { files: updatedFiles });\n } catch {\n // New patches aren't in lockfile yet — in-memory update sufficient\n }\n }\n }\n\n // Build set of file paths that any earlier patch CONFLICTED on in this\n // run. The absorption branch below uses this to detect a clean follow-up\n // patch whose disk state was reset to OURS by revertConflictingFiles or\n // applyPatches' cross-patch marker stripping (ReplayApplicator.ts:157-189).\n // Such a patch shows an empty diff vs currentGen and would otherwise be\n // silently absorbed — masking a real customization. Preserve as\n // unresolved instead so the customer can recover via `fern replay resolve`.\n const conflictedFilePaths = new Set<string>();\n for (const r of results) {\n if (r.status !== \"conflict\") continue;\n if (r.fileResults) {\n for (const fr of r.fileResults) {\n if (fr.status !== \"conflict\") continue;\n conflictedFilePaths.add(fr.file);\n if (r.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(r.resolvedFiles)) {\n if (resolved === fr.file) conflictedFilePaths.add(orig);\n }\n }\n }\n } else {\n // Defensive: a conflict result without fileResults isn't produced\n // by the current applicator, but if a future change introduces\n // one, fall back to patch.files so we don't silently regress.\n for (const f of r.patch.files) conflictedFilePaths.add(f);\n }\n }\n\n for (const result of results) {\n if (result.status === \"conflict\" && result.fileResults) {\n // For conflict patches with mixed results, trim any clean files\n // that were absorbed by the generator. This prevents absorbed files\n // from poisoning the pre-generation rebase conflict marker check.\n await this.trimAbsorbedFiles(result, currentGenSha);\n continue;\n }\n\n // Only rebase cleanly applied patches.\n // Conflicted patches keep their old base_generation so they retry.\n if (result.status !== \"applied\") continue;\n\n const patch = result.patch;\n\n // Skip if already based on the current generation\n if (patch.base_generation === currentGenSha) continue;\n\n try {\n // Classify file ownership. FER-9809 widens main's earlier\n // \"protected = .fernignore only\" classification to include\n // every user-owned file (persisted `user_owned` flag + raw\n // patch_content `--- /dev/null` creation signal + per-file\n // tree lookup on the patch's base_generation). The wider\n // classification is what keeps user-created files (e.g.\n // interceptor.ts) from being silently absorbed when\n // `commitGeneration` stages them into the gen tree via\n // `git add -A` — the empty diff against currentGen would\n // otherwise look identical to an absorption candidate.\n const originalByResolved: Record<string, string> = {};\n if (result.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(result.resolvedFiles)) {\n originalByResolved[resolved] = orig;\n }\n }\n const isUserOwnedPerFile = await Promise.all(\n patch.files.map(async (file) => {\n // .fernignore itself is always user-owned\n if (file === \".fernignore\") return true;\n // .fernignore patterns (cheaper than git)\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) {\n return true;\n }\n // Persisted flag (applies to ALL files in the patch if set).\n if (patch.user_owned) return true;\n // Legacy-safe: patch_content header says this file is a\n // creation (immune to bundling artifacts).\n if (this.fileIsCreationInPatchContent(patch.patch_content, originalByResolved[file] ?? file)) {\n return true;\n }\n // Fall back to current gen tree membership.\n const content = await this.git.showFile(currentGenSha, file);\n return content === null;\n })\n );\n // Match main's \"protected\" semantics for the compact subset:\n // .fernignore itself OR fernignore-pattern-matched files. These\n // must never be absorbed even on empty diff.\n const hasProtectedFiles = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n // FER-9809 \"keep\" branch fires only when EVERY file in the\n // patch is user-owned. Mixed composite patches (user + gen\n // files, e.g. from tree-diff fallback) still flow through the\n // absorption/rebase branch below so the gen-file halves get\n // content-rebased; this also avoids regressing W1's\n // accumulator invariant on mixed-ownership composites.\n const allUserOwned = isUserOwnedPerFile.every(Boolean);\n\n if (allUserOwned && patch.files.length > 0) {\n const baseChanged = patch.base_generation !== currentGenSha;\n\n // Rebase content hash against current generation so both the\n // no-patches and normal-regeneration flows produce identical\n // hashes for user-owned patches. preGenerationRebase (normal\n // flow) converts patch_content to `git diff currentGen HEAD`\n // and recomputes the hash. Without this, the no-patches flow\n // keeps the original formatPatch hash, which differs because\n // the diff base and format are both different (FER-9850, D5-D9).\n const userDiff = await this.git\n .exec([\"diff\", currentGenSha, \"--\", ...patch.files])\n .catch(() => null);\n let userDiffSnapshot: Record<string, string> | null = null;\n if (userDiff != null && userDiff.trim()) {\n const newHash = this.detector.computeContentHash(userDiff);\n patch.patch_content = userDiff;\n patch.content_hash = newHash;\n // rebasePatches only operates on `status === \"applied\"`\n // patches (clean merges). Working tree is the correctly\n // merged customer state at the new generation —\n // including any path renames carried by `patch.files`.\n // Snapshot capture here is what keeps snapshot keys\n // aligned with current paths across regen cycles\n // (W5 rename-churn relies on this).\n const snap = await this.readSnapshotFromDisk(patch.files);\n if (Object.keys(snap).length > 0) {\n userDiffSnapshot = snap;\n patch.theirs_snapshot = snap;\n }\n }\n\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n ...(!patch.user_owned ? { user_owned: true } : {}),\n ...(userDiff != null && userDiff.trim()\n ? {\n patch_content: patch.patch_content,\n content_hash: patch.content_hash,\n ...(userDiffSnapshot != null && Object.keys(userDiffSnapshot).length > 0\n ? { theirs_snapshot: userDiffSnapshot }\n : {})\n }\n : {})\n });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n patch.user_owned = true;\n keptAsUserOwned++;\n // Count as repointed when base advanced — tests track this.\n if (baseChanged) repointed++;\n continue;\n }\n\n // Mixed or generator-only patch — compute diff vs currentGen\n // for absorption/rebase decisions.\n //\n // FER-9983 note: rebasePatches uses the legacy cumulative\n // diff here (matching preGenerationRebase's behavior). The\n // provenance-aware dedup at line ~1140 below preserves\n // patches with distinct `original_commit`s when their\n // rebased content_hash converges. Per-patch surgical\n // scoping in this hot path interacts badly with bundled\n // user-owned files (file already in currentGen due to\n // commitGeneration), causing false absorption — kept legacy\n // here for safety. The customer-facing FER-9983 fix lives\n // in `commands/resolve.ts`.\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", ...patch.files]).catch(() => null);\n\n if (diff === null) continue;\n\n if (!diff.trim()) {\n if (hasProtectedFiles) {\n // Protected files — never absorb. Advance base_generation only.\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGenSha });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n keptAsUserOwned++;\n continue;\n }\n // Conflict-by-association guard: do not absorb if a predecessor\n // in this run conflicted on any of this patch's files. Empty\n // diff is suspicious here — disk was reset to OURS by marker\n // stripping, masking a real customization. Preserve as\n // unresolved so `fern replay resolve` can recover it.\n const overlapsConflicted = patch.files.some((f) => conflictedFilePaths.has(f));\n if (overlapsConflicted) {\n patch.status = \"unresolved\";\n try {\n this.lockManager.updatePatch(patch.id, { status: \"unresolved\" });\n } catch {\n // New patch — addPatch() in the caller carries the\n // in-memory status through into the lockfile.\n }\n this.warnings.push(\n `Patch ${patch.id} (${patch.original_message}) was preserved as unresolved ` +\n `because an earlier patch conflicted on the same file(s) (${patch.files.join(\", \")}). ` +\n `Run \\`fern replay resolve\\` to apply this customization manually.`\n );\n continue;\n }\n // Generator file with empty net effect — absorb.\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n\n if (hasProtectedFiles) {\n // Protected files with a real diff: keep patch_content as-is.\n // Only advance base_generation.\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGenSha });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n keptAsUserOwned++;\n continue;\n }\n\n // Generator files OR mixed patches with some user-owned files:\n // rebase patch_content to the canonical git-diff against new\n // generation.\n const newContentHash = this.detector.computeContentHash(diff);\n\n // Consolidate when another patch already captured this exact\n // diff. Two patches with byte-identical post-rebase\n // patch_content encode the SAME customer-side delta — applying\n // both back-to-back at the next regen produces duplicate-apply\n // corruption (the same lines spliced in twice). Consolidate\n // to one canonical patch; per-commit attribution is recoverable\n // from `git log -- <file>`. See preGenerationRebase for the\n // full rationale.\n const priorPatchId = seenContentHashes.get(newContentHash);\n if (priorPatchId !== undefined) {\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n if (priorPatchId !== patch.id) {\n this.warnings.push(\n `Consolidated patch ${patch.id} (commit ${(patch.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into prior patch ${priorPatchId}: byte-identical patch_content after rebase. ` +\n `Per-commit attribution preserved in git log.`\n );\n }\n continue;\n } else {\n seenContentHashes.set(newContentHash, patch.id);\n }\n\n // Mutate in-memory AND lockfile. For new patches (not yet added to\n // the lockfile), updatePatch throws; the in-memory mutation ensures\n // the correct values end up persisted when addPatch runs later.\n patch.base_generation = currentGenSha;\n patch.patch_content = diff;\n patch.content_hash = newContentHash;\n // Snapshot from working tree. Same rationale as the\n // user-owned branch above: only fires for cleanly-applied\n // patches (`status === \"applied\"` filter at the top of\n // the loop), so disk = correctly-merged customer state at\n // the new generation. Captures rename keys for next regen.\n const snapshot = await this.readSnapshotFromDisk(patch.files);\n const snapshotIsNonEmpty = Object.keys(snapshot).length > 0;\n if (snapshotIsNonEmpty) {\n patch.theirs_snapshot = snapshot;\n }\n try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash,\n ...(snapshotIsNonEmpty ? { theirs_snapshot: snapshot } : {})\n });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n contentRebased++;\n } catch {\n // If rebasing fails for any reason, keep the original patch unchanged\n }\n }\n\n return { absorbed, repointed, contentRebased, keptAsUserOwned, absorbedPatchIds };\n }\n\n /**\n * Read THEIRS snapshot (post-customer-edit content) for a list of files\n * from the working tree on disk. Used by `rebasePatches` after a clean\n * apply — disk = correctly-merged customer state at the new generation.\n * Skips binary files (matches `mergeFile`/`populateAccumulatorForPatch`\n * policy — binary content as `utf-8` is lossy and snapshots of it would\n * never be used during apply anyway).\n */\n private async readSnapshotFromDisk(files: string[]): Promise<Record<string, string>> {\n const snapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n try {\n const content = await readFileAsync(join(this.outputDir, file), \"utf-8\");\n snapshot[file] = content;\n } catch {\n // Missing file — omit (the file might have been deleted by the customer).\n }\n }\n return snapshot;\n }\n\n /**\n * FER-10203: returns true when a `[fern-autoversion]` commit between\n * `fromSha` and `toSha` touched any of the patch's `files`. Re-classifies\n * each grep match via `isGenerationCommit` so a customer commit that\n * merely quotes the marker in its body doesn't false-positive.\n */\n private async hasAutoversionContamination(\n fromSha: string,\n toSha: string,\n files: string[],\n ): Promise<boolean> {\n if (files.length === 0) return false;\n const log = await this.git\n .exec([\n \"log\",\n `${fromSha}..${toSha}`,\n \"--grep=\\\\[fern-autoversion\\\\]\",\n \"--extended-regexp\",\n \"--format=%H%x09%aN%x09%ae%x09%s\",\n \"--\",\n ...files,\n ])\n .catch(() => \"\");\n if (!log.trim()) return false;\n for (const line of log.trim().split(\"\\n\")) {\n const [sha, authorName, authorEmail, message] = line.split(\"\\t\");\n if (sha == null) continue;\n if (\n isGenerationCommit({\n sha,\n authorName: authorName ?? \"\",\n authorEmail: authorEmail ?? \"\",\n message: message ?? \"\",\n })\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * FER-10203: rebuild patch_content from `theirs_snapshot` (captured at\n * detection time, predates pipeline content) rather than a HEAD-relative\n * diff. Returns `null` when snapshot is missing or doesn't cover every\n * file in `patch.files` — caller leaves the patch unchanged.\n */\n private async computeSnapshotBasedPatchDiff(\n patch: StoredPatch,\n currentGen: string,\n ): Promise<string | null> {\n if (!patch.theirs_snapshot) return null;\n if (Object.keys(patch.theirs_snapshot).length === 0) return null;\n for (const file of patch.files) {\n if (patch.theirs_snapshot[file] == null) return null;\n }\n\n const fragments: string[] = [];\n for (const file of patch.files) {\n const theirsContent = patch.theirs_snapshot[file]!;\n const oursContent = await this.git.showFile(currentGen, file).catch(() => null);\n if (oursContent == null) {\n fragments.push(synthesizeNewFileDiff(file, theirsContent));\n continue;\n }\n if (oursContent === theirsContent) continue;\n const fileDiff = await unifiedDiff(oursContent, theirsContent, file);\n if (fileDiff.trim()) {\n fragments.push(fileDiff);\n }\n }\n return fragments.join(\"\");\n }\n\n /**\n * Read THEIRS snapshot from a git tree-ish (commit, branch, or tree).\n * Used when the diff that produced `patch_content` was relative to that\n * tree (e.g., `git diff currentGen HEAD --` → snapshot from HEAD).\n * Skips binary files.\n */\n private async readSnapshotFromTree(treeRef: string, files: string[]): Promise<Record<string, string>> {\n const snapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(treeRef, file).catch(() => null);\n if (content != null) snapshot[file] = content;\n }\n return snapshot;\n }\n\n /**\n * One-shot auto-migration: backfill `theirs_snapshot` on existing\n * patches that predate the snapshot encoding. Computes the snapshot by\n * applying the patch's `patch_content` to its `base_generation` tree —\n * yielding the patch's INDIVIDUAL contribution.\n *\n * **Skips patches sharing files with other patches.** HEAD's content\n * for a file shared by N patches is cumulative across all of them, so\n * a HEAD-fallback would falsely encode other patches' contributions\n * into one patch's snapshot — breaking FER-9525 cross-patch isolation\n * if the snapshot fallback later fires. Per-patch snapshots only\n * make sense when the patch owns its file. Multi-patch-same-file\n * legacy lockfiles keep using line-anchored reconstruction (the\n * existing path); they're no worse than pre-upgrade.\n *\n * **Does not fall back to HEAD when BASE-reconstruction fails.** Same\n * reason — HEAD content can be cumulative. Patches whose\n * reconstruction fails just don't get a snapshot; legacy paths\n * (PR #73's by-association gate, accumulator fallback) handle them.\n *\n * Skips patches that already have a snapshot.\n */\n private async migratePatchesToSnapshot(patches: StoredPatch[]): Promise<void> {\n const { applyPatchToContent } = await import(\"./PatchApplyTheirs.js\");\n // Identify files that appear in MULTIPLE patches in the lockfile.\n const fileFreq = new Map<string, number>();\n for (const p of patches) {\n for (const f of p.files) {\n fileFreq.set(f, (fileFreq.get(f) ?? 0) + 1);\n }\n }\n let migrated = 0;\n let skipped = 0;\n for (const patch of patches) {\n if (patch.theirs_snapshot != null) continue;\n const sharesAnyFile = patch.files.some((f) => (fileFreq.get(f) ?? 0) > 1);\n if (sharesAnyFile) {\n skipped++;\n continue;\n }\n const snapshot: Record<string, string> = {};\n for (const file of patch.files) {\n if (isBinaryFile(file)) continue;\n try {\n const base = await this.git.showFile(patch.base_generation, file).catch(() => null);\n if (base != null) {\n const content = await applyPatchToContent(base, patch.patch_content, file);\n if (content != null) snapshot[file] = content;\n }\n } catch {\n // Reconstruction failed — leave this file out of the snapshot.\n }\n }\n // Only persist when at least one file's snapshot was computed.\n // Empty snapshots provide no value and would suppress retries.\n if (Object.keys(snapshot).length > 0) {\n patch.theirs_snapshot = snapshot;\n try {\n this.lockManager.updatePatch(patch.id, { theirs_snapshot: snapshot });\n migrated++;\n } catch {\n // Patch not in lockfile yet (shouldn't happen here, but be defensive).\n }\n }\n }\n if (migrated > 0) {\n this.warnings.push(\n `Migrated ${migrated} patch(es) to snapshot encoding. Future regens use 3-way merge ` +\n `with stored THEIRS, robust to generator structural changes.`\n );\n }\n if (skipped > 0) {\n this.warnings.push(\n `Skipped snapshot migration for ${skipped} patch(es) sharing files with other patches. ` +\n `These continue to use line-anchored reconstruction (the existing path).`\n );\n }\n }\n\n /**\n * Determine whether `file` is user-owned (never produced by the generator).\n *\n * Resolution order (first match wins):\n * 1. `patch.user_owned === true` — authoritative, persisted across cycles.\n * 2. `.fernignore` itself, or file matches a .fernignore pattern.\n * 3. Legacy-safe signal: `patch_content` shows this file as a `--- /dev/null`\n * creation. Works for patches that predate the `user_owned` field or\n * whose flag was lost. Immune to rename tricks — relies on raw patch text.\n * 4. Tree-based check against `patch.base_generation` when it is reachable\n * AND distinct from `currentGenSha`. If the base tree is unreachable\n * (shallow clone / aggressive `git gc --prune`), emit a one-time\n * customer-actionable warning (deduplicated via warnedGens) and\n * conservatively treat as user-owned — strictly safer than silent\n * absorption (FER-9809).\n * 5. Final fallback — check `currentGenSha` when there is no usable base\n * (legacy one-gen lockfile). Preserves pre-fix behavior for that edge.\n *\n * `originalFileName` is the pre-rename path when the generator moved the\n * file between the patch's base and the current generation. Tree lookups\n * at ancestor generations use the original path — that's where the\n * generator produced the content.\n */\n private async isFileUserOwned(\n file: string,\n patch: StoredPatch,\n currentGenSha: string,\n fernignorePatterns: string[],\n warnedGens: Set<string>,\n originalFileName?: string,\n ): Promise<boolean> {\n if (patch.user_owned) return true;\n if (file === \".fernignore\") return true;\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) return true;\n\n // Legacy-safe: parse patch_content to see if THIS file's diff is a\n // `--- /dev/null` creation. Handles lockfiles that predate `user_owned`.\n if (this.fileIsCreationInPatchContent(patch.patch_content, originalFileName ?? file)) {\n return true;\n }\n\n const base = patch.base_generation;\n if (base && base !== currentGenSha) {\n const reachable =\n (await this.git.commitExists(base)) || (await this.git.treeExists(base));\n if (!reachable) {\n if (!warnedGens.has(base)) {\n warnedGens.add(base);\n this.warnings.push(\n `Base generation ${base.slice(0, 7)} is unreachable (shallow clone or pruned history). ` +\n `Treating affected files as user-owned to avoid silent data loss. ` +\n `Run \\`git fetch --unshallow\\` or avoid \\`git gc --prune\\` to restore full history.`\n );\n }\n return true;\n }\n return (await this.git.showFile(base, originalFileName ?? file)) === null;\n }\n\n // base_generation is missing or already bumped to currentGen. The current\n // gen tree cannot authoritatively distinguish user-created from bundled\n // files, but it's the only reference we have. Preserves pre-fix behavior.\n return (await this.git.showFile(currentGenSha, originalFileName ?? file)) === null;\n }\n\n /**\n * Returns true if `file`'s diff section in `patchContent` starts with\n * `--- /dev/null`, meaning this file was introduced by the patch (user\n * creation). Used as a legacy-safe fallback when `patch.user_owned` is\n * absent or cleared.\n */\n private fileIsCreationInPatchContent(patchContent: string, file: string): boolean {\n const lines = patchContent.split(\"\\n\");\n let inFileSection = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git \")) {\n inFileSection = line.includes(` b/${file}`) || line.endsWith(` b/${file}`);\n continue;\n }\n if (inFileSection && line.startsWith(\"--- \")) {\n return line === \"--- /dev/null\";\n }\n }\n return false;\n }\n\n /**\n * For conflict patches with mixed results (some files merged, some conflicted),\n * check if the cleanly merged files were absorbed by the generator (empty diff).\n * If so, remove them from patch.files so they don't pollute the pre-generation\n * rebase conflict marker check (`git grep <<<<<<< -- ...patch.files`).\n *\n * Non-absorbed clean files stay in patch.files — removing them would lose\n * the customization on the next generation.\n */\n private async trimAbsorbedFiles(result: ReplayResult, currentGenSha: string): Promise<void> {\n const cleanFiles = result.fileResults!.filter((f) => f.status === \"merged\").map((f) => f.file);\n if (cleanFiles.length === 0) return;\n\n const patch = result.patch;\n // If the entire patch is persisted as user-owned, nothing is ever a\n // generator-clean candidate for trimming — short-circuit.\n if (patch.user_owned) return;\n\n const fernignorePatterns = this.readFernignorePatterns();\n const warnedGens = new Set<string>();\n\n // Filter to only generator-produced clean files (not user-owned)\n const generatorCleanFiles: string[] = [];\n for (const file of cleanFiles) {\n if (await this.isFileUserOwned(file, patch, currentGenSha, fernignorePatterns, warnedGens)) {\n continue; // user-owned file — never a candidate for absorption trimming\n }\n generatorCleanFiles.push(file);\n }\n if (generatorCleanFiles.length === 0) return;\n\n // Check which clean files have an empty diff (absorbed by generator)\n const absorbedFiles = new Set<string>();\n for (const file of generatorCleanFiles) {\n try {\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", file]).catch(() => null);\n if (!diff || !diff.trim()) {\n absorbedFiles.add(file);\n }\n } catch {\n // If diff fails, leave the file in the patch\n }\n }\n if (absorbedFiles.size === 0) return;\n\n // Remove absorbed files from the patch's file list\n const remainingFiles = patch.files.filter((f) => !absorbedFiles.has(f));\n if (remainingFiles.length === patch.files.length) return; // nothing changed\n\n try {\n this.lockManager.updatePatch(patch.id, { files: remainingFiles });\n } catch {\n // New patches aren't in lockfile yet — update in-memory only\n patch.files = remainingFiles;\n }\n }\n\n /**\n * Pre-generation rebase: update patches using the customer's current state.\n * Called BEFORE commitGeneration() while HEAD has customer code.\n */\n private async preGenerationRebase(\n patches: StoredPatch[]\n ): Promise<{ conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number }> {\n const lock = this.lockManager.read();\n const currentGen = lock.current_generation;\n\n // If the previous run was skip-application, clear the marker and\n // skip all revert detection. Patches are preserved as-is.\n if (this.lockManager.isReplaySkipped()) {\n this.lockManager.clearReplaySkippedAt();\n return { conflictResolved: 0, conflictAbsorbed: 0, contentRefreshed: 0 };\n }\n\n // Auto-migrate legacy patches lacking `theirs_snapshot` to the new\n // encoding. One-shot per existing patch — once migrated, future\n // regens use the snapshot path. Compute snapshot from BASE +\n // patch_content (same logic the slow apply path uses today and\n // already trusts). Falls back to HEAD content if BASE is GC'd.\n await this.migratePatchesToSnapshot(patches);\n\n // Detect whether HEAD is a [fern-generated] commit AND it changed\n // *source* files (vs HEAD~1) — the discriminator for the\n // \"manually-staged-generation-at-HEAD\" bug case where `git diff\n // currentGen HEAD -- file` would produce generator-vs-generator\n // content (not customer intent) and corrupt patch_content/snapshot.\n //\n // Test helpers and infrastructure commits (e.g.,\n // `[fern-generated] store patches` that only touches .fern/) are\n // also generation commits but DON'T change source — they're safe\n // to content-refresh against. The HEAD~1 source-diff check\n // distinguishes these: the bug case mutates a source file vs its\n // parent (customer's last code → generator output), while infra\n // commits don't.\n //\n // Per-patch evaluation happens below — this just precomputes the\n // generation-author signal.\n const headMessage = await this.git.exec([\"log\", \"-1\", \"--format=%s%n%aN%n%ae\", \"HEAD\"]).catch(() => \"\");\n const [headMsgLine, headAuthorName, headAuthorEmail] = headMessage.split(\"\\n\");\n const headIsGeneration = headMsgLine\n ? isGenerationCommit({\n sha: \"HEAD\",\n authorName: headAuthorName ?? \"\",\n authorEmail: headAuthorEmail ?? \"\",\n message: headMsgLine\n })\n : false;\n const headParentChangedFiles = async (patchFiles: string[]): Promise<Set<string>> => {\n if (patchFiles.length === 0) return new Set();\n const diff = await this.git\n .exec([\"diff\", \"--name-only\", \"HEAD~1\", \"HEAD\", \"--\", ...patchFiles])\n .catch(() => \"\");\n return new Set(diff.trim().split(\"\\n\").filter(Boolean));\n };\n\n let conflictResolved = 0;\n let conflictAbsorbed = 0;\n let contentRefreshed = 0;\n const fernignorePatterns = this.readFernignorePatterns();\n const warnedGens = new Set<string>();\n // Cache reachability checks per-SHA to avoid repeating commitExists/treeExists\n // git subprocess calls for the same base across many patches (N patches ×\n // 2 calls is the main per-cycle cost in long-horizon scenarios like W11).\n const reachabilityCache = new Map<string, boolean>();\n const isReachable = async (sha: string): Promise<boolean> => {\n const cached = reachabilityCache.get(sha);\n if (cached !== undefined) return cached;\n const reachable =\n (await this.git.commitExists(sha)) || (await this.git.treeExists(sha));\n reachabilityCache.set(sha, reachable);\n return reachable;\n };\n\n // FER-9809: a patch whose every file is user-owned produces an empty diff\n // between currentGen and HEAD (because commitGeneration bundled the file\n // into currentGen — both sides are identical). That empty diff is NOT a\n // revert signal. Only patches with at least one generator-produced file\n // can have their emptiness legitimately interpreted as \"user reverted.\"\n const allPatchFilesUserOwned = async (patch: StoredPatch): Promise<boolean> => {\n if (patch.user_owned) return true;\n if (patch.files.length === 0) return false;\n for (const file of patch.files) {\n if (!(await this.isFileUserOwned(file, patch, currentGen, fernignorePatterns, warnedGens))) {\n return false;\n }\n }\n return true;\n };\n\n for (const patch of patches) {\n // FER-9809: surface a warning when the patch's declared base_generation\n // is unreachable (shallow clone / aggressive `git gc --prune`). Check\n // this BEFORE any status gating — the warning is a reachability signal\n // independent of whether the patch is currently unresolved/resolving.\n if (\n patch.base_generation &&\n patch.base_generation !== currentGen &&\n !warnedGens.has(patch.base_generation)\n ) {\n if (!(await isReachable(patch.base_generation))) {\n warnedGens.add(patch.base_generation);\n this.warnings.push(\n `Base generation ${patch.base_generation.slice(0, 7)} is unreachable ` +\n `(shallow clone or pruned history). Treating affected files as user-owned ` +\n `to avoid silent data loss. ` +\n `Run \\`git fetch --unshallow\\` or avoid \\`git gc --prune\\` to restore full history.`\n );\n }\n }\n\n // Skip patches with any status (unresolved/resolving) — they weren't\n // successfully applied last time. Clear status so applyPatches() can\n // try them against the new generation.\n if (patch.status != null) {\n delete patch.status;\n continue;\n }\n\n // When HEAD is a generation commit AND it mutated this patch's\n // source files vs its parent, the customer manually staged a\n // new generation at HEAD without running replay. Both the\n // content-refresh and stale-base branches below would treat\n // `git diff currentGen → HEAD` as customer intent — but here\n // it's generator-vs-generator structural changes (the customer\n // overwrote their own resolved file with the generator's new\n // output). Refreshing patch_content/snapshot with that diff\n // silently erases the customization. Skip and let the patch\n // survive intact; `mergeFile`'s slow path will reconcile via\n // 3-way merge against the (still-valid) theirs_snapshot.\n //\n // Infrastructure [fern-generated] commits (e.g. test helpers,\n // store-patches commits) don't mutate source files vs parent,\n // so they fall through to the normal refresh path.\n if (headIsGeneration) {\n const parentChangedFiles = await headParentChangedFiles(patch.files);\n const headTouchedSource = patch.files.some((f) => parentChangedFiles.has(f));\n if (headTouchedSource) {\n continue;\n }\n }\n\n if (patch.base_generation === currentGen) {\n // Content refresh: check if user modified their customization\n // since the last replay commit. FER-10203: when autoversion\n // contaminated HEAD, route via snapshot-based reconstruction.\n try {\n const contaminated = await this.hasAutoversionContamination(\n currentGen,\n \"HEAD\",\n patch.files,\n );\n\n if (contaminated) {\n const snapshotDiff = await this.computeSnapshotBasedPatchDiff(\n patch,\n currentGen,\n );\n if (snapshotDiff === null) continue;\n if (!snapshotDiff.trim()) {\n if (await allPatchFilesUserOwned(patch)) continue;\n this.lockManager.removePatch(patch.id);\n contentRefreshed++;\n continue;\n }\n const snapHasStaleMarkers = snapshotDiff.split(\"\\n\").some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (snapHasStaleMarkers) continue;\n const isProtectedSnap = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n if (isProtectedSnap) continue;\n const snapHash = this.detector.computeContentHash(snapshotDiff);\n if (snapHash !== patch.content_hash) {\n this.lockManager.updatePatch(patch.id, {\n patch_content: snapshotDiff,\n content_hash: snapHash,\n });\n contentRefreshed++;\n }\n continue;\n }\n\n const ppResult = await computePerPatchDiffWithFallback(\n patch,\n (f) => this.git.showFile(currentGen, f),\n (f) => this.git.showFile(\"HEAD\", f),\n (files) => this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...files])\n .catch(() => null)\n );\n\n if (ppResult === null) continue;\n const diff = ppResult.diff;\n\n if (!diff.trim()) {\n // Empty diff usually means customer reverted the\n // customization. But if every file is user-owned, empty\n // diff is expected (the generator bundled the files\n // into currentGen) — preserve the patch (FER-9809).\n if (await allPatchFilesUserOwned(patch)) continue;\n // User reverted all customizations in this patch\n this.lockManager.removePatch(patch.id);\n contentRefreshed++;\n continue;\n }\n\n // Skip content refresh if the diff contains stale conflict\n // markers from a previous crashed run. Only check added lines\n // (prefixed with \"+\") to avoid false positives from files that\n // legitimately contain marker text (e.g., documentation).\n const diffLines = diff.split(\"\\n\");\n const hasStaleMarkers = diffLines.some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (hasStaleMarkers) {\n continue;\n }\n\n // Skip content conversion for .fernignore-protected files —\n // matches rebasePatches' behavior so both flows end with\n // identical patch_content for the same scenario (FER-9810).\n // User-created (non-protected) files go through the regular\n // content-refresh path so they can be deduplicated when\n // multiple incremental patches resolve to the same cumulative\n // state.\n const isProtected = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n if (isProtected) {\n continue;\n }\n\n const newContentHash = this.detector.computeContentHash(diff);\n if (newContentHash !== patch.content_hash) {\n // User changed their customization — update patch content\n // and recalculate the files list (some files may no longer differ)\n const filesOutput = await this.git\n .exec([\"diff\", \"--name-only\", currentGen, \"HEAD\", \"--\", ...patch.files])\n .catch(() => null);\n\n const newFiles = filesOutput\n ? filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !f.startsWith(\".fern/\"))\n : patch.files;\n\n if (newFiles.length === 0) {\n this.lockManager.removePatch(patch.id);\n } else {\n // Snapshot THEIRS from HEAD (the diff is\n // currentGen → HEAD). The `headIsGeneration`\n // early-continue above already protects against\n // the manual-gen-commit-at-HEAD case (where HEAD\n // is generator content with no customer intent).\n // For genuine customer edits, HEAD is the\n // authoritative customer state — refresh\n // snapshot to match so subsequent regens see\n // the customer's latest intent.\n const snapshot = await this.readSnapshotFromTree(\"HEAD\", newFiles);\n this.lockManager.updatePatch(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n files: newFiles,\n ...(Object.keys(snapshot).length > 0 ? { theirs_snapshot: snapshot } : {})\n });\n }\n contentRefreshed++;\n }\n } catch {\n // If anything fails, leave the patch unchanged\n }\n continue;\n }\n\n try {\n // Check for unresolved conflict markers in HEAD\n const markerFiles = await this.git\n .exec([\"grep\", \"-l\", \"<<<<<<< Generated\", \"HEAD\", \"--\", ...patch.files])\n .catch(() => \"\");\n\n if (markerFiles.trim()) continue;\n\n // FER-10203: snapshot-based reconstruction when contaminated.\n const contaminated = await this.hasAutoversionContamination(\n currentGen,\n \"HEAD\",\n patch.files,\n );\n\n if (contaminated) {\n const snapshotDiff = await this.computeSnapshotBasedPatchDiff(\n patch,\n currentGen,\n );\n if (snapshotDiff === null) continue;\n if (!snapshotDiff.trim()) {\n if (await allPatchFilesUserOwned(patch)) {\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGen });\n } catch {\n // New patch — not in lockfile yet\n }\n continue;\n }\n this.lockManager.removePatch(patch.id);\n conflictAbsorbed++;\n continue;\n }\n const snapHasStaleMarkers = snapshotDiff.split(\"\\n\").some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (snapHasStaleMarkers) continue;\n const snapHash = this.detector.computeContentHash(snapshotDiff);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: snapshotDiff,\n content_hash: snapHash,\n });\n conflictResolved++;\n continue;\n }\n\n // FER-9983: per-patch-region diff with cumulative fallback for\n // unlocatable subset (see content-refresh branch above for\n // the BLOCKER B2 rationale).\n const ppResult = await computePerPatchDiffWithFallback(\n patch,\n (f) => this.git.showFile(currentGen, f),\n (f) => this.git.showFile(\"HEAD\", f),\n (files) => this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...files])\n .catch(() => null)\n );\n\n // ppResult === null only when cumulative fallback explicitly\n // failed — skip the patch rather than corrupt the lockfile.\n if (ppResult === null) continue;\n const diff = ppResult.diff;\n\n if (!diff.trim()) {\n // Empty diff: for user-owned patches this is expected\n // (currentGen has bundled copies), not a revert signal.\n if (await allPatchFilesUserOwned(patch)) {\n // Repoint stale base onto current so the next cycle\n // routes via the fast content-refresh branch.\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGen });\n } catch {\n // New patches aren't in lockfile yet\n }\n continue;\n }\n // Empty diff — customer reverted their customization\n this.lockManager.removePatch(patch.id);\n conflictAbsorbed++;\n continue;\n }\n\n // Update the patch with the resolved content. The\n // `headIsGeneration` early-continue above protects the\n // bug case (HEAD is a generator commit with no customer\n // intent). For genuine customer resolutions, refresh\n // snapshot from HEAD too.\n const newContentHash = this.detector.computeContentHash(diff);\n const snapshot = await this.readSnapshotFromTree(\"HEAD\", patch.files);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: diff,\n content_hash: newContentHash,\n ...(Object.keys(snapshot).length > 0 ? { theirs_snapshot: snapshot } : {})\n });\n conflictResolved++;\n } catch {\n // If anything fails, leave the patch unchanged\n }\n }\n\n return { conflictResolved, conflictAbsorbed, contentRefreshed };\n }\n\n /**\n * After applyPatches(), surface a warning for each (patch × file) where\n * diff3 silently dropped lines that were unchanged context in the\n * customer's THEIRS. The deletion stays on disk (correct diff3 outcome),\n * but the customer must learn so they can re-add the lines if they\n * relied on them. This is the \"surface or preserve, never silently drop\"\n * contract for legitimate-deletion cases.\n */\n private recordDroppedContextLineWarnings(results: ReplayResult[]): void {\n const PREVIEW_COUNT = 5;\n for (const result of results) {\n if (!result.fileResults) continue;\n for (const fr of result.fileResults) {\n const dropped = fr.droppedContextLines;\n if (!dropped || dropped.length === 0) continue;\n const preview = dropped\n .slice(0, PREVIEW_COUNT)\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n const more = dropped.length > PREVIEW_COUNT\n ? `\\n ... and ${dropped.length - PREVIEW_COUNT} more`\n : \"\";\n this.warnings.push(\n `${fr.file}: ${dropped.length} line(s) that appeared as unchanged ` +\n `context in your customization were deleted by the new generator output. ` +\n `The merge followed the deletion. First lines deleted:\\n${preview}${more}\\n` +\n `If you want to keep these lines, restore them in a follow-up commit and ` +\n `re-run replay; otherwise this warning can be safely ignored.`\n );\n }\n }\n }\n\n /**\n * After applyPatches(), strip conflict markers from conflicting files\n * so only clean content is committed. Keeps the Generated (OURS) side.\n */\n private revertConflictingFiles(results: ReplayResult[]): void {\n for (const result of results) {\n if (result.status !== \"conflict\" || !result.fileResults) continue;\n\n for (const fileResult of result.fileResults) {\n if (fileResult.status !== \"conflict\") continue;\n\n const filePath = join(this.outputDir, fileResult.file);\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const stripped = stripConflictMarkers(content);\n writeFileSync(filePath, stripped);\n } catch {\n // If file doesn't exist or can't be read, skip\n }\n }\n }\n }\n\n /**\n * Clean up stale conflict markers left by a previous crashed run.\n * Called after commitGeneration() when HEAD is the [fern-generated] commit.\n * Restores files to their clean generated state from HEAD.\n * Skips .fernignore-protected files to prevent overwriting user content.\n */\n private async cleanupStaleConflictMarkers(): Promise<void> {\n const markerFiles = await this.git\n .exec([\"grep\", \"-l\", \"<<<<<<< Generated\", \"--\", \".\"])\n .catch(() => \"\");\n\n const files = markerFiles.trim().split(\"\\n\").filter(Boolean);\n if (files.length === 0) return;\n\n const fernignorePatterns = this.readFernignorePatterns();\n\n for (const file of files) {\n if (fernignorePatterns.some((pattern) => minimatch(file, pattern))) continue;\n\n try {\n await this.git.exec([\"checkout\", \"HEAD\", \"--\", file]);\n } catch {\n // File may not exist in the generation tree (e.g., user-created\n // file). Skip — revertConflictingFiles will handle it later.\n }\n }\n }\n\n private readFernignorePatterns(): string[] {\n const fernignorePath = join(this.outputDir, \".fernignore\");\n if (!existsSync(fernignorePath)) return [];\n return readFileSync(fernignorePath, \"utf-8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n }\n\n private buildReport(\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\",\n patches: StoredPatch[],\n results: ReplayResult[],\n options?: ReplayOptions,\n warnings?: string[],\n rebaseCounts?: {\n absorbed: number;\n repointed: number;\n contentRebased: number;\n keptAsUserOwned: number;\n absorbedPatchIds: Set<string>;\n },\n preRebaseCounts?: { conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number },\n patchesReverted?: number\n ): ReplayReport {\n const conflictResults = results.filter((r) => r.status === \"conflict\");\n const conflictDetails = conflictResults\n .map((r) => {\n const conflictFiles = r.fileResults?.filter((f) => f.status === \"conflict\") ?? [];\n const cleanFiles = r.fileResults?.filter((f) => f.status === \"merged\").map((f) => f.file) ?? [];\n return {\n patchId: r.patch.id,\n patchMessage: r.patch.original_message,\n reason: r.conflictReason,\n files: conflictFiles,\n cleanFiles: cleanFiles.length > 0 ? cleanFiles : undefined\n };\n })\n .filter((d) => d.files.length > 0);\n const partialCount = conflictDetails.filter((d) => d.cleanFiles && d.cleanFiles.length > 0).length;\n\n // Widen unresolvedPatches to include conflict-by-association entries:\n // patches whose result.status is \"applied\" but whose patch.status was\n // set to \"unresolved\" by the rebase guard (clean follow-up after\n // same-file conflict). They have no file-level merge conflicts of\n // their own but must surface so the resolve workflow handles them.\n const unresolvedResults = results.filter(\n (r) => r.status === \"conflict\" || r.patch.status === \"unresolved\"\n );\n\n return {\n flow,\n patchesDetected: patches.length,\n patchesApplied: results.filter((r) => r.status === \"applied\").length,\n patchesWithConflicts: conflictResults.length,\n patchesSkipped: results.filter((r) => r.status === \"skipped\").length,\n patchesPartiallyApplied: partialCount > 0 ? partialCount : undefined,\n patchesAbsorbed: rebaseCounts && rebaseCounts.absorbed > 0 ? rebaseCounts.absorbed : undefined,\n patchesRepointed: rebaseCounts && rebaseCounts.repointed > 0 ? rebaseCounts.repointed : undefined,\n patchesContentRebased:\n rebaseCounts && rebaseCounts.contentRebased > 0 ? rebaseCounts.contentRebased : undefined,\n patchesKeptAsUserOwned:\n rebaseCounts && rebaseCounts.keptAsUserOwned > 0 ? rebaseCounts.keptAsUserOwned : undefined,\n patchesReverted: patchesReverted && patchesReverted > 0 ? patchesReverted : undefined,\n patchesConflictResolved:\n preRebaseCounts && preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed > 0\n ? preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed\n : undefined,\n patchesRefreshed:\n preRebaseCounts && preRebaseCounts.contentRefreshed > 0 ? preRebaseCounts.contentRefreshed : undefined,\n conflicts: conflictResults.flatMap((r) => r.fileResults?.filter((f) => f.status === \"conflict\") ?? []),\n conflictDetails: conflictDetails.length > 0 ? conflictDetails : undefined,\n unresolvedPatches:\n unresolvedResults.length > 0\n ? unresolvedResults.map((r) => ({\n patchId: r.patch.id,\n patchMessage: r.patch.original_message,\n files: r.patch.files,\n conflictDetails: r.fileResults?.filter((f) => f.status === \"conflict\") ?? []\n }))\n : undefined,\n wouldApply: options?.dryRun ? patches : undefined,\n warnings: warnings && warnings.length > 0 ? warnings : undefined\n };\n }\n}\n\n/**\n * Bucket the patches given to commitReplay so the commit message body is\n * an honest reflection of outcomes. A patch is:\n * - `unresolved`: file-level merge conflict OR PR #73 conflict-by-association\n * (`patch.status === \"unresolved\"` set by `rebasePatches`)\n * - `absorbed`: in `absorbedPatchIds` (rebase removed it because the\n * generator now emits the customization natively)\n * - `applied`: everything else with status === \"applied\"\n * Skipped/binary patches don't surface in the commit message at all.\n *\n * `patchesPassedToCommit` is what the caller hands to `commitReplay` (e.g.,\n * `allPatches` for normal regen, `newPatches` for the no-patches flow).\n * The function preserves its order so the commit body matches lockfile order.\n */\nfunction computeCommitBuckets(\n results: ReplayResult[],\n absorbedPatchIds: Set<string>,\n patchesPassedToCommit: StoredPatch[]\n): { applied: StoredPatch[]; unresolved: StoredPatch[]; absorbed: StoredPatch[] } {\n const resultByPatchId = new Map<string, ReplayResult>();\n for (const r of results) resultByPatchId.set(r.patch.id, r);\n\n const applied: StoredPatch[] = [];\n const unresolved: StoredPatch[] = [];\n const absorbed: StoredPatch[] = [];\n\n for (const patch of patchesPassedToCommit) {\n if (absorbedPatchIds.has(patch.id)) {\n absorbed.push(patch);\n continue;\n }\n const r = resultByPatchId.get(patch.id);\n if (!r) {\n // No result (e.g., patch wasn't applied this cycle but is in\n // the lockfile). Treat as applied for legacy parity — the\n // alternative would silently disappear from the commit body.\n applied.push(patch);\n continue;\n }\n if (r.status === \"conflict\" || patch.status === \"unresolved\") {\n unresolved.push(patch);\n continue;\n }\n if (r.status === \"applied\") {\n applied.push(patch);\n continue;\n }\n // status === \"skipped\" — omit. Skipped patches typically come from\n // exclude patterns; surfacing them in the commit body is noise.\n }\n\n return { applied, unresolved, absorbed };\n}\n","/**\n * Per-patch contribution diff (FER-9983).\n *\n * Given a stored patch, the post-regen `currentGen` content of each file, and\n * the working-tree (post-resolution) content, compute a unified diff that\n * captures ONLY this patch's contribution — scoped to the regions identified\n * by the patch's stored hunks via context-line anchoring.\n *\n * Why this exists: `git diff currentGen -- patch.files` returns the full\n * cumulative diff for those files. When two patches share a file, the\n * cumulative diff includes BOTH patches' customizations — which means each\n * patch ends up with the same `patch_content` and `content_hash`. The\n * dedup-by-hash logic downstream then collapses them into one and silently\n * loses provenance.\n */\n\nimport { mkdtemp, writeFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport { parseHunks, locateHunksInOurs, type DiffHunk, type LocatedHunk } from \"./HybridReconstruction.js\";\n\n/**\n * Trim a hunk's body to exactly the line counts declared in its `@@` header.\n *\n * `parseHunks` keeps appending lines to a hunk's body until it hits the next\n * `@@` header or end of input. When the patch text has trailing blank lines\n * (e.g. from a trailing newline in the multi-file diff), those blanks get\n * conflated with context lines (per the helper's \"bare empty = context\"\n * heuristic), inflating the parsed body past `oldCount`/`newCount`. That\n * inflation causes `locateHunksInOurs` to overshoot when computing\n * `oursSpan` because trailing context anchoring lands on lines beyond the\n * hunk's actual region.\n */\nfunction normalizeHunkBody(hunk: DiffHunk): DiffHunk {\n let contextC = 0;\n let removeC = 0;\n let addC = 0;\n const trimmed: typeof hunk.lines = [];\n for (const line of hunk.lines) {\n const oldUsed = contextC + removeC;\n const newUsed = contextC + addC;\n if (oldUsed >= hunk.oldCount && newUsed >= hunk.newCount) break;\n trimmed.push(line);\n if (line.type === \"context\") contextC++;\n else if (line.type === \"remove\") removeC++;\n else if (line.type === \"add\") addC++;\n }\n return { ...hunk, lines: trimmed };\n}\n\nexport interface PerPatchDiffResult {\n /** Concatenated unified diff (one `diff --git` block per file). Empty string if patch contributes nothing. */\n diff: string;\n /** Files where the patch's hunks could not be anchored against either currentGen or working tree. Caller should fall back. */\n unlocatableFiles: string[];\n}\n\n/**\n * Extract the per-file unified diff for `filePath` from a multi-file unified diff.\n * Mirrors `ReplayApplicator.extractFileDiff` — kept here to avoid cross-module\n * private-method exposure.\n */\nexport function extractFileDiffForFile(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const out: string[] = [];\n let inTarget = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTarget) break;\n if (isDiffLineForFile(line, filePath)) {\n inTarget = true;\n out.push(line);\n }\n continue;\n }\n if (inTarget) out.push(line);\n }\n return out.length > 0 ? out.join(\"\\n\") + \"\\n\" : null;\n}\n\nfunction isDiffLineForFile(line: string, filePath: string): boolean {\n // Use anchored regex (matches `ReplayApplicator.ts` pattern) to avoid\n // substring false positives — e.g. `src/user.ts` matching `src/user.tsx`,\n // or `lib/foo.ts` matching `lib/foo.ts-backup`. Match on the b-path\n // (post-image) since it's the canonical destination, including for\n // renames (`diff --git a/old b/new`).\n const match = line.match(/^diff --git a\\/(.+) b\\/(.+)$/);\n return match !== null && (match[2] === filePath || match[1] === filePath);\n}\n\n/**\n * Compute the per-patch contribution diff.\n *\n * The caller owns content reads via `getCurrentGenContent` / `getWorkingTreeContent`\n * so that the helper is reusable from `resolve.ts` (reads from disk) and\n * `rebasePatches` (reads from git tree + disk).\n *\n * Algorithm:\n * 1. For each file in `patch.files`:\n * a. Parse the patch's hunks for this file.\n * b. Anchor the hunks in `currentGen` content via `locateHunksInOurs`.\n * c. Anchor the hunks in `workingTree` content via `locateHunksInOurs`.\n * d. Overlay each anchored region from working tree onto currentGen,\n * producing a \"currentGen + just this patch's contribution\" string.\n * e. Compute a unified diff between currentGen and that overlay via\n * `git diff --no-index`. This is the per-patch diff for the file.\n * 2. Concatenate per-file diffs.\n *\n * Falls back to `unlocatableFiles` for files where steps b/c fail (rename,\n * heavy generator restructure, etc.) — caller's responsibility to handle.\n */\nexport async function computePerPatchDiff(\n patch: { patch_content: string; files: string[] },\n getCurrentGenContent: (file: string) => Promise<string | null>,\n getWorkingTreeContent: (file: string) => Promise<string | null>\n): Promise<PerPatchDiffResult> {\n const fragments: string[] = [];\n const unlocatableFiles: string[] = [];\n\n for (const file of patch.files) {\n const fileDiff = extractFileDiffForFile(patch.patch_content, file);\n if (fileDiff == null) {\n // patch.files lists this path, but patch_content doesn't reference it.\n // This commonly happens after a generator rename (resolvedFiles pre-pass\n // updated patch.files to the NEW path, but patch_content still uses the\n // OLD path). Treat as unlocatable so the caller falls back to the legacy\n // cumulative-file diff for this file.\n unlocatableFiles.push(file);\n continue;\n }\n\n const hunksRaw = parseHunks(fileDiff).map(normalizeHunkBody);\n // M1: drop hunks whose body is empty after trimming or whose body\n // line counts don't match the `@@` header. Either is a sign of a\n // malformed/truncated diff; passing them downstream into\n // `locateHunksInOurs` would yield garbage offsets and silently\n // corrupt the overlay.\n const hunks = hunksRaw.filter((h) => {\n if (h.lines.length === 0) return false;\n let ctx = 0, rm = 0, add = 0;\n for (const ln of h.lines) {\n if (ln.type === \"context\") ctx++;\n else if (ln.type === \"remove\") rm++;\n else if (ln.type === \"add\") add++;\n }\n return ctx + rm === h.oldCount && ctx + add === h.newCount;\n });\n if (hunks.length === 0) {\n // If parseHunks returned hunks but none survived the body check,\n // signal unlocatable so the caller falls back to cumulative diff.\n if (hunksRaw.length > 0) unlocatableFiles.push(file);\n continue;\n }\n\n const currentGen = await getCurrentGenContent(file);\n const workingTree = await getWorkingTreeContent(file);\n\n // Determine whether the patch is a pure new-file patch (no remove lines\n // anywhere). True new-file patches have all hunks with oldCount === 0.\n const isPureNewFile = hunks.every((h) => h.oldCount === 0);\n const isPureDelete = hunks.every((h) => h.newCount === 0);\n\n // New-file patch: file didn't exist in currentGen. Only valid if patch is\n // genuinely a new-file patch — otherwise we may be in the ghost case\n // (currentGen tree unreachable for a file the patch knows existed).\n if (currentGen == null) {\n if (!isPureNewFile) {\n unlocatableFiles.push(file);\n continue;\n }\n if (workingTree == null) continue;\n fragments.push(synthesizeNewFileDiff(file, workingTree));\n continue;\n }\n\n // Pure-new-file patch where currentGen ALREADY has the file: this is\n // the FER-9809 user-owned bundling case (a previous generation commit\n // bundled the customer's file into the gen tree). Compare full\n // contents directly — anchoring an empty `oldSide` would over-grab.\n // If contents match → no contribution since last cycle. If they\n // differ → customer modified, emit a full-file diff.\n if (isPureNewFile) {\n if (workingTree == null) {\n // File deleted in working tree → emit deletion diff.\n fragments.push(synthesizeDeleteFileDiff(file, currentGen));\n continue;\n }\n if (workingTree === currentGen) {\n // No change since bundling — no contribution.\n continue;\n }\n const fullDiff = await unifiedDiff(currentGen, workingTree, file);\n if (fullDiff && fullDiff.trim()) fragments.push(fullDiff);\n continue;\n }\n\n // Deleted in working tree: file existed in currentGen.\n if (workingTree == null) {\n if (!isPureDelete) {\n unlocatableFiles.push(file);\n continue;\n }\n fragments.push(synthesizeDeleteFileDiff(file, currentGen));\n continue;\n }\n\n const currentGenLines = splitLines(currentGen);\n const workingTreeLines = splitLines(workingTree);\n\n const locInCurrentGenRaw = locateHunksInOurs(hunks, currentGenLines);\n const locInWorkingTreeRaw = locateHunksInOurs(hunks, workingTreeLines);\n\n if (locInCurrentGenRaw == null || locInWorkingTreeRaw == null) {\n unlocatableFiles.push(file);\n continue;\n }\n\n // FER-9983: HybridReconstruction.computeOursSpan returns the context\n // count when trailing context is empty, which doesn't account for\n // remove/add lines. Re-derive span by content matching with a\n // domain hint: currentGen is expected to look like the patch's \"old\"\n // side (pre-patch); workingTree is expected to look like the \"new\"\n // side (post-patch). The hint disambiguates pure-insertion hunks\n // where oldSide is a prefix of newSide and both fit by coincidence.\n const locInCurrentGen = locInCurrentGenRaw.map((l) =>\n resolveSpan(l, currentGenLines, \"old\")\n );\n const locInWorkingTree = locInWorkingTreeRaw.map((l) =>\n resolveSpan(l, workingTreeLines, \"new\")\n );\n\n // Overlay each region from working tree onto currentGen.\n const overlay = overlayRegions(\n currentGenLines,\n locInCurrentGen,\n workingTreeLines,\n locInWorkingTree\n );\n\n // M2: overlay returned null → invariant violation (mismatched\n // anchored hunk counts). Signal unlocatable so caller falls back\n // to cumulative; do NOT silently treat as \"no contribution\".\n if (overlay === null) {\n unlocatableFiles.push(file);\n continue;\n }\n\n if (overlay === currentGen) {\n // Patch contributed nothing in this file — customer reverted or absorbed.\n continue;\n }\n\n const fileUnifiedDiff = await unifiedDiff(currentGen, overlay, file);\n if (fileUnifiedDiff && fileUnifiedDiff.trim()) {\n fragments.push(fileUnifiedDiff);\n }\n }\n\n return {\n diff: fragments.join(\"\"),\n unlocatableFiles\n };\n}\n\n/**\n * Combine a per-patch diff with a cumulative-diff fallback for any files\n * whose hunks couldn't be anchored. This is the helper used by both\n * `commands/resolve.ts` and `ReplayService.preGenerationRebase` to ensure\n * unlocatable files don't silently drop the patch when the locatable\n * subset's per-patch diff is empty (FER-9983 BLOCKER B1/B2).\n *\n * Algorithm:\n * 1. Run per-patch diff on `patch.files`.\n * 2. If `unlocatableFiles` is non-empty, run cumulative diff scoped to\n * ONLY those unlocatable files via `runCumulativeDiff(files)`.\n * 3. Concatenate the two. Return null if the cumulative invocation fails.\n *\n * Returns:\n * - `{ diff, hadFallback }` where `diff` may be empty (true patch revert)\n * and `hadFallback` indicates whether the cumulative subset was used.\n * - `null` if the cumulative invocation explicitly failed (callers should\n * skip the patch — same semantics as a missing diff).\n */\nexport async function computePerPatchDiffWithFallback(\n patch: { patch_content: string; files: string[] },\n getCurrentGenContent: (file: string) => Promise<string | null>,\n getWorkingTreeContent: (file: string) => Promise<string | null>,\n runCumulativeDiff: (files: string[]) => Promise<string | null>\n): Promise<{ diff: string; hadFallback: boolean; fallbackFiles: string[] } | null> {\n const ppDiff = await computePerPatchDiff(\n patch,\n getCurrentGenContent,\n getWorkingTreeContent\n );\n\n if (ppDiff.unlocatableFiles.length === 0) {\n return { diff: ppDiff.diff, hadFallback: false, fallbackFiles: [] };\n }\n\n // Run cumulative diff scoped to ONLY the unlocatable files. Merging\n // them with the per-patch diff for locatable files preserves the\n // surgical scoping for files we COULD anchor, while still capturing\n // contributions for files we couldn't.\n const cumulative = await runCumulativeDiff(ppDiff.unlocatableFiles);\n if (cumulative === null) {\n return null;\n }\n\n const merged = ppDiff.diff + (cumulative.trim() ? cumulative : \"\");\n return { diff: merged, hadFallback: true, fallbackFiles: ppDiff.unlocatableFiles };\n}\n\nfunction splitLines(content: string): string[] {\n // Match parseHunks's line semantics: split on \"\\n\", preserving trailing-newline behavior.\n return content.split(\"\\n\");\n}\n\n/**\n * Determine the correct oursSpan for an anchored hunk by content-matching.\n * The hunk's `@@` header tells us oldCount (lines if patch's \"old\" side present)\n * and newCount (lines if patch's \"new\" side present). We match the lines in\n * OURS at the anchor against both sides and pick the one that fits.\n */\n/**\n * Determine the correct `oursSpan` for an anchored hunk by content-matching.\n *\n * `prefer` tells us which side of the patch we EXPECT OURS to look like:\n * - `\"old\"` → OURS is patch's BASE (e.g. currentGen, pre-patch state).\n * Default to `oldCount` when both sides fit.\n * - `\"new\"` → OURS is patch's THEIRS (e.g. workingTree post-apply).\n * Default to `newCount` when both sides fit.\n *\n * For pure-insertion hunks (no remove lines), `oldSide` is a strict prefix\n * of `newSide`. Both sides will fit whenever oldSide does AND the next OURS\n * lines coincide with the patch's added lines — common for generic adds\n * like `}` or empty lines. Without the `prefer` hint, picking the longer\n * (or shorter) match unconditionally over-includes (or under-includes)\n * sibling-patch content. With `prefer`, we use the caller's domain\n * knowledge to pick the right span.\n */\nfunction resolveSpan(\n loc: LocatedHunk,\n oursLines: string[],\n prefer: \"old\" | \"new\"\n): LocatedHunk {\n const { hunk, oursOffset } = loc;\n\n // Build the expected \"old\" content sequence from the hunk: context + remove lines, in order.\n const oldSide: string[] = [];\n const newSide: string[] = [];\n for (const line of hunk.lines) {\n if (line.type === \"context\") {\n oldSide.push(line.content);\n newSide.push(line.content);\n } else if (line.type === \"remove\") {\n oldSide.push(line.content);\n } else if (line.type === \"add\") {\n newSide.push(line.content);\n }\n }\n\n const oldFits = sequenceMatches(oldSide, oursLines, oursOffset);\n const newFits = sequenceMatches(newSide, oursLines, oursOffset);\n\n if (prefer === \"old\") {\n if (oldFits) return { ...loc, oursSpan: hunk.oldCount };\n if (newFits) return { ...loc, oursSpan: hunk.newCount };\n } else {\n if (newFits) return { ...loc, oursSpan: hunk.newCount };\n if (oldFits) return { ...loc, oursSpan: hunk.oldCount };\n }\n\n // Neither side matches exactly — fall back to original computeOursSpan\n // value (already in loc.oursSpan). This is best-effort for unanchored\n // edges; the caller's overlay+diff will produce a best-effort diff.\n return loc;\n}\n\nfunction sequenceMatches(needle: string[], haystack: string[], offset: number): boolean {\n if (offset + needle.length > haystack.length) return false;\n for (let i = 0; i < needle.length; i++) {\n if (haystack[offset + i] !== needle[i]) return false;\n }\n return true;\n}\n\n/**\n * Reconstruct currentGen with each anchored region replaced by the\n * corresponding region from working tree. Returns the joined string, or\n * `null` to signal an irrecoverable inconsistency (caller should treat as\n * unlocatable rather than silently produce a corrupt overlay).\n */\nfunction overlayRegions(\n currentGenLines: string[],\n locInCurrentGen: LocatedHunk[],\n workingTreeLines: string[],\n locInWorkingTree: LocatedHunk[]\n): string | null {\n // Same hunks parsed against both, lengths must match. If they don't,\n // something invariant-violating happened — signal failure rather than\n // returning currentGen (which the caller would interpret as \"patch\n // contributed nothing\" and silently drop the patch).\n if (locInCurrentGen.length !== locInWorkingTree.length) {\n return null;\n }\n const out: string[] = [];\n let cursor = 0;\n for (let i = 0; i < locInCurrentGen.length; i++) {\n const cg = locInCurrentGen[i]!;\n const wt = locInWorkingTree[i]!;\n // Gap before this hunk: keep currentGen content\n if (cg.oursOffset > cursor) {\n out.push(...currentGenLines.slice(cursor, cg.oursOffset));\n }\n // Replace currentGen's region with working tree's region for this hunk\n out.push(...workingTreeLines.slice(wt.oursOffset, wt.oursOffset + wt.oursSpan));\n cursor = cg.oursOffset + cg.oursSpan;\n }\n // Trailing gap: keep currentGen content\n if (cursor < currentGenLines.length) {\n out.push(...currentGenLines.slice(cursor));\n }\n return out.join(\"\\n\");\n}\n\n/**\n * Compute a unified diff between two strings using `git diff --no-index`.\n * Headers are rewritten to `a/<file>` / `b/<file>` for compatibility with\n * `git apply` and the rest of the codebase's patch handling.\n */\nexport async function unifiedDiff(beforeContent: string, afterContent: string, filePath: string): Promise<string> {\n if (beforeContent === afterContent) return \"\";\n\n const tmp = await mkdtemp(join(tmpdir(), \"fern-replay-pp-\"));\n try {\n const beforePath = join(tmp, \"before\");\n const afterPath = join(tmp, \"after\");\n await writeFile(beforePath, beforeContent, \"utf-8\");\n await writeFile(afterPath, afterContent, \"utf-8\");\n\n const raw = await runGitDiffNoIndex(beforePath, afterPath);\n if (!raw.trim()) return \"\";\n\n return rewriteDiffHeaders(raw, filePath);\n } finally {\n await rm(tmp, { recursive: true, force: true });\n }\n}\n\nfunction runGitDiffNoIndex(beforePath: string, afterPath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"git\", [\"diff\", \"--no-index\", \"--\", beforePath, afterPath]);\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout.on(\"data\", (d: Buffer) => (stdout += d.toString()));\n proc.stderr.on(\"data\", (d: Buffer) => (stderr += d.toString()));\n proc.on(\"close\", (code) => {\n // git diff --no-index returns 0 (no diff) or 1 (diff present) on success;\n // anything else is a real error.\n if (code === 0 || code === 1) resolve(stdout);\n else reject(new Error(`git diff --no-index failed (code ${code}): ${stderr}`));\n });\n });\n}\n\n/**\n * Rewrite the `diff --git`, `---`, and `+++` headers from temp paths to\n * `a/<file>` and `b/<file>` so the diff applies cleanly via `git apply`.\n */\nfunction rewriteDiffHeaders(raw: string, filePath: string): string {\n const lines = raw.split(\"\\n\");\n const out: string[] = [];\n let seenFirstHeader = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git \")) {\n out.push(`diff --git a/${filePath} b/${filePath}`);\n seenFirstHeader = true;\n continue;\n }\n if (!seenFirstHeader) {\n // Skip preamble before first diff header\n continue;\n }\n if (line.startsWith(\"--- \")) {\n out.push(`--- a/${filePath}`);\n continue;\n }\n if (line.startsWith(\"+++ \")) {\n out.push(`+++ b/${filePath}`);\n continue;\n }\n out.push(line);\n }\n return out.join(\"\\n\");\n}\n\nexport function synthesizeNewFileDiff(file: string, content: string): string {\n const lines = content.split(\"\\n\");\n // Drop trailing empty element if file ends with newline (matches git's diff format).\n const hasTrailingNewline = content.endsWith(\"\\n\");\n const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;\n const header = [\n `diff --git a/${file} b/${file}`,\n \"new file mode 100644\",\n \"--- /dev/null\",\n `+++ b/${file}`,\n `@@ -0,0 +1,${bodyLines.length} @@`,\n ].join(\"\\n\");\n const body = bodyLines.map((l) => `+${l}`).join(\"\\n\");\n const trailer = hasTrailingNewline ? \"\" : \"\\n\\\\";\n return header + \"\\n\" + body + trailer + \"\\n\";\n}\n\nexport function synthesizeDeleteFileDiff(file: string, content: string): string {\n const lines = content.split(\"\\n\");\n const hasTrailingNewline = content.endsWith(\"\\n\");\n const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;\n const header = [\n `diff --git a/${file} b/${file}`,\n \"deleted file mode 100644\",\n `--- a/${file}`,\n \"+++ /dev/null\",\n `@@ -1,${bodyLines.length} +0,0 @@`,\n ].join(\"\\n\");\n const body = bodyLines.map((l) => `-${l}`).join(\"\\n\");\n const trailer = hasTrailingNewline ? \"\" : \"\\n\\\\";\n return header + \"\\n\" + body + trailer + \"\\n\";\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { parse, stringify } from \"yaml\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { isBinaryFile } from \"./ReplayApplicator.js\";\nimport type { CustomizationsConfig, StoredPatch } from \"./types.js\";\n\nexport interface MigrationAnalysis {\n /** Files in .fernignore that have git commit history (can be tracked by Replay) */\n trackedByBoth: Array<{ file: string; commit: string }>;\n /** Files in .fernignore but NO recent commit history found after last generation */\n fernignoreOnly: string[];\n /** Commits found that AREN'T in .fernignore (inline edits to generated files) */\n commitsOnly: StoredPatch[];\n /** Synthetic patches created for .fernignore files that differ from pristine generation */\n syntheticPatches: StoredPatch[];\n}\n\nexport interface MigrationResult {\n patchesCreated: number;\n filesSkipped: string[];\n warnings: string[];\n}\n\nexport class FernignoreMigrator {\n private git: GitClient;\n private lockManager: LockfileManager;\n private outputDir: string;\n\n constructor(git: GitClient, lockManager: LockfileManager, outputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.outputDir = outputDir;\n }\n\n fernignoreExists(): boolean {\n return existsSync(join(this.outputDir, \".fernignore\"));\n }\n\n readFernignorePatterns(): string[] {\n const fernignorePath = join(this.outputDir, \".fernignore\");\n if (!existsSync(fernignorePath)) {\n return [];\n }\n const content = readFileSync(fernignorePath, \"utf-8\");\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n }\n\n /** Analyze .fernignore patterns vs git history. Creates synthetic patches for files differing from pristine generation. */\n async analyzeMigration(): Promise<MigrationAnalysis> {\n const patterns = this.readFernignorePatterns();\n const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);\n const { patches } = await detector.detectNewPatches();\n\n const trackedByBoth: Array<{ file: string; commit: string }> = [];\n const fernignoreOnly: string[] = [];\n const commitsOnly: StoredPatch[] = [];\n const syntheticPatches: StoredPatch[] = [];\n\n // Check each fernignore pattern against recent patches\n for (const pattern of patterns) {\n const matchingPatch = patches.find((p) => p.files.some((f) => minimatch(f, pattern) || f === pattern));\n if (matchingPatch) {\n trackedByBoth.push({\n file: pattern,\n commit: matchingPatch.original_commit\n });\n } else {\n fernignoreOnly.push(pattern);\n }\n }\n\n // For fernignore-only patterns, try to create synthetic patches\n // by diffing current file state against pristine generation tree\n const lock = this.lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n\n if (currentGen && fernignoreOnly.length > 0) {\n const resolvedFiles = await this.resolvePatterns(fernignoreOnly);\n const remainingFernignoreOnly: string[] = [];\n\n for (const { pattern, files } of resolvedFiles) {\n const patchFiles: string[] = [];\n const diffParts: string[] = [];\n\n for (const filePath of files) {\n const pristine = await this.git.showFile(currentGen.tree_hash, filePath);\n const currentContent = this.readFileContent(filePath);\n\n if (currentContent === null) {\n // File in .fernignore but not on disk — nothing to track\n continue;\n }\n\n if (pristine === null) {\n // File doesn't exist in generation tree — it's a wholly new file\n patchFiles.push(filePath);\n diffParts.push(this.createNewFileDiff(filePath, currentContent));\n } else if (pristine !== currentContent) {\n // File differs from pristine — user has customized it\n patchFiles.push(filePath);\n diffParts.push(this.createFileDiff(filePath, pristine, currentContent));\n }\n // If pristine === currentContent, file is unchanged — skip\n }\n\n if (patchFiles.length > 0) {\n const patchContent = diffParts.join(\"\\n\");\n const contentHash = `sha256:${createHash(\"sha256\").update(patchContent).digest(\"hex\")}`;\n\n // Snapshot THEIRS from the customer's working tree (the\n // diff is pristine → currentContent on disk). Skip\n // binary files (utf-8 read of binary content is lossy).\n const theirsSnapshot: Record<string, string> = {};\n for (const filePath of patchFiles) {\n if (isBinaryFile(filePath)) continue;\n const c = this.readFileContent(filePath);\n if (c != null) theirsSnapshot[filePath] = c;\n }\n\n syntheticPatches.push({\n id: `patch-fernignore-${createHash(\"sha256\").update(pattern).digest(\"hex\").slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: currentGen.commit_sha,\n original_message: `[fernignore-migration] Customizations for ${pattern}`,\n original_author: \"Fern Replay <replay@buildwithfern.com>\",\n base_generation: currentGen.commit_sha,\n files: patchFiles,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n // Synthetic patches captured from .fernignore-protected files\n // are user-owned by definition — the customer's content\n // diverges from the generator's pristine output, and the\n // generator never produced this divergent content. Without\n // this flag, removing the file from .fernignore later (so\n // it leaves the protection check in `isFileUserOwned`) would\n // expose the patch to absorption on the next regen,\n // silently losing the customization.\n user_owned: true\n });\n\n trackedByBoth.push({\n file: pattern,\n commit: `synthetic (differs from generated)`\n });\n } else {\n // No diff found — file matches generated output or doesn't exist\n remainingFernignoreOnly.push(pattern);\n }\n }\n\n // Replace fernignoreOnly with only truly untrackable patterns\n fernignoreOnly.length = 0;\n fernignoreOnly.push(...remainingFernignoreOnly);\n }\n\n // Find patches that touch files NOT in .fernignore\n for (const patch of patches) {\n const hasUnprotectedFiles = patch.files.some((f) => !patterns.some((p) => minimatch(f, p) || f === p));\n if (hasUnprotectedFiles) {\n commitsOnly.push(patch);\n }\n }\n\n return { trackedByBoth, fernignoreOnly, commitsOnly, syntheticPatches };\n }\n\n private async resolvePatterns(patterns: string[]): Promise<Array<{ pattern: string; files: string[] }>> {\n const allFiles = (await this.git.exec([\"ls-files\"])).trim().split(\"\\n\").filter(Boolean);\n const results: Array<{ pattern: string; files: string[] }> = [];\n\n for (const pattern of patterns) {\n const matching = allFiles.filter(\n (f) => minimatch(f, pattern) || f === pattern || f.startsWith(pattern + \"/\")\n );\n results.push({ pattern, files: matching.length > 0 ? matching : [pattern] });\n }\n\n return results;\n }\n\n private readFileContent(filePath: string): string | null {\n const fullPath = join(this.outputDir, filePath);\n if (!existsSync(fullPath)) {\n return null;\n }\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n return null;\n }\n return readFileSync(fullPath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n private createNewFileDiff(filePath: string, content: string): string {\n const lines = content.split(\"\\n\");\n const hunks = lines.map((l) => `+${l}`).join(\"\\n\");\n return [\n `diff --git a/${filePath} b/${filePath}`,\n \"new file mode 100644\",\n `--- /dev/null`,\n `+++ b/${filePath}`,\n `@@ -0,0 +1,${lines.length} @@`,\n hunks\n ].join(\"\\n\");\n }\n\n private createFileDiff(filePath: string, pristine: string, current: string): string {\n const oldLines = pristine.split(\"\\n\");\n const newLines = current.split(\"\\n\");\n // Simple full-file replacement diff — not optimal but correct\n const removals = oldLines.map((l) => `-${l}`).join(\"\\n\");\n const additions = newLines.map((l) => `+${l}`).join(\"\\n\");\n return [\n `diff --git a/${filePath} b/${filePath}`,\n `--- a/${filePath}`,\n `+++ b/${filePath}`,\n `@@ -1,${oldLines.length} +1,${newLines.length} @@`,\n removals,\n additions\n ].join(\"\\n\");\n }\n\n async migrate(): Promise<MigrationResult> {\n const analysis = await this.analyzeMigration();\n const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);\n const { patches } = await detector.detectNewPatches();\n\n const warnings: string[] = [];\n let patchesCreated = 0;\n\n // Add all detected patches to lockfile\n for (const patch of patches) {\n this.lockManager.addPatch(patch);\n patchesCreated++;\n }\n\n if (patchesCreated > 0) {\n this.lockManager.save();\n }\n\n // Warn about fernignore-only files\n for (const file of analysis.fernignoreOnly) {\n warnings.push(\n `${file}: in .fernignore but no commit history found. Commit this file or keep in .fernignore as fallback.`\n );\n }\n\n return {\n patchesCreated,\n filesSkipped: analysis.fernignoreOnly,\n warnings\n };\n }\n\n movePatternsToReplayYml(patterns: string[]): void {\n const replayYmlPath = join(this.outputDir, \".fern\", \"replay.yml\");\n let config: CustomizationsConfig = {};\n\n if (existsSync(replayYmlPath)) {\n const content = readFileSync(replayYmlPath, \"utf-8\");\n config = (parse(content) as CustomizationsConfig) ?? {};\n }\n\n const existing = config.exclude ?? [];\n const merged = [...new Set([...existing, ...patterns])];\n config.exclude = merged;\n\n const dir = dirname(replayYmlPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(replayYmlPath, stringify(config, { lineWidth: 0 }), \"utf-8\");\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { FernignoreMigrator, type MigrationAnalysis } from \"../FernignoreMigrator.js\";\nimport { isGenerationCommit, isReplayCommit } from \"../git/CommitDetection.js\";\nimport { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport type { CommitInfo, StoredPatch } from \"../types.js\";\n\nexport interface BootstrapOptions {\n /** Log what would happen but don't modify anything */\n dryRun?: boolean;\n /** How to handle .fernignore: \"migrate\" moves patterns to replay.yml, \"delete\" removes it, \"skip\" leaves it */\n fernignoreAction?: \"migrate\" | \"delete\" | \"skip\";\n /** Maximum number of commits to scan for generation history (default: 500) */\n maxCommitsToScan?: number;\n /** Allow overwriting an existing lockfile */\n force?: boolean;\n /** When true, scan git history for existing patches. Default: false (clean start with 0 patches). */\n importHistory?: boolean;\n}\n\nexport interface BootstrapResult {\n /** The generation commit used as baseline, or null if none found */\n generationCommit: CommitInfo | null;\n /** Number of customization patches detected */\n patchesDetected: number;\n /** Number of patches written to lockfile */\n patchesCreated: number;\n /** The detected patches (for dry-run inspection) */\n patches: StoredPatch[];\n /** .fernignore patterns found, if any */\n fernignorePatterns: string[];\n /** .fernignore migration analysis, if .fernignore exists */\n fernignoreAnalysis?: MigrationAnalysis;\n /** Whether .fernignore was updated to protect replay files */\n fernignoreUpdated: boolean;\n /** Warnings about edge cases */\n warnings: string[];\n /** Number of older generation commits that were skipped (stale commits ignored) */\n staleGenerationsSkipped: number;\n /** The generation commit SHA used as cutoff for patch detection */\n scannedSinceGeneration: string;\n}\n\n/**\n * Bootstrap Replay for an existing SDK repository.\n *\n * Scans git history to find all generation commits, identifies\n * user customization patches between them, and creates the initial replay.lock.\n *\n * This is a one-time migration step for SDKs that existed before Replay.\n */\nexport async function bootstrap(outputDir: string, options?: BootstrapOptions): Promise<BootstrapResult> {\n const git = new GitClient(outputDir);\n const lockManager = new LockfileManager(outputDir);\n const maxCommits = options?.maxCommitsToScan ?? 500;\n const warnings: string[] = [];\n\n // Check for existing lockfile\n if (lockManager.exists() && !options?.force) {\n return {\n generationCommit: null,\n patchesDetected: 0,\n patchesCreated: 0,\n patches: [],\n fernignorePatterns: [],\n fernignoreUpdated: false,\n warnings: [\"Replay lockfile already exists. Use --force to overwrite.\"],\n staleGenerationsSkipped: 0,\n scannedSinceGeneration: \"\"\n };\n }\n\n // 1. Find ALL generation commits (newest first, excluding replay commits)\n const genCommits = await findAllGenerationCommits(git, maxCommits);\n\n if (genCommits.length === 0) {\n return {\n generationCommit: null,\n patchesDetected: 0,\n patchesCreated: 0,\n patches: [],\n fernignorePatterns: [],\n fernignoreUpdated: false,\n warnings: [\n \"No generation commits found in the last \" +\n maxCommits +\n \" commits. \" +\n \"Run 'fern generate' first to establish a baseline.\"\n ],\n staleGenerationsSkipped: 0,\n scannedSinceGeneration: \"\"\n };\n }\n\n const latestGen = genCommits[0]!;\n\n // 2. Set up in-memory lockfile (don't write to disk yet — we may be in dry-run mode)\n // For clean start (no importHistory), use HEAD as current_generation so that\n // the next fern generate detects 0 old commits. When importing history, use\n // the actual generation commit as the base for patch detection.\n const anchorSha = options?.importHistory ? latestGen.sha : (await git.exec([\"rev-parse\", \"HEAD\"])).trim();\n const treeHash = await git.getTreeHash(anchorSha);\n const genRecord = {\n commit_sha: anchorSha,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: \"unknown\",\n generator_versions: {} as Record<string, string>\n };\n\n lockManager.initializeInMemory(genRecord);\n\n // 3. Scan for user patches (only when importing history)\n const patches: StoredPatch[] = options?.importHistory ? await findAllUserPatches(git, genCommits) : [];\n\n // 4. Handle .fernignore if present (only when importing history)\n const migrator = new FernignoreMigrator(git, lockManager, outputDir);\n const fernignorePatterns = migrator.readFernignorePatterns();\n let fernignoreAnalysis: MigrationAnalysis | undefined;\n\n if (options?.importHistory && migrator.fernignoreExists() && fernignorePatterns.length > 0) {\n fernignoreAnalysis = await migrator.analyzeMigration();\n\n // Add synthetic patches from .fernignore analysis\n if (fernignoreAnalysis.syntheticPatches.length > 0) {\n patches.push(...fernignoreAnalysis.syntheticPatches);\n }\n\n if (fernignoreAnalysis.fernignoreOnly.length > 0) {\n for (const file of fernignoreAnalysis.fernignoreOnly) {\n warnings.push(\n `${file}: in .fernignore but no recent commits found since last generation. ` +\n \"File may be stale, matches generated output, or does not exist. No customization to track.\"\n );\n }\n }\n }\n\n // In dry-run mode, don't persist anything\n if (options?.dryRun) {\n return {\n generationCommit: latestGen,\n patchesDetected: patches.length,\n patchesCreated: 0,\n patches,\n fernignorePatterns,\n fernignoreAnalysis,\n fernignoreUpdated: false,\n warnings,\n staleGenerationsSkipped: genCommits.length - 1,\n scannedSinceGeneration: latestGen.sha\n };\n }\n\n // 5. Persist patches to lockfile\n for (const patch of patches) {\n lockManager.addPatch(patch);\n }\n lockManager.save();\n\n // 6. Ensure .fernignore protects replay files from generation wipe\n const fernignoreUpdated = ensureFernignoreEntries(outputDir);\n\n // 7. Ensure .gitattributes marks replay.lock as generated (collapses diff in GitHub PRs)\n ensureGitattributesEntries(outputDir);\n\n // 8. Handle .fernignore migration\n if (migrator.fernignoreExists() && fernignorePatterns.length > 0) {\n const action = options?.fernignoreAction ?? \"skip\";\n if (action === \"migrate\") {\n // Move truly untrackable patterns (no diff from generated) to replay.yml exclude list\n const patternsToExclude = fernignoreAnalysis?.fernignoreOnly ?? [];\n if (patternsToExclude.length > 0) {\n migrator.movePatternsToReplayYml(patternsToExclude);\n }\n }\n }\n\n return {\n generationCommit: latestGen,\n patchesDetected: patches.length,\n patchesCreated: patches.length,\n patches,\n fernignorePatterns,\n fernignoreAnalysis,\n fernignoreUpdated,\n warnings,\n staleGenerationsSkipped: genCommits.length - 1,\n scannedSinceGeneration: latestGen.sha\n };\n}\n\nasync function findAllGenerationCommits(git: GitClient, maxCommits: number): Promise<CommitInfo[]> {\n const log = await git.exec([\"log\", \"--format=%H%x00%an%x00%ae%x00%s\", `-${maxCommits}`]);\n\n if (!log.trim()) {\n return [];\n }\n\n const genCommits: CommitInfo[] = [];\n for (const line of log.trim().split(\"\\n\")) {\n if (!line) continue;\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n const commit: CommitInfo = { sha, authorName, authorEmail, message };\n if (isGenerationCommit(commit) && !isReplayCommit(commit)) {\n genCommits.push(commit);\n }\n }\n\n return genCommits;\n}\n\nasync function findAllUserPatches(\n git: GitClient,\n genCommits: CommitInfo[] // newest first\n): Promise<StoredPatch[]> {\n const patches: StoredPatch[] = [];\n const seenHashes = new Set<string>();\n\n // Only scan since the LAST (most recent) generation commit to HEAD\n // This ignores \"stale\" commits that were regenerated over before the customer activated replay\n const latestGen = genCommits[0]!;\n const recentPatches = await extractUserPatches(git, latestGen.sha, \"HEAD\", latestGen.sha, seenHashes);\n patches.push(...recentPatches);\n\n return patches;\n}\n\nasync function extractUserPatches(\n git: GitClient,\n fromSha: string,\n toRef: string,\n baseGeneration: string,\n seenHashes: Set<string>\n): Promise<StoredPatch[]> {\n const log = await git.exec([\"log\", \"--format=%H%x00%an%x00%ae%x00%s\", `${fromSha}..${toRef}`]);\n\n if (!log.trim()) {\n return [];\n }\n\n const commits = parseGitLog(log);\n const patches: StoredPatch[] = [];\n\n // Process in reverse (oldest first) for chronological order\n for (const commit of commits.reverse()) {\n if (isGenerationCommit(commit)) continue;\n\n const parents = await git.getCommitParents(commit.sha);\n if (parents.length > 1) continue;\n\n const patchContent = await git.formatPatch(commit.sha);\n const contentHash = computeContentHash(patchContent);\n\n if (seenHashes.has(contentHash)) continue;\n seenHashes.add(contentHash);\n\n const filesOutput = await git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n\n patches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: baseGeneration,\n files: filesOutput.trim().split(\"\\n\").filter(Boolean),\n patch_content: patchContent\n });\n }\n\n return patches;\n}\n\nfunction parseGitLog(log: string): CommitInfo[] {\n return log\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => {\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n });\n}\n\nconst REPLAY_FERNIGNORE_ENTRIES = [\".fern/replay.lock\", \".fern/replay.yml\", \".gitattributes\"];\n\nfunction ensureFernignoreEntries(outputDir: string): boolean {\n const fernignorePath = join(outputDir, \".fernignore\");\n let content = \"\";\n\n if (existsSync(fernignorePath)) {\n content = readFileSync(fernignorePath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const entry of REPLAY_FERNIGNORE_ENTRIES) {\n if (!lines.some((line) => line.trim() === entry)) {\n toAdd.push(entry);\n }\n }\n\n if (toAdd.length === 0) {\n return false;\n }\n\n if (content && !content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n content += toAdd.join(\"\\n\") + \"\\n\";\n writeFileSync(fernignorePath, content, \"utf-8\");\n return true;\n}\n\nconst GITATTRIBUTES_ENTRIES = [\".fern/replay.lock linguist-generated=true\"];\n\nfunction ensureGitattributesEntries(outputDir: string): void {\n const gitattributesPath = join(outputDir, \".gitattributes\");\n let content = \"\";\n\n if (existsSync(gitattributesPath)) {\n content = readFileSync(gitattributesPath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const entry of GITATTRIBUTES_ENTRIES) {\n if (!lines.some((line) => line.trim() === entry)) {\n toAdd.push(entry);\n }\n }\n\n if (toAdd.length === 0) {\n return;\n }\n\n if (content && !content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n content += toAdd.join(\"\\n\") + \"\\n\";\n writeFileSync(gitattributesPath, content, \"utf-8\");\n}\n\nfunction computeContentHash(patchContent: string): string {\n const lines = patchContent.split(\"\\n\");\n\n // Strip email wrapper from format-patch output (matches ReplayDetector)\n const diffStart = lines.findIndex((l) => l.startsWith(\"diff --git \"));\n const relevantLines = diffStart > 0 ? lines.slice(diffStart) : lines;\n\n const normalized = relevantLines\n .filter((line) => !line.startsWith(\"index \"))\n .join(\"\\n\")\n .replace(/\\n-- \\n[\\d]+\\.[\\d]+[^\\n]*\\s*$/, \"\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\n}\n","import { minimatch } from \"minimatch\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport type { StoredPatch } from \"../types.js\";\n\nexport interface ForgetOptions {\n /** Don't actually remove, just show what would be removed */\n dryRun?: boolean;\n /** Remove all tracked patches (keep lockfile and generation history) */\n all?: boolean;\n /** Specific patch IDs to remove */\n patchIds?: string[];\n /** Search pattern: file path, glob, or commit message substring */\n pattern?: string;\n}\n\nexport interface DiffStat {\n additions: number;\n deletions: number;\n}\n\nexport interface MatchedPatch {\n id: string;\n message: string;\n files: string[];\n diffstat: DiffStat;\n status?: \"unresolved\" | \"resolving\";\n}\n\nexport interface ForgetResult {\n /** Whether replay is initialized (lockfile exists) */\n initialized: boolean;\n /** Patches that were (or would be in dry-run) removed */\n removed: MatchedPatch[];\n /** Number of patches remaining after removal */\n remaining: number;\n /** True if a search/pattern was given but nothing matched */\n notFound: boolean;\n /** Patch IDs that were specified but don't exist (idempotent mode) */\n alreadyForgotten: string[];\n /** Total patches before removal */\n totalPatches: number;\n /** Warnings (e.g., forgetting patches with conflict markers on disk) */\n warnings: string[];\n /** Matching patches for interactive selection (search/no-arg mode only) */\n matched?: MatchedPatch[];\n}\n\nfunction parseDiffStat(patchContent: string): DiffStat {\n let additions = 0;\n let deletions = 0;\n let inDiffHunk = false;\n for (const line of patchContent.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n inDiffHunk = true;\n continue;\n }\n if (!inDiffHunk) continue;\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n additions++;\n } else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n deletions++;\n }\n }\n return { additions, deletions };\n}\n\nfunction toMatchedPatch(patch: StoredPatch): MatchedPatch {\n return {\n id: patch.id,\n message: patch.original_message,\n files: patch.files,\n diffstat: parseDiffStat(patch.patch_content),\n ...(patch.status ? { status: patch.status } : {}),\n };\n}\n\nfunction matchesPatch(patch: StoredPatch, pattern: string): boolean {\n // File path match: exact or glob\n const fileMatch = patch.files.some(\n (file) => file === pattern || minimatch(file, pattern),\n );\n if (fileMatch) return true;\n\n // Commit message match: case-insensitive substring\n return patch.original_message.toLowerCase().includes(pattern.toLowerCase());\n}\n\nfunction buildWarnings(patches: StoredPatch[]): string[] {\n const warnings: string[] = [];\n for (const patch of patches) {\n if (patch.status === \"resolving\") {\n warnings.push(\n `patch ${patch.id} has conflict markers in these files: ${patch.files.join(\", \")}. ` +\n `Run \\`git checkout -- <files>\\` to restore the generated versions.`,\n );\n } else if (patch.status === \"unresolved\") {\n warnings.push(\n `patch ${patch.id} had unresolved conflicts (files: ${patch.files.join(\", \")}).`,\n );\n }\n }\n return warnings;\n}\n\nconst EMPTY_RESULT: ForgetResult = {\n initialized: false,\n removed: [],\n remaining: 0,\n notFound: false,\n alreadyForgotten: [],\n totalPatches: 0,\n warnings: [],\n};\n\nexport function forget(outputDir: string, options?: ForgetOptions): ForgetResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return { ...EMPTY_RESULT };\n }\n\n const lock = lockManager.read();\n const totalPatches = lock.patches.length;\n\n // --all: remove all patches\n if (options?.all) {\n const removed = lock.patches.map(toMatchedPatch);\n const warnings = buildWarnings(lock.patches);\n\n if (!options.dryRun) {\n for (const patch of lock.patches) {\n lockManager.addForgottenHash(patch.content_hash);\n }\n lockManager.clearPatches();\n lockManager.save();\n }\n\n return {\n initialized: true,\n removed,\n remaining: 0,\n notFound: false,\n alreadyForgotten: [],\n totalPatches,\n warnings,\n };\n }\n\n // Patch ID mode: remove specific patches by ID\n if (options?.patchIds && options.patchIds.length > 0) {\n const removed: MatchedPatch[] = [];\n const alreadyForgotten: string[] = [];\n const patchesToRemove: StoredPatch[] = [];\n\n for (const id of options.patchIds) {\n const patch = lock.patches.find((p) => p.id === id);\n if (patch) {\n removed.push(toMatchedPatch(patch));\n patchesToRemove.push(patch);\n } else {\n alreadyForgotten.push(id);\n }\n }\n\n const warnings = buildWarnings(patchesToRemove);\n\n if (!options.dryRun) {\n for (const patch of patchesToRemove) {\n lockManager.addForgottenHash(patch.content_hash);\n lockManager.removePatch(patch.id);\n }\n lockManager.save();\n }\n\n return {\n initialized: true,\n removed,\n remaining: totalPatches - removed.length,\n notFound: removed.length === 0 && alreadyForgotten.length > 0,\n alreadyForgotten,\n totalPatches,\n warnings,\n };\n }\n\n // Search mode: match by pattern (file path, glob, or commit message)\n if (options?.pattern) {\n const matched = lock.patches\n .filter((p) => matchesPatch(p, options.pattern!))\n .map(toMatchedPatch);\n\n return {\n initialized: true,\n removed: [],\n remaining: totalPatches,\n notFound: matched.length === 0,\n alreadyForgotten: [],\n totalPatches,\n warnings: [],\n matched,\n };\n }\n\n // No argument: return all patches for interactive selection\n return {\n initialized: true,\n removed: [],\n remaining: totalPatches,\n notFound: totalPatches === 0,\n alreadyForgotten: [],\n totalPatches,\n warnings: [],\n matched: lock.patches.map(toMatchedPatch),\n };\n}\n","import { unlinkSync } from \"node:fs\";\nimport { LockfileManager } from \"../LockfileManager.js\";\n\nexport interface ResetOptions {\n /** Don't actually delete, just show what would happen */\n dryRun?: boolean;\n}\n\nexport interface ResetResult {\n /** Whether reset was successful (or would be) */\n success: boolean;\n /** Number of patches that were (or would be) removed */\n patchesRemoved: number;\n /** Whether the lockfile was (or would be) deleted */\n lockfileDeleted: boolean;\n /** True if there was nothing to reset */\n nothingToReset: boolean;\n}\n\nexport function reset(outputDir: string, options?: ResetOptions): ResetResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return {\n success: true,\n patchesRemoved: 0,\n lockfileDeleted: false,\n nothingToReset: true\n };\n }\n\n const lock = lockManager.read();\n const patchCount = lock.patches.length;\n\n if (!options?.dryRun) {\n unlinkSync(lockManager.lockfilePath);\n }\n\n return {\n success: true,\n patchesRemoved: patchCount,\n lockfileDeleted: true,\n nothingToReset: false\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport { ReplayApplicator, isBinaryFile } from \"../ReplayApplicator.js\";\nimport { ReplayCommitter } from \"../ReplayCommitter.js\";\nimport { ReplayDetector } from \"../ReplayDetector.js\";\nimport { computePerPatchDiffWithFallback } from \"../PatchRegionDiff.js\";\n\nexport interface ResolveOptions {\n /** Check for remaining conflict markers before committing. Default: true */\n checkMarkers?: boolean;\n}\n\nexport interface ResolveResult {\n /** Whether the resolve succeeded */\n success: boolean;\n /** Commit SHA of the [fern-replay] commit, if created */\n commitSha?: string;\n /** Reason for failure or current state */\n reason?: string;\n /** Files that have conflict markers */\n unresolvedFiles?: string[];\n /** Phase the command executed */\n phase?: \"applied\" | \"committed\" | \"nothing-to-resolve\";\n /** Number of patches applied to working tree (phase 1) */\n patchesApplied?: number;\n /** Number of patches resolved and committed (phase 2) */\n patchesResolved?: number;\n /** Non-fatal diagnostic messages (e.g., per-patch fallbacks) */\n warnings?: string[];\n}\n\nexport async function resolve(outputDir: string, options?: ResolveOptions): Promise<ResolveResult> {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return { success: false, reason: \"no-lockfile\" };\n }\n\n const lock = lockManager.read();\n if (lock.patches.length === 0) {\n return { success: false, reason: \"no-patches\" };\n }\n\n const git = new GitClient(outputDir);\n const unresolvedPatches = lockManager.getUnresolvedPatches();\n const resolvingPatches = lockManager.getResolvingPatches();\n\n // ---- Phase 1: Apply unresolved patches to working tree ----\n if (unresolvedPatches.length > 0) {\n const applicator = new ReplayApplicator(git, lockManager, outputDir);\n // applyMode: \"resolve\" — preserve conflict markers on disk so the\n // customer sees A's conflicts (instead of having them silently\n // stripped by the intra-loop sanitize that the replay pipeline\n // depends on for clean follow-up patches). See ReplayApplicator\n // applyPatches docstring for the rationale.\n await applicator.applyPatches(unresolvedPatches, { applyMode: \"resolve\" });\n\n const markerFiles = await findConflictMarkerFiles(git);\n\n if (markerFiles.length > 0) {\n // Mark as \"resolving\" so next call knows Phase 1 happened\n for (const patch of unresolvedPatches) {\n lockManager.updatePatch(patch.id, { status: \"resolving\" });\n }\n lockManager.save();\n\n return {\n success: false,\n reason: \"conflicts-applied\",\n unresolvedFiles: markerFiles,\n phase: \"applied\",\n patchesApplied: unresolvedPatches.length\n };\n }\n\n // All patches applied cleanly — fall through to commit phase.\n // Treat these as needing commit (same as resolving patches).\n }\n\n // ---- Phase 1.5: Conflict markers still present ----\n if (options?.checkMarkers !== false) {\n const currentMarkerFiles = await findConflictMarkerFiles(git);\n if (currentMarkerFiles.length > 0) {\n return { success: false, reason: \"unresolved-conflicts\", unresolvedFiles: currentMarkerFiles };\n }\n }\n\n // ---- Phase 2: Commit resolution ----\n // Includes both \"resolving\" patches (from a previous Phase 1 call) and\n // \"unresolved\" patches that applied cleanly (from Phase 1 above).\n const patchesToCommit = [...resolvingPatches, ...unresolvedPatches];\n if (patchesToCommit.length > 0) {\n const currentGen = lock.current_generation;\n const detector = new ReplayDetector(git, lockManager, outputDir);\n const warnings: string[] = [];\n let patchesResolved = 0;\n\n // Two-pass: pass 1 computes per-patch attribution; pass 2 applies\n // it with consolidation when multiple patches end up with byte-\n // identical content (which would otherwise duplicate-apply at the\n // next regen and corrupt the customer's file).\n type PassResult =\n | { kind: \"skip\" }\n | { kind: \"revert\" }\n | { kind: \"apply\"; diff: string; hash: string; hadFallback: boolean; fallbackFiles: string[] };\n\n const pass1: PassResult[] = [];\n for (const patch of patchesToCommit) {\n // FER-9983: per-patch contribution diff. Using cumulative\n // `git diff currentGen -- patch.files` would assign byte-\n // identical patch_content to every patch sharing a file —\n // which the consolidation pass below catches, but per-patch\n // attribution (when achievable) preserves better provenance.\n const result = await computePerPatchDiffWithFallback(\n patch,\n (f) => git.showFile(currentGen, f),\n (f) => readFile(join(outputDir, f), \"utf-8\").catch(() => null),\n (files) => git.exec([\"diff\", currentGen, \"--\", ...files]).catch(() => null)\n );\n\n if (result === null) {\n warnings.push(\n `Patch ${patch.id}: cumulative-diff fallback failed for unlocatable files; preserving patch unchanged`\n );\n pass1.push({ kind: \"skip\" });\n continue;\n }\n\n const diff = result.diff;\n if (!diff.trim()) {\n pass1.push({ kind: \"revert\" });\n continue;\n }\n\n const hash = detector.computeContentHash(diff);\n pass1.push({\n kind: \"apply\",\n diff,\n hash,\n hadFallback: result.hadFallback,\n fallbackFiles: result.fallbackFiles,\n });\n }\n\n // Pass 2 setup: identify the LAST occurrence of each content hash —\n // that's the canonical patch (most recent customer intent). Earlier\n // patches with the same hash get consolidated into that one. Per\n // user direction (criterion #5 in the brief): \"consolidate to ONE\n // canonical patch rather than copying cumulative content into all.\"\n const lastIndexByHash = new Map<string, number>();\n for (let i = 0; i < pass1.length; i++) {\n const r = pass1[i]!;\n if (r.kind === \"apply\") lastIndexByHash.set(r.hash, i);\n }\n\n for (let i = 0; i < patchesToCommit.length; i++) {\n const patch = patchesToCommit[i]!;\n const r = pass1[i]!;\n if (r.kind === \"skip\") continue;\n if (r.kind === \"revert\") {\n // Genuine revert: customer dropped this patch entirely.\n lockManager.removePatch(patch.id);\n continue;\n }\n\n // r.kind === \"apply\"\n if (lastIndexByHash.get(r.hash) !== i) {\n // Duplicate of a later patch — consolidate by removing.\n // The customer's contribution survives on the canonical\n // patch (the last one with this hash). Per-commit\n // attribution is recoverable from `git log -- <file>`.\n const canonicalIdx = lastIndexByHash.get(r.hash)!;\n const canonical = patchesToCommit[canonicalIdx]!;\n lockManager.removePatch(patch.id);\n warnings.push(\n `Consolidated patch ${patch.id} (commit ${(patch.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into patch ${canonical.id} (commit ${(canonical.original_commit || \"<missing>\").slice(0, 7)}): ` +\n `byte-identical patch_content after resolution. Per-commit attribution preserved in git log; ` +\n `lockfile collapsed to avoid duplicate-apply corruption on next regen.`\n );\n continue;\n }\n\n if (r.hadFallback) {\n warnings.push(\n `Patch ${patch.id}: ${r.fallbackFiles.join(\", \")} could not be anchored; cumulative-diff fallback applied for those files`\n );\n }\n\n const changedFiles = r.hadFallback\n ? await getChangedFiles(git, currentGen, patch.files)\n : extractFilesFromDiff(r.diff);\n\n // Capture THEIRS as a snapshot of the customer's resolved file\n // content. This is what THEIRS *means* — the post-customer-edit\n // state. Storing it directly (instead of relying on\n // patch_content's diff to reconstruct it) makes future regens\n // robust to generator structural changes that would invalidate\n // the diff's line anchors.\n const filesForSnapshot = changedFiles.length > 0 ? changedFiles : patch.files;\n const theirsSnapshot: Record<string, string> = {};\n for (const file of filesForSnapshot) {\n if (isBinaryFile(file)) continue;\n const content = await readFile(join(outputDir, file), \"utf-8\").catch(() => null);\n if (content != null) {\n theirsSnapshot[file] = content;\n }\n }\n\n lockManager.markPatchResolved(patch.id, {\n patch_content: r.diff,\n content_hash: r.hash,\n base_generation: currentGen,\n files: filesForSnapshot,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {})\n });\n patchesResolved++;\n }\n\n lockManager.save();\n\n const committer = new ReplayCommitter(git, outputDir);\n await committer.stageAll();\n const commitSha = await committer.commitReplay(\n lock.patches.length,\n lock.patches,\n \"[fern-replay] Resolved conflicts\"\n );\n\n return {\n success: true,\n commitSha,\n phase: \"committed\",\n patchesResolved,\n warnings: warnings.length > 0 ? warnings : undefined\n };\n }\n\n // ---- No unresolved/resolving patches → legacy behavior ----\n const committer = new ReplayCommitter(git, outputDir);\n await committer.stageAll();\n const commitSha = await committer.commitReplay(lock.patches.length, lock.patches);\n\n return { success: true, commitSha, phase: \"committed\" };\n}\n\nasync function findConflictMarkerFiles(git: GitClient): Promise<string[]> {\n const output = await git.exec([\"grep\", \"-l\", \"<<<<<<<\", \"--\", \".\"]).catch(() => \"\");\n return output.trim() ? output.trim().split(\"\\n\").filter(Boolean) : [];\n}\n\nasync function getChangedFiles(git: GitClient, currentGen: string, files: string[]): Promise<string[]> {\n const filesOutput = await git.exec([\"diff\", \"--name-only\", currentGen, \"--\", ...files]).catch(() => null);\n\n if (!filesOutput || !filesOutput.trim()) return files;\n\n const changed = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !f.startsWith(\".fern/\"));\n\n return changed.length > 0 ? changed : files;\n}\n\n/**\n * Parse `diff --git a/<X> b/<Y>` headers from a unified diff and return the\n * destination paths. For renames, the \"to\" side is preferred. Filters out\n * `.fern/` paths.\n */\nfunction extractFilesFromDiff(unifiedDiff: string): string[] {\n const out = new Set<string>();\n const renameSources = new Set<string>();\n let currentTarget: string | null = null;\n\n for (const line of unifiedDiff.split(\"\\n\")) {\n const headerMatch = line.match(/^diff --git a\\/(.+?) b\\/(.+)$/);\n if (headerMatch) {\n currentTarget = headerMatch[2]!;\n if (!currentTarget.startsWith(\".fern/\")) out.add(currentTarget);\n continue;\n }\n if (currentTarget && line.startsWith(\"rename from \")) {\n renameSources.add(line.slice(\"rename from \".length));\n }\n }\n // Drop rename sources (we want the post-rename path, not the pre-rename path).\n for (const src of renameSources) out.delete(src);\n return Array.from(out);\n}\n","import { LockfileManager } from \"../LockfileManager.js\";\n\nexport interface StatusResult {\n /** Whether replay is initialized (lockfile exists) */\n initialized: boolean;\n /** Total number of generations tracked */\n generationCount: number;\n /** Last generation info, if available */\n lastGeneration: StatusGeneration | undefined;\n /** Tracked customization patches */\n patches: StatusPatch[];\n /** Count of patches with \"unresolved\" or \"resolving\" status */\n unresolvedCount: number;\n /** Exclude patterns from replay.yml */\n excludePatterns: string[];\n}\n\nexport interface StatusPatch {\n /** Patch ID (e.g. \"patch-def45678\") */\n id: string;\n /** \"added\" if patch_content contains \"new file mode\", otherwise \"modified\" */\n type: \"added\" | \"modified\";\n /** Original commit message */\n message: string;\n /** Author name (without email) */\n author: string;\n /** Short SHA of the original commit (7 chars) */\n sha: string;\n /** Files touched by this patch */\n files: string[];\n /** Number of files */\n fileCount: number;\n /** Patch resolution status, if any */\n status?: \"unresolved\" | \"resolving\";\n}\n\nexport interface StatusGeneration {\n /** Short commit SHA (7 chars) */\n sha: string;\n /** Generation timestamp */\n timestamp: string;\n /** CLI version used for generation */\n cliVersion: string;\n /** Generator versions (e.g. { \"fern-java-sdk\": \"3.35.0\" }) */\n generatorVersions: Record<string, string>;\n}\n\nexport function status(outputDir: string): StatusResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return {\n initialized: false,\n generationCount: 0,\n lastGeneration: undefined,\n patches: [],\n unresolvedCount: 0,\n excludePatterns: [],\n };\n }\n\n const lock = lockManager.read();\n\n const patches: StatusPatch[] = lock.patches.map((patch) => ({\n id: patch.id,\n type: patch.patch_content.includes(\"new file mode\") ? \"added\" as const : \"modified\" as const,\n message: patch.original_message,\n author: patch.original_author.split(\"<\")[0]?.trim() || \"unknown\",\n sha: patch.original_commit.slice(0, 7),\n files: patch.files,\n fileCount: patch.files.length,\n ...(patch.status ? { status: patch.status } : {}),\n }));\n\n const unresolvedCount = lock.patches.filter(\n (p) => p.status === \"unresolved\" || p.status === \"resolving\"\n ).length;\n\n let lastGeneration: StatusGeneration | undefined;\n const lastGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n if (lastGen) {\n lastGeneration = {\n sha: lastGen.commit_sha.slice(0, 7),\n timestamp: lastGen.timestamp,\n cliVersion: lastGen.cli_version,\n generatorVersions: lastGen.generator_versions,\n };\n }\n\n const config = lockManager.getCustomizationsConfig();\n const excludePatterns = config.exclude ?? [];\n\n return {\n initialized: true,\n generationCount: lock.generations.length,\n lastGeneration,\n patches,\n unresolvedCount,\n excludePatterns,\n };\n}\n"],"mappings":"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","names":["spawn","resolve","contextCount","import_promises","import_node_os","import_node_path","content","import_node_path","GitClient","reconstructFromGhostPatch","outDir","merged","import_node_fs","import_promises","import_node_path","import_minimatch","import_promises","import_node_os","import_node_path","isDiffLineForFile","rm","resolve","existingPatches","newPatches","allPatches","readFileAsync","applyPatchToContent","import_node_crypto","import_node_fs","import_node_path","import_minimatch","import_yaml","import_node_crypto","import_node_fs","import_node_path","import_minimatch","import_node_fs","import_promises","import_node_path","committer","commitSha","unifiedDiff"]}
|
|
1
|
+
{"version":3,"sources":["../src/git/GitClient.ts","../src/HybridReconstruction.ts","../src/PatchApplyTheirs.ts","../src/index.ts","../src/credentials.ts","../src/git/CommitDetection.ts","../src/LockfileManager.ts","../src/ReplayDetector.ts","../src/shared/binary.ts","../src/ThreeWayMerge.ts","../src/ReplayApplicator.ts","../src/accumulator/MergeAccumulator.ts","../src/applicator/resolveInputs.ts","../src/conflict-utils.ts","../src/applicator/buildMergePlan.ts","../src/applicator/runMergeAndRecord.ts","../src/ReplayCommitter.ts","../src/ReplayService.ts","../src/PatchRegionDiff.ts","../src/classifier/FileOwnership.ts","../src/flows/FirstGenerationFlow.ts","../src/flows/SkipApplicationFlow.ts","../src/flows/NoPatchesFlow.ts","../src/flows/NormalRegenerationFlow.ts","../src/FernignoreMigrator.ts","../src/commands/bootstrap.ts","../src/commands/forget.ts","../src/commands/reset.ts","../src/commands/resolve.ts","../src/commands/status.ts"],"sourcesContent":["import { type SimpleGit, simpleGit } from \"simple-git\";\nimport type { CommitInfo } from \"../types.js\";\n\nexport class GitClient {\n private git: SimpleGit;\n private repoPath: string;\n\n constructor(repoPath: string) {\n this.repoPath = repoPath;\n this.git = simpleGit(repoPath);\n }\n\n async exec(args: string[]): Promise<string> {\n return this.git.raw(args);\n }\n\n async execWithInput(args: string[], input: string): Promise<string> {\n // simple-git's raw() doesn't support stdin directly,\n // so we use spawn for commands that need stdin (e.g. git am)\n const { spawn } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const proc = spawn(\"git\", args, { cwd: this.repoPath });\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data: Buffer) => {\n stdout += data.toString();\n });\n proc.stderr.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve(stdout);\n } else {\n reject(new Error(`git ${args.join(\" \")} failed (code ${code}): ${stderr}`));\n }\n });\n\n proc.stdin.write(input);\n proc.stdin.end();\n });\n }\n\n async formatPatch(commitSha: string): Promise<string> {\n return this.exec([\"format-patch\", \"-1\", commitSha, \"--stdout\"]);\n }\n\n async applyPatch(patchContent: string): Promise<void> {\n await this.execWithInput([\"am\", \"--3way\"], patchContent);\n }\n\n async getTreeHash(commitSha: string): Promise<string> {\n return (await this.exec([\"rev-parse\", `${commitSha}^{tree}`])).trim();\n }\n\n async showFile(treeish: string, filePath: string): Promise<string | null> {\n try {\n return await this.exec([\"show\", `${treeish}:${filePath}`]);\n } catch {\n return null;\n }\n }\n\n async getCommitInfo(commitSha: string): Promise<CommitInfo> {\n const format = \"%H%x00%an%x00%ae%x00%s\";\n const output = await this.exec([\"log\", \"-1\", `--format=${format}`, commitSha]);\n const [sha, authorName, authorEmail, message] = output.trim().split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n }\n\n async getCommitParents(commitSha: string): Promise<string[]> {\n const output = await this.exec([\"rev-parse\", `${commitSha}^@`]);\n return output.trim().split(\"\\n\").filter(Boolean);\n }\n\n /**\n * Detects renames and copies between two trees.\n *\n * Both `R` (rename) and `C` (copy) entries are returned as `{from, to}` pairs.\n * Copies are treated as rename-equivalent because the generator may produce the\n * new path while the old path remains in the tree (e.g., imperfect cleanup,\n * customer edits at the old path, or test helpers that only write new files).\n * Callers that care about \"is the source still present\" should verify via\n * `showFile(toTree, from)`.\n */\n async detectRenames(fromTree: string, toTree: string): Promise<Array<{ from: string; to: string }>> {\n try {\n // --find-copies (-C) catches the case where the generator writes the new path\n // but leaves the old path in the tree (e.g., when the generator's cleanup step\n // didn't run, or customer edits at the old path kept it present). Rename\n // detection alone requires the old path to be deleted; copy detection does not.\n const output = await this.exec([\n \"diff\", \"--find-renames\", \"--find-copies\", \"--name-status\", fromTree, toTree\n ]);\n const renames: Array<{ from: string; to: string }> = [];\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Lines look like: R095\\told/path.ts\\tnew/path.ts (rename, 95% similarity)\n // or: C095\\tsrc/path.ts\\tnew/path.ts (copy, 95% similarity)\n if (line.startsWith(\"R\") || line.startsWith(\"C\")) {\n const parts = line.split(\"\\t\");\n if (parts.length >= 3) {\n renames.push({ from: parts[1]!, to: parts[2]! });\n }\n }\n }\n return renames;\n } catch {\n return [];\n }\n }\n\n async isAncestor(commit: string, descendant: string): Promise<boolean> {\n try {\n const mergeBase = (await this.exec([\"merge-base\", commit, descendant])).trim();\n return mergeBase === commit;\n } catch {\n // No common ancestor (e.g., orphan branches)\n return false;\n }\n }\n\n async commitExists(sha: string): Promise<boolean> {\n try {\n const type = await this.exec([\"cat-file\", \"-t\", sha]);\n return type.trim() === \"commit\";\n } catch {\n return false;\n }\n }\n\n async treeExists(treeHash: string): Promise<boolean> {\n try {\n const type = await this.exec([\"cat-file\", \"-t\", treeHash]);\n return type.trim() === \"tree\";\n } catch {\n return false;\n }\n }\n\n async getCommitBody(commitSha: string): Promise<string> {\n return this.exec([\"log\", \"-1\", \"--format=%B\", commitSha]);\n }\n\n getRepoPath(): string {\n return this.repoPath;\n }\n}\n","/**\n * Hybrid BASE reconstruction for ghost commits.\n *\n * When a patch's base generation tree is unreachable (GC'd after squash merge,\n * shallow clone), we reconstruct BASE and THEIRS from the unified diff and\n * the current OURS content on disk.\n *\n * The unified diff encodes:\n * - BASE = context lines + removed lines\n * - THEIRS = context lines + added lines\n *\n * By matching context lines against OURS, we anchor hunks to positions in the\n * current file and fill gaps with OURS content, producing hybrid BASE and\n * THEIRS suitable for threeWayMerge().\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DiffHunk {\n /** 1-based line number in the old (BASE) file where this hunk starts */\n oldStart: number;\n /** Number of lines in the old (BASE) file this hunk spans */\n oldCount: number;\n /** 1-based line number in the new (THEIRS) file where this hunk starts */\n newStart: number;\n /** Number of lines in the new (THEIRS) file this hunk spans */\n newCount: number;\n /** Ordered entries: context lines, removed lines, added lines */\n lines: HunkLine[];\n}\n\nexport type HunkLine =\n | { type: \"context\"; content: string }\n | { type: \"remove\"; content: string }\n | { type: \"add\"; content: string };\n\nexport interface LocatedHunk {\n hunk: DiffHunk;\n /** 0-based index in OURS lines where this hunk's context starts */\n oursOffset: number;\n /** Number of OURS lines this hunk covers */\n oursSpan: number;\n}\n\nexport interface ReconstructionResult {\n base: string;\n theirs: string;\n}\n\n// ---------------------------------------------------------------------------\n// 1. Hunk Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a unified diff (for a single file) into structured hunks.\n * Input should start with `diff --git` and contain `@@` hunk headers.\n */\nexport function parseHunks(fileDiff: string): DiffHunk[] {\n const lines = fileDiff.split(\"\\n\");\n const hunks: DiffHunk[] = [];\n let currentHunk: DiffHunk | null = null;\n\n for (const line of lines) {\n const headerMatch = line.match(\n /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/\n );\n if (headerMatch) {\n if (currentHunk) {\n hunks.push(currentHunk);\n }\n currentHunk = {\n oldStart: parseInt(headerMatch[1]!, 10),\n oldCount: headerMatch[2] != null ? parseInt(headerMatch[2], 10) : 1,\n newStart: parseInt(headerMatch[3]!, 10),\n newCount: headerMatch[4] != null ? parseInt(headerMatch[4], 10) : 1,\n lines: []\n };\n continue;\n }\n\n if (!currentHunk) continue;\n\n // Skip metadata lines\n if (\n line.startsWith(\"diff --git\") ||\n line.startsWith(\"index \") ||\n line.startsWith(\"---\") ||\n line.startsWith(\"+++\") ||\n line.startsWith(\"old mode\") ||\n line.startsWith(\"new mode\") ||\n line.startsWith(\"similarity index\") ||\n line.startsWith(\"rename from\") ||\n line.startsWith(\"rename to\") ||\n line.startsWith(\"new file mode\") ||\n line.startsWith(\"deleted file mode\")\n ) {\n continue;\n }\n\n if (line === \"\\\\") {\n continue;\n }\n\n if (line.startsWith(\"-\")) {\n currentHunk.lines.push({ type: \"remove\", content: line.slice(1) });\n } else if (line.startsWith(\"+\")) {\n currentHunk.lines.push({ type: \"add\", content: line.slice(1) });\n } else if (line.startsWith(\" \") || line === \"\") {\n // Context line. A bare empty string is a context line for an empty line\n // (unified diff uses \" \" prefix but trailing whitespace stripping may remove it).\n currentHunk.lines.push({\n type: \"context\",\n content: line.startsWith(\" \") ? line.slice(1) : line\n });\n }\n }\n\n if (currentHunk) {\n hunks.push(currentHunk);\n }\n\n return hunks;\n}\n\n// ---------------------------------------------------------------------------\n// 2. Context Matcher\n// ---------------------------------------------------------------------------\n\nfunction extractLeadingContext(hunk: DiffHunk): string[] {\n const result: string[] = [];\n for (const line of hunk.lines) {\n if (line.type !== \"context\") break;\n result.push(line.content);\n }\n return result;\n}\n\nfunction extractTrailingContext(hunk: DiffHunk): string[] {\n const result: string[] = [];\n for (let i = hunk.lines.length - 1; i >= 0; i--) {\n if (hunk.lines[i]!.type !== \"context\") break;\n result.unshift(hunk.lines[i]!.content);\n }\n return result;\n}\n\nfunction countOursLinesBeforeTrailing(hunk: DiffHunk): number {\n let count = 0;\n const trailingStart = findTrailingContextStart(hunk);\n for (let i = 0; i < trailingStart; i++) {\n if (hunk.lines[i]!.type === \"context\") count++;\n }\n return count;\n}\n\nfunction findTrailingContextStart(hunk: DiffHunk): number {\n let i = hunk.lines.length - 1;\n while (i >= 0 && hunk.lines[i]!.type === \"context\") {\n i--;\n }\n return i + 1;\n}\n\nfunction matchesAt(needle: string[], haystack: string[], offset: number): boolean {\n for (let i = 0; i < needle.length; i++) {\n if (haystack[offset + i] !== needle[i]) return false;\n }\n return true;\n}\n\n/**\n * Find a sequence of context lines in OURS, starting search near `hint`.\n * Returns 0-based index of the first matching line, or -1 if not found.\n */\nfunction findContextInOurs(\n contextLines: string[],\n oursLines: string[],\n minIndex: number,\n hint: number\n): number {\n const SEARCH_WINDOW = 200;\n const maxStart = oursLines.length - contextLines.length;\n\n const clampedHint = Math.max(minIndex, Math.min(hint, maxStart));\n\n // Check hint position first, then expand outward symmetrically\n if (clampedHint >= minIndex && clampedHint <= maxStart) {\n if (matchesAt(contextLines, oursLines, clampedHint)) {\n return clampedHint;\n }\n }\n for (let delta = 1; delta <= SEARCH_WINDOW; delta++) {\n for (const sign of [1, -1] as const) {\n const idx = clampedHint + delta * sign;\n if (idx < minIndex || idx > maxStart) continue;\n if (matchesAt(contextLines, oursLines, idx)) {\n return idx;\n }\n }\n }\n\n return -1;\n}\n\n/**\n * Compute how many lines this hunk spans in OURS.\n */\nfunction computeOursSpan(\n hunk: DiffHunk,\n oursLines: string[],\n oursOffset: number\n): number {\n const leading = extractLeadingContext(hunk);\n const trailing = extractTrailingContext(hunk);\n\n if (trailing.length === 0) {\n const contextCount = hunk.lines.filter(\n (l) => l.type === \"context\"\n ).length;\n return Math.min(contextCount, oursLines.length - oursOffset);\n }\n\n // Find trailing context starting after leading context\n const searchStart = oursOffset + leading.length;\n for (let i = searchStart; i <= oursLines.length - trailing.length; i++) {\n if (matchesAt(trailing, oursLines, i)) {\n return i + trailing.length - oursOffset;\n }\n }\n\n // Trailing context not found — fall back to context-only estimate\n const contextCount = hunk.lines.filter(\n (l) => l.type === \"context\"\n ).length;\n return Math.min(contextCount, oursLines.length - oursOffset);\n}\n\n/**\n * Locate each hunk's position in OURS by matching context lines.\n * Returns null if any hunk cannot be located.\n */\nexport function locateHunksInOurs(\n hunks: DiffHunk[],\n oursLines: string[]\n): LocatedHunk[] | null {\n const located: LocatedHunk[] = [];\n let minOursIndex = 0;\n\n for (const hunk of hunks) {\n const contextLines = extractLeadingContext(hunk);\n let oursOffset: number;\n\n if (contextLines.length > 0) {\n const found = findContextInOurs(\n contextLines,\n oursLines,\n minOursIndex,\n hunk.newStart - 1\n );\n if (found === -1) {\n // Try trailing context as fallback\n const trailingContext = extractTrailingContext(hunk);\n if (trailingContext.length > 0) {\n const trailingFound = findContextInOurs(\n trailingContext,\n oursLines,\n minOursIndex,\n hunk.newStart - 1\n );\n if (trailingFound === -1) return null;\n const nonTrailingCount = countOursLinesBeforeTrailing(hunk);\n oursOffset = trailingFound - nonTrailingCount;\n if (oursOffset < minOursIndex) return null;\n } else {\n return null;\n }\n } else {\n oursOffset = found;\n }\n } else if (hunk.oldStart === 1 && hunk.oldCount === 0) {\n // Pure addition at start of file (or to empty file)\n oursOffset = 0;\n } else {\n // No context lines — use @@ header as best guess\n oursOffset = Math.max(hunk.newStart - 1, minOursIndex);\n }\n\n const oursSpan = computeOursSpan(hunk, oursLines, oursOffset);\n\n located.push({ hunk, oursOffset, oursSpan });\n minOursIndex = oursOffset + oursSpan;\n }\n\n return located;\n}\n\n// ---------------------------------------------------------------------------\n// 3. Assembler\n// ---------------------------------------------------------------------------\n\n/**\n * Assemble hybridBASE and hybridTHEIRS from located hunks and OURS.\n *\n * In gaps between hunks, BASE and THEIRS both get OURS content (3-way merge\n * treats gaps as \"no change\"). In hunk regions, BASE = context + removed,\n * THEIRS = context + added.\n */\nexport function assembleHybrid(\n locatedHunks: LocatedHunk[],\n oursLines: string[]\n): ReconstructionResult {\n const baseLines: string[] = [];\n const theirsLines: string[] = [];\n let oursCursor = 0;\n\n for (const { hunk, oursOffset, oursSpan } of locatedHunks) {\n // Gap before this hunk: fill with OURS content\n if (oursOffset > oursCursor) {\n const gapLines = oursLines.slice(oursCursor, oursOffset);\n baseLines.push(...gapLines);\n theirsLines.push(...gapLines);\n }\n\n // Hunk region: extract BASE lines and THEIRS lines from the diff\n for (const line of hunk.lines) {\n switch (line.type) {\n case \"context\":\n baseLines.push(line.content);\n theirsLines.push(line.content);\n break;\n case \"remove\":\n baseLines.push(line.content);\n break;\n case \"add\":\n theirsLines.push(line.content);\n break;\n }\n }\n\n oursCursor = oursOffset + oursSpan;\n }\n\n // Trailing gap after last hunk\n if (oursCursor < oursLines.length) {\n const gapLines = oursLines.slice(oursCursor);\n baseLines.push(...gapLines);\n theirsLines.push(...gapLines);\n }\n\n return {\n base: baseLines.join(\"\\n\"),\n theirs: theirsLines.join(\"\\n\")\n };\n}\n\n// ---------------------------------------------------------------------------\n// 4. Top-Level Entry Point\n// ---------------------------------------------------------------------------\n\n/**\n * Attempt to reconstruct BASE and THEIRS from a unified diff and OURS content.\n * Used when the patch's base generation tree is unreachable (ghost commit).\n *\n * Returns null if reconstruction fails (context mismatch, new/deleted file).\n */\nexport function reconstructFromGhostPatch(\n fileDiff: string,\n ours: string\n): ReconstructionResult | null {\n const hunks = parseHunks(fileDiff);\n\n if (hunks.length === 0) {\n return null;\n }\n\n // Pure new-file diff — use extractNewFileFromPatch instead\n const isPureAddition = hunks.every(\n (h) => h.oldCount === 0 && h.lines.every((l) => l.type !== \"remove\")\n );\n if (isPureAddition) {\n return null;\n }\n\n // Pure deletion\n const isPureDeletion = hunks.every(\n (h) => h.newCount === 0 && h.lines.every((l) => l.type !== \"add\")\n );\n if (isPureDeletion) {\n const baseLines: string[] = [];\n for (const hunk of hunks) {\n for (const line of hunk.lines) {\n if (line.type === \"context\" || line.type === \"remove\") {\n baseLines.push(line.content);\n }\n }\n }\n return {\n base: baseLines.join(\"\\n\"),\n theirs: \"\"\n };\n }\n\n const oursLines = ours.split(\"\\n\");\n const located = locateHunksInOurs(hunks, oursLines);\n\n if (!located) {\n return null;\n }\n\n return assembleHybrid(located, oursLines);\n}\n","import { mkdtemp, mkdir, writeFile, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { GitClient } from \"./git/GitClient.js\";\n\n/**\n * Apply a patch's `patch_content` to a base content string, returning the\n * post-apply (THEIRS) content.\n *\n * Free-function counterpart to `ReplayApplicator.applyPatchToContent`,\n * usable from `ReplayService.migratePatchesToSnapshot` without the\n * applicator's instance state. Creates its own temporary git repo each\n * call — fine for the one-shot migration path; not a hot loop.\n *\n * Returns `null` when the patch can't apply against the base (line\n * anchors don't match, malformed diff, or git apply rejects). Callers\n * fall back to a different THEIRS source.\n */\nexport async function applyPatchToContent(\n base: string,\n patchContent: string,\n filePath: string,\n): Promise<string | null> {\n const fileDiff = extractFileDiff(patchContent, filePath);\n if (!fileDiff) return null;\n\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-migrate-\"));\n const tempGit = new GitClient(tempDir);\n try {\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"migrate@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay Migration\"]);\n await tempGit.exec([\"config\", \"commit.gpgSign\", \"false\"]);\n\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, base);\n\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `base for ${filePath}`, \"--allow-empty\"]);\n\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n return await readFile(tempFilePath, \"utf-8\");\n } catch {\n return null;\n } finally {\n await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/**\n * Extract the diff hunks for `filePath` from a multi-file unified-diff\n * patch. Returns the slice starting at the file's `diff --git` header\n * up to the next `diff --git` (or end of input). Mirrors the logic in\n * `ReplayApplicator.extractFileDiff` — kept here for reuse without\n * exposing the private method.\n */\nfunction extractFileDiff(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const out: string[] = [];\n let inTarget = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTarget) break;\n const match = line.match(/^diff --git a\\/.+ b\\/(.+)$/);\n if (match && match[1] === filePath) {\n inTarget = true;\n out.push(line);\n }\n continue;\n }\n if (inTarget) out.push(line);\n }\n return out.length > 0 ? out.join(\"\\n\") + \"\\n\" : null;\n}\n","export type {\n GenerationLock,\n GenerationRecord,\n StoredPatch,\n CustomizationsConfig,\n MoveDeclaration,\n ReplayResult,\n FileResult,\n ConflictRegion,\n ConflictReason,\n ConflictMetadata,\n MergeResult,\n CommitInfo,\n ReplayConfig,\n FlowKind,\n} from \"./types.js\";\n\nexport {\n CREDENTIAL_PATTERNS,\n SENSITIVE_FILE_PATTERNS,\n isSensitiveFile,\n scanForCredentials,\n type CredentialPattern,\n} from \"./credentials.js\";\n\nexport { GitClient } from \"./git/GitClient.js\";\nexport {\n isGenerationCommit,\n isReplayCommit,\n isRevertCommit,\n parseRevertedSha,\n parseRevertedMessage,\n FERN_BOT_NAME,\n FERN_BOT_EMAIL,\n FERN_BOT_LOGIN,\n} from \"./git/CommitDetection.js\";\nexport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nexport { ReplayDetector, type DetectionResult } from \"./ReplayDetector.js\";\nexport { threeWayMerge } from \"./ThreeWayMerge.js\";\nexport { ReplayApplicator } from \"./ReplayApplicator.js\";\nexport { ReplayCommitter, type CommitOptions } from \"./ReplayCommitter.js\";\nexport {\n ReplayService,\n type ReplayReport,\n type ReplayOptions,\n type ApplyOptions,\n type ReplayPreparation,\n type ConflictDetail,\n type UnresolvedPatchInfo,\n} from \"./ReplayService.js\";\nexport { FernignoreMigrator, type MigrationAnalysis, type MigrationResult } from \"./FernignoreMigrator.js\";\nexport {\n bootstrap, type BootstrapOptions, type BootstrapResult,\n forget, type ForgetOptions, type ForgetResult, type MatchedPatch, type DiffStat,\n reset, type ResetOptions, type ResetResult,\n resolve, type ResolveOptions, type ResolveResult,\n status, type StatusResult, type StatusPatch, type StatusGeneration,\n} from \"./commands/index.js\";\n","/**\n * Credential detection patterns for the replay pipeline.\n *\n * Two-layer defense against credential leaks in .fern/replay.lock:\n * Layer 1 — file-level: SENSITIVE_FILE_PATTERNS blocks entire files (.env, .pem, etc.)\n * Layer 2 — content-level: CREDENTIAL_PATTERNS catches inline secrets in any file\n *\n * These patterns mirror the invariant assertions in __tests__/invariants/i4-credential-containment.ts.\n * If they diverge, the invariant tests independently catch real leaks.\n */\n\nexport interface CredentialPattern {\n name: string;\n re: RegExp;\n}\n\nexport const CREDENTIAL_PATTERNS: ReadonlyArray<CredentialPattern> = [\n { name: \"PRIVATE KEY block\", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },\n { name: \"OPENSSH key\", re: /-----BEGIN OPENSSH PRIVATE KEY-----/ },\n { name: \"RSA key\", re: /-----BEGIN RSA PRIVATE KEY-----/ },\n { name: \"CERTIFICATE\", re: /-----BEGIN CERTIFICATE-----/ },\n { name: \"TOKEN=\", re: /\\bTOKEN\\s*=\\s*[\"']?[A-Za-z0-9._\\-+/=]{10,}/ },\n { name: \"api_key=\", re: /\\bapi[_-]?key\\s*=\\s*[\"']?[A-Za-z0-9._\\-+/=]{10,}/i },\n { name: \"password=\", re: /\\bpassword\\s*=\\s*[\"']?[^\\s\"']{6,}/i },\n { name: \"AWS_SECRET_ACCESS_KEY\", re: /AWS_SECRET_ACCESS_KEY/ },\n { name: \"JWT (eyJ...)\", re: /\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b/ },\n];\n\nexport const SENSITIVE_FILE_PATTERNS: ReadonlyArray<RegExp> = [\n /(^|\\/)\\.env(\\.[^/]+)?$/,\n /\\.pem$/,\n /\\.key$/,\n /\\.pkce_state\\.json$/,\n /(^|\\/)id_rsa$/,\n /(^|\\/)id_ed25519$/,\n];\n\n/** Check if a file path matches any sensitive file pattern. */\nexport function isSensitiveFile(filePath: string): boolean {\n return SENSITIVE_FILE_PATTERNS.some((re) => re.test(filePath));\n}\n\n/** Scan content for credential patterns. Returns matched pattern names. */\nexport function scanForCredentials(content: string): string[] {\n const matches: string[] = [];\n for (const { name, re } of CREDENTIAL_PATTERNS) {\n if (re.test(content)) {\n matches.push(name);\n }\n }\n return matches;\n}\n","import type { CommitInfo } from \"../types.js\";\n\n// Constants from Fern's PR #11502\nexport const FERN_BOT_NAME = \"fern-api\";\nexport const FERN_BOT_EMAIL = \"115122769+fern-api[bot]@users.noreply.github.com\";\nexport const FERN_BOT_LOGIN = \"fern-api[bot]\";\n\n// Fern-support commits (via bot account) are excluded from generation detection.\nconst FERN_SUPPORT_NAMES = [\"fern-support\", \"Fern Support\"];\n\nexport function isGenerationCommit(commit: CommitInfo): boolean {\n const isFernSupport = FERN_SUPPORT_NAMES.includes(commit.authorName);\n\n const isBotAuthor =\n !isFernSupport &&\n (commit.authorLogin === FERN_BOT_LOGIN ||\n commit.authorEmail === FERN_BOT_EMAIL ||\n commit.authorName === FERN_BOT_NAME);\n\n const hasGenerationMarker =\n commit.message.startsWith(\"[fern-generated]\") ||\n commit.message.startsWith(\"[fern-replay]\") ||\n commit.message.startsWith(\"[fern-autoversion]\") ||\n commit.message.includes(\"Generated by Fern\") ||\n commit.message.includes(\"\\u{1F916} Generated with Fern\") ||\n // Squash merge of a Fern-generated PR uses the PR title as commit message.\n // The default PR title is \"SDK Generation\" (from GithubStep's commitMessage default).\n // GitHub appends \"(#N)\" for the PR number, e.g. \"SDK Generation (#70)\".\n commit.message.startsWith(\"SDK Generation\");\n\n return isBotAuthor || hasGenerationMarker;\n}\n\nexport function isReplayCommit(commit: CommitInfo): boolean {\n return commit.message.startsWith(\"[fern-replay]\");\n}\n\n/** Check if a commit message matches git's standard revert format: Revert \"...\" */\nexport function isRevertCommit(message: string): boolean {\n return /^Revert \".+\"$/.test(message);\n}\n\n/** Extract the reverted commit SHA from a full commit body containing \"This reverts commit SHA.\" */\nexport function parseRevertedSha(fullBody: string): string | undefined {\n const match = fullBody.match(/This reverts commit ([0-9a-f]{40})\\./);\n return match?.[1];\n}\n\n/** Extract the original commit message from a revert subject like 'Revert \"original message\"' */\nexport function parseRevertedMessage(subject: string): string | undefined {\n const match = subject.match(/^Revert \"(.+)\"$/);\n return match?.[1];\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { stringify, parse } from \"yaml\";\nimport { isSensitiveFile, scanForCredentials } from \"./credentials.js\";\nimport type {\n GenerationLock,\n GenerationRecord,\n StoredPatch,\n CustomizationsConfig,\n} from \"./types.js\";\n\nconst LOCKFILE_HEADER = \"# DO NOT EDIT MANUALLY - Managed by Fern Replay\\n\";\n\nexport class LockfileNotFoundError extends Error {\n constructor(path: string) {\n super(`Lockfile not found: ${path}`);\n this.name = \"LockfileNotFoundError\";\n }\n}\n\nexport class LockfileManager {\n private outputDir: string;\n private lock: GenerationLock | null = null;\n readonly warnings: string[] = [];\n\n constructor(outputDir: string) {\n this.outputDir = outputDir;\n }\n\n get lockfilePath(): string {\n return join(this.outputDir, \".fern\", \"replay.lock\");\n }\n\n get customizationsPath(): string {\n return join(this.outputDir, \".fern\", \"replay.yml\");\n }\n\n exists(): boolean {\n return existsSync(this.lockfilePath);\n }\n\n read(): GenerationLock {\n if (this.lock) {\n return this.lock;\n }\n try {\n const content = readFileSync(this.lockfilePath, \"utf-8\");\n this.lock = parse(content) as GenerationLock;\n return this.lock;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === \"ENOENT\"\n ) {\n throw new LockfileNotFoundError(this.lockfilePath);\n }\n throw error;\n }\n }\n\n initialize(firstGeneration: GenerationRecord): void {\n this.initializeInMemory(firstGeneration);\n this.save();\n }\n\n /**\n * Set up in-memory lock state without writing to disk.\n * Useful for bootstrap dry-run where we need state for detection\n * but don't want to persist anything.\n */\n initializeInMemory(firstGeneration: GenerationRecord): void {\n this.lock = {\n version: \"1.0\",\n generations: [firstGeneration],\n current_generation: firstGeneration.commit_sha,\n patches: [],\n };\n }\n\n save(): void {\n if (!this.lock) {\n throw new Error(\"No lockfile data to save. Call read() or initialize() first.\");\n }\n\n // Clear warnings from any previous save() call to prevent accumulation.\n this.warnings.length = 0;\n\n // Layer 2 credential safety net: scan all patches before writing.\n // Strips ENTIRE patches that contain credential content (in either\n // `patch_content` or `theirs_snapshot`) or reference sensitive files.\n // Snapshot scanning is essential — snapshots store full file content,\n // so they're strictly more credential-rich than the diff alone.\n // Without scanning snapshots, a customer-edited config with a\n // committed token would leak into `.fern/replay.lock` via the\n // snapshot field even though the patch_content scan caught nothing.\n //\n // Note: if a patch modifies both a sensitive file and a legitimate file, the entire\n // patch is dropped. This is a deliberate safety trade-off — partial redaction risks\n // leaving credential context that regex didn't catch. The customer gets a warning.\n const cleanPatches: StoredPatch[] = [];\n for (const patch of this.lock.patches) {\n const diffMatches = scanForCredentials(patch.patch_content);\n const snapshotMatches: string[] = [];\n if (patch.theirs_snapshot) {\n for (const content of Object.values(patch.theirs_snapshot)) {\n const m = scanForCredentials(content);\n for (const x of m) {\n if (!snapshotMatches.includes(x)) snapshotMatches.push(x);\n }\n }\n }\n const credentialMatches = [...diffMatches, ...snapshotMatches.filter((m) => !diffMatches.includes(m))];\n const sensitiveFiles = patch.files.filter((f) => isSensitiveFile(f));\n\n if (credentialMatches.length > 0 || sensitiveFiles.length > 0) {\n const reasons: string[] = [];\n if (credentialMatches.length > 0) {\n reasons.push(`credential patterns: ${credentialMatches.join(\", \")}`);\n }\n if (sensitiveFiles.length > 0) {\n reasons.push(`sensitive files: ${sensitiveFiles.join(\", \")}`);\n }\n this.warnings.push(\n `Patch ${patch.id} removed from lockfile: ${reasons.join(\"; \")}. ` +\n `This prevents credential exposure in committed lockfiles.`\n );\n } else {\n cleanPatches.push(patch);\n }\n }\n this.lock.patches = cleanPatches;\n\n const dir = dirname(this.lockfilePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const yaml = stringify(this.lock, {\n lineWidth: 0,\n blockQuote: \"literal\",\n });\n const content = LOCKFILE_HEADER + yaml;\n // Atomic write: write to temp file then rename (rename is atomic on most filesystems)\n const tmpPath = this.lockfilePath + \".tmp\";\n writeFileSync(tmpPath, content, \"utf-8\");\n renameSync(tmpPath, this.lockfilePath);\n }\n\n addGeneration(record: GenerationRecord): void {\n this.ensureLoaded();\n this.lock!.generations.push(record);\n this.lock!.current_generation = record.commit_sha;\n }\n\n addPatch(patch: StoredPatch): void {\n this.ensureLoaded();\n this.lock!.patches.push(patch);\n }\n\n updatePatch(\n patchId: string,\n updates: Partial<Pick<StoredPatch, \"base_generation\" | \"patch_content\" | \"content_hash\" | \"files\" | \"status\" | \"user_owned\" | \"theirs_snapshot\">>,\n ): void {\n this.ensureLoaded();\n const patch = this.lock!.patches.find((p) => p.id === patchId);\n if (!patch) {\n throw new Error(`Patch not found: ${patchId}`);\n }\n Object.assign(patch, updates);\n }\n\n removePatch(patchId: string): void {\n this.ensureLoaded();\n this.lock!.patches = this.lock!.patches.filter((p) => p.id !== patchId);\n }\n\n clearPatches(): void {\n this.ensureLoaded();\n this.lock!.patches = [];\n }\n\n addForgottenHash(hash: string): void {\n this.ensureLoaded();\n if (!this.lock!.forgotten_hashes) {\n this.lock!.forgotten_hashes = [];\n }\n if (!this.lock!.forgotten_hashes.includes(hash)) {\n this.lock!.forgotten_hashes.push(hash);\n }\n }\n\n getUnresolvedPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches.filter((p) => p.status === \"unresolved\");\n }\n\n getResolvingPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches.filter((p) => p.status === \"resolving\");\n }\n\n markPatchUnresolved(patchId: string): void {\n this.updatePatch(patchId, { status: \"unresolved\" });\n }\n\n markPatchResolved(\n patchId: string,\n updates: Pick<StoredPatch, \"patch_content\" | \"content_hash\" | \"base_generation\" | \"files\" | \"theirs_snapshot\">,\n ): void {\n this.ensureLoaded();\n const patch = this.lock!.patches.find((p) => p.id === patchId);\n if (!patch) {\n throw new Error(`Patch not found: ${patchId}`);\n }\n delete patch.status;\n Object.assign(patch, updates);\n }\n\n getPatches(): StoredPatch[] {\n this.ensureLoaded();\n return this.lock!.patches;\n }\n\n setReplaySkippedAt(timestamp: string): void {\n this.ensureLoaded();\n this.lock!.replay_skipped_at = timestamp;\n }\n\n clearReplaySkippedAt(): void {\n this.ensureLoaded();\n delete this.lock!.replay_skipped_at;\n }\n\n isReplaySkipped(): boolean {\n this.ensureLoaded();\n return this.lock!.replay_skipped_at != null;\n }\n\n getGeneration(commitSha: string): GenerationRecord | undefined {\n this.ensureLoaded();\n return this.lock!.generations.find((g) => g.commit_sha === commitSha);\n }\n\n getCustomizationsConfig(): CustomizationsConfig {\n if (!existsSync(this.customizationsPath)) {\n return {};\n }\n const content = readFileSync(this.customizationsPath, \"utf-8\");\n return (parse(content) as CustomizationsConfig) ?? {};\n }\n\n private ensureLoaded(): void {\n if (!this.lock) {\n throw new Error(\"No lockfile loaded. Call read() or initialize() first.\");\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { isSensitiveFile } from \"./credentials.js\";\nimport { isBinaryFile } from \"./shared/binary.js\";\nimport { isGenerationCommit, isRevertCommit, parseRevertedMessage, parseRevertedSha } from \"./git/CommitDetection.js\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport type { CommitInfo, GenerationLock, GenerationRecord, StoredPatch } from \"./types.js\";\n\ntype MergeCompositePatchInput = {\n mergeCommit: CommitInfo;\n firstParent: string;\n lastGen: GenerationRecord;\n lock: GenerationLock;\n};\n\n// Infrastructure files managed by the generation pipeline, not user code.\n// Changes to these should never be captured as customization patches.\nconst INFRASTRUCTURE_FILES = new Set([\".fernignore\"]);\n\n/**\n * Parse the `diff --git a/<p> b/<p>` headers out of a `git format-patch` blob\n * and classify each file as a creation (`new file mode …`), deletion\n * (`deleted file mode …`), or neither (modify / rename / chmod).\n *\n * Only handles the unquoted `a/…` `b/…` form — git quotes paths that contain\n * control characters or non-UTF-8 bytes (`\"a/weird\\tname.txt\"`), which the\n * parser skips. SDK files don't contain such characters in practice; if that\n * assumption is ever violated, quoted headers yield `currentPath = null` and\n * are silently ignored (false negative, never a false positive).\n */\nfunction parsePatchFileHeaders(patchContent: string): Array<{ path: string; isCreate: boolean; isDelete: boolean }> {\n const results: Array<{ path: string; isCreate: boolean; isDelete: boolean }> = [];\n let currentPath: string | null = null;\n let currentIsCreate = false;\n let currentIsDelete = false;\n\n const flush = () => {\n if (currentPath !== null) {\n results.push({ path: currentPath, isCreate: currentIsCreate, isDelete: currentIsDelete });\n }\n };\n\n for (const line of patchContent.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n flush();\n currentPath = null;\n currentIsCreate = false;\n currentIsDelete = false;\n // Unquoted form: \"diff --git a/<path> b/<path>\". Non-greedy matching\n // handles paths with spaces (e.g. \"sdk files/helper.py\") in the common\n // case. Pathological paths containing the literal substring \" b/\" are\n // mis-parsed; see the docstring for the safety argument (false\n // negatives are harmless, false positives are impossible).\n const match = line.match(/^diff --git a\\/(.+?) b\\/(.+?)$/);\n if (match) {\n // Track both sides — rename commits have a != b. Creations and\n // deletions always have a == b, so we record the (post-rename)\n // \"b\" path which is what `patch.files` will contain.\n currentPath = match[2] ?? null;\n }\n } else if (currentPath !== null) {\n if (line.startsWith(\"new file mode \")) {\n currentIsCreate = true;\n } else if (line.startsWith(\"deleted file mode \")) {\n currentIsDelete = true;\n }\n }\n }\n flush();\n return results;\n}\n\nasync function capturePatchSnapshot(\n git: GitClient,\n files: string[],\n treeish: string,\n): Promise<Record<string, string>> {\n const snapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await git.showFile(treeish, file).catch(() => null);\n if (content != null) snapshot[file] = content;\n }\n return snapshot;\n}\n\nfunction filterInfrastructureAndSensitiveFiles(\n rawFilesOutput: string,\n): { files: string[]; sensitiveFiles: string[] } {\n const allFiles = rawFilesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n .filter((f) => !f.startsWith(\".fern/\"));\n const sensitiveFiles = allFiles.filter((f) => isSensitiveFile(f));\n const files = allFiles.filter((f) => !isSensitiveFile(f));\n return { files, sensitiveFiles };\n}\n\nexport interface DetectionResult {\n patches: StoredPatch[];\n revertedPatchIds: string[];\n}\n\nexport class ReplayDetector {\n private git: GitClient;\n private lockManager: LockfileManager;\n private sdkOutputDir: string;\n readonly warnings: string[] = [];\n\n constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.sdkOutputDir = sdkOutputDir;\n }\n\n async detectNewPatches(): Promise<DetectionResult> {\n const lock = this.lockManager.read();\n const lastGen = this.getLastGeneration(lock);\n if (!lastGen) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const exists = await this.git.commitExists(lastGen.commit_sha);\n if (!exists) {\n this.warnings.push(\n `Generation commit ${lastGen.commit_sha.slice(0, 7)} not found in git history. ` +\n `Falling back to alternate detection.`\n );\n return this.detectPatchesViaTreeDiff(lastGen, /* commitKnownMissing */ true);\n }\n\n // Non-linear history (e.g. squash merge): walk merge-base..HEAD and\n // filter generation commits per-commit, the same way the linear path\n // does. The prior `detectPatchesViaTreeDiff` composite shortcut had\n // no commit awareness, so a `[fern-autoversion]` step subsumed by a\n // squash-merge would surface as a \"customer customization\" with the\n // placeholder→semver swap baked in.\n const isAncestor = await this.git.isAncestor(lastGen.commit_sha, \"HEAD\");\n if (!isAncestor) {\n return this.detectPatchesViaMergeBase(lastGen, lock);\n }\n\n return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);\n }\n\n /**\n * Non-linear-history detection via `merge-base(prevGen, HEAD)`.\n *\n * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous\n * `[fern-generated]`) is orphaned but still in git's object database. The\n * merge-base is the commit on main from which the bot's branch was created —\n * a reachable ancestor of HEAD. Walking that range and classifying each\n * commit via `isGenerationCommit` mirrors the linear path and eliminates\n * the bug class where pipeline-driven changes (autoversion, replay,\n * generation) get bundled as customer customizations.\n *\n * Falls through to the legacy composite path when no common ancestor exists\n * (truly disjoint history — orphan branches with no shared root).\n */\n private async detectPatchesViaMergeBase(\n lastGen: GenerationRecord,\n lock: GenerationLock,\n ): Promise<DetectionResult> {\n let mergeBase = \"\";\n try {\n mergeBase = (\n await this.git.exec([\"merge-base\", lastGen.commit_sha, \"HEAD\"])\n ).trim();\n } catch {\n // `git merge-base` exits non-zero when there's no common ancestor.\n }\n if (!mergeBase) {\n this.warnings.push(\n `No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. ` +\n `Falling back to composite tree-diff detection.`\n );\n return this.detectPatchesViaTreeDiff(lastGen, /* commitKnownMissing */ false);\n }\n return this.detectPatchesInRange(mergeBase, lastGen, lock);\n }\n\n /**\n * Walk `${rangeStart}..HEAD`, classify each commit, emit one\n * `StoredPatch` per customer commit. Body shared by the linear path\n * (rangeStart = lastGen.commit_sha) and the merge-base path.\n *\n * Patch `base_generation` is always `lastGen.commit_sha` — the\n * lockfile-tracked reference the applicator uses to fetch base file\n * content, regardless of where the walk actually started.\n */\n private async detectPatchesInRange(\n rangeStart: string,\n lastGen: GenerationRecord,\n lock: GenerationLock,\n ): Promise<DetectionResult> {\n const log = await this.git.exec([\n \"log\",\n \"--first-parent\",\n \"--format=%H%x00%an%x00%ae%x00%s\",\n `${rangeStart}..HEAD`,\n \"--\",\n this.sdkOutputDir\n ]);\n\n if (!log.trim()) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const commits = this.parseGitLog(log);\n const newPatches: StoredPatch[] = [];\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n\n for (const commit of commits) {\n if (isGenerationCommit(commit)) {\n continue;\n }\n\n if (lock.patches.find((p) => p.original_commit === commit.sha)) {\n continue;\n }\n\n const parents = await this.git.getCommitParents(commit.sha);\n\n if (parents.length > 1) {\n // Merge commit: produce a single composite patch via tree diff\n const compositePatch = await this.createMergeCompositePatch({\n mergeCommit: commit,\n firstParent: parents[0]!,\n lastGen,\n lock,\n });\n if (compositePatch) {\n newPatches.push(compositePatch);\n }\n continue;\n }\n\n let patchContent: string;\n try {\n patchContent = await this.git.formatPatch(commit.sha);\n } catch {\n this.warnings.push(\n `Could not generate patch for commit ${commit.sha.slice(0, 7)} — ` +\n `it may be unreachable in a shallow clone. Skipping.`\n );\n continue;\n }\n\n let contentHash = this.computeContentHash(patchContent);\n if (lock.patches.find((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n const { files, sensitiveFiles } = filterInfrastructureAndSensitiveFiles(filesOutput);\n\n if (sensitiveFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from patch for commit ${commit.sha.slice(0, 7)}: ` +\n `${sensitiveFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n\n // Regenerate patch content scoped to non-sensitive files only.\n // Recompute content hash to match the actual stored content.\n if (files.length > 0) {\n const parentSha = parents[0];\n if (parentSha) {\n try {\n patchContent = await this.git.exec([\"diff\", parentSha, commit.sha, \"--\", ...files]);\n } catch {\n continue;\n }\n if (!patchContent.trim()) continue;\n contentHash = this.computeContentHash(patchContent);\n }\n }\n }\n\n // Skip patches that only touch infrastructure/sensitive files\n if (files.length === 0) {\n continue;\n }\n\n // Snapshot THEIRS from the customer's commit tree (post-edit content).\n const theirsSnapshot = await capturePatchSnapshot(this.git, files, commit.sha);\n\n newPatches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: lastGen.commit_sha,\n files,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(patchContent) ? { user_owned: true } : {})\n });\n }\n\n // Collapse zero-net-change files on the linear path. On merge\n // commits, createMergeCompositePatch already diffs\n // firstParent..mergeCommit so transient files net out naturally. On\n // linear history each commit becomes its own patch, so a file\n // created in commit A and deleted in commit B survives as two\n // patches whose cumulative diff is empty. This filter drops such\n // patches before they reach the lockfile — and importantly, this\n // also prevents committed-then-deleted credentials (.env, .pem)\n // from leaking their contents verbatim into replay.lock.\n const survivingPatches = await this.collapseNetZeroFiles(newPatches);\n\n // Reverse so patches apply in chronological order (oldest first)\n survivingPatches.reverse();\n\n // Reconcile revert commits: match against existing and newly-detected patches.\n // Uses a Set for revertedPatchIds to avoid duplicate counting when multiple\n // reverts target the same patch.\n const revertedPatchIdSet = new Set<string>();\n const revertIndicesToRemove = new Set<number>();\n\n for (let i = 0; i < survivingPatches.length; i++) {\n const patch = survivingPatches[i]!;\n if (!isRevertCommit(patch.original_message)) continue;\n\n // Get full commit body for SHA extraction. May fail in shallow clones\n // or if the commit was GC'd — fall back to message-only matching.\n let body = \"\";\n try {\n body = await this.git.getCommitBody(patch.original_commit);\n } catch {\n // Shallow clone or unreachable commit — message matching only\n }\n const revertedSha = parseRevertedSha(body);\n const revertedMessage = parseRevertedMessage(patch.original_message);\n\n // Try to match against existing lockfile patches\n let matchedExisting = false;\n if (revertedSha) {\n const existing = lock.patches.find((p) => p.original_commit === revertedSha);\n if (existing) {\n revertedPatchIdSet.add(existing.id);\n revertIndicesToRemove.add(i);\n matchedExisting = true;\n }\n }\n if (!matchedExisting && revertedMessage) {\n const existing = lock.patches.find((p) => p.original_message === revertedMessage);\n if (existing) {\n revertedPatchIdSet.add(existing.id);\n revertIndicesToRemove.add(i);\n matchedExisting = true;\n }\n }\n\n if (matchedExisting) continue;\n\n // Try to match against newly-detected patches in the same run\n let matchedNew = false;\n if (revertedSha) {\n const idx = survivingPatches.findIndex(\n (p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_commit === revertedSha\n );\n if (idx !== -1) {\n revertIndicesToRemove.add(i);\n revertIndicesToRemove.add(idx);\n matchedNew = true;\n }\n }\n if (!matchedNew && revertedMessage) {\n const idx = survivingPatches.findIndex(\n (p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_message === revertedMessage\n );\n if (idx !== -1) {\n revertIndicesToRemove.add(i);\n revertIndicesToRemove.add(idx);\n }\n }\n\n // Unmatched revert: the original commit predates replay (e.g. .fernignore era).\n // A revert is never a customization — drop it so it doesn't become a patch.\n if (!matchedExisting && !matchedNew) {\n revertIndicesToRemove.add(i);\n }\n }\n\n const filteredPatches = survivingPatches.filter((_, i) => !revertIndicesToRemove.has(i));\n return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };\n }\n\n /**\n * Compute content hash for deduplication.\n *\n * Produces a format-agnostic hash so both `git format-patch` output\n * (email-wrapped) and plain `git diff` output hash to the same value\n * when the underlying diff hunks are identical.\n *\n * Normalization:\n * 1. Strip email wrapper: everything before the first `diff --git` line\n * (From:, Subject:, Date:, diffstat, blank separators).\n * 2. Strip `index` lines (blob SHA pairs change across rebases).\n * 3. Strip trailing git version marker (`-- \\n<version>`).\n *\n * This ensures content hashes match across the no-patches and normal-\n * regeneration flows, which store formatPatch and git-diff formats\n * respectively.\n */\n computeContentHash(patchContent: string): string {\n const lines = patchContent.split(\"\\n\");\n\n // Strip email wrapper: everything before the first 'diff --git'\n const diffStart = lines.findIndex((l) => l.startsWith(\"diff --git \"));\n const relevantLines = diffStart > 0 ? lines.slice(diffStart) : lines;\n\n const normalized = relevantLines\n .filter((line) => !line.startsWith(\"index \"))\n .join(\"\\n\")\n // Strip trailing git version marker (\"-- \\n2.x.x\")\n .replace(/\\n-- \\n[\\d]+\\.[\\d]+[^\\n]*\\s*$/, \"\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\n }\n\n /**\n * Drop patches whose files were transiently created and then deleted\n * within the current linear detection window, and are absent from\n * HEAD at the end of the window.\n *\n * Rationale: on a merge commit, createMergeCompositePatch already diffs\n * firstParent..mergeCommit so net-zero files never enter the composite. On\n * linear history each commit becomes its own patch, so a file that was\n * briefly added and later removed survives as a create+delete pair whose\n * cumulative diff is empty. We drop such patches before they reach the\n * lockfile.\n *\n * A file is \"transient\" when:\n * 1. some patch in the window sets `new file mode` for it (a creation), AND\n * 2. some patch in the window sets `deleted file mode` for it (a deletion), AND\n * 3. it is absent from HEAD's tree.\n *\n * The HEAD guard (#3) prevents false positives when a file is deleted\n * and then recreated with different content — the cumulative diff of\n * such a pair is non-empty and must be preserved.\n *\n * This only drops patches whose `files` are a subset of the transient\n * set. A partial-transient patch (one that touches a transient file\n * alongside a persistent one) is left unmodified; surgical stripping of\n * single files from a multi-file patch would require a follow-up that\n * regenerates the patch content via `git format-patch -- <files>`. No\n * current failing test exercises this, and leaving the patch intact\n * preserves today's behaviour. Revisit if a future adversarial test\n * demands per-file stripping.\n */\n private async collapseNetZeroFiles(patches: StoredPatch[]): Promise<StoredPatch[]> {\n if (patches.length === 0) return patches;\n\n type FileState = { created: boolean; deleted: boolean };\n const stateByFile = new Map<string, FileState>();\n\n for (const patch of patches) {\n for (const header of parsePatchFileHeaders(patch.patch_content)) {\n if (!header.isCreate && !header.isDelete) continue;\n const prior = stateByFile.get(header.path) ?? { created: false, deleted: false };\n if (header.isCreate) prior.created = true;\n if (header.isDelete) prior.deleted = true;\n stateByFile.set(header.path, prior);\n }\n }\n\n // No file has both a create and a delete event in the window → nothing to collapse.\n let anyCandidate = false;\n for (const state of stateByFile.values()) {\n if (state.created && state.deleted) { anyCandidate = true; break; }\n }\n if (!anyCandidate) return patches;\n\n const headFiles = await this.listHeadFiles();\n\n const transient = new Set<string>();\n for (const [file, state] of stateByFile) {\n if (state.created && state.deleted && !headFiles.has(file)) {\n transient.add(file);\n }\n }\n\n if (transient.size === 0) return patches;\n\n return patches.filter((patch) => !patch.files.every((f) => transient.has(f)));\n }\n\n /**\n * List every tracked path at HEAD (one `git ls-tree -r` invocation).\n * Returns an empty Set if HEAD is unborn or the invocation fails — the\n * caller then treats every candidate as \"not in HEAD\" and may collapse\n * more aggressively. On typical SDK repos this is a single sub-10ms call.\n */\n private async listHeadFiles(): Promise<Set<string>> {\n try {\n const out = await this.git.exec([\"ls-tree\", \"-r\", \"--name-only\", \"HEAD\"]);\n return new Set(out.split(\"\\n\").map((l) => l.trim()).filter(Boolean));\n } catch {\n return new Set();\n }\n }\n\n /**\n * Create a single composite patch for a merge commit by diffing the merge\n * commit against its first parent. This captures the net change of the\n * entire merged branch as one patch, eliminating accumulator chaining and\n * zero-net-change ghost conflicts.\n */\n private async createMergeCompositePatch(\n input: MergeCompositePatchInput\n ): Promise<StoredPatch | null> {\n const { mergeCommit, firstParent, lastGen, lock } = input;\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n\n // Diff first parent against merge commit to get net change of the branch\n const filesOutput = await this.git.exec([\n \"diff\", \"--name-only\", firstParent, mergeCommit.sha\n ]);\n const { files, sensitiveFiles } = filterInfrastructureAndSensitiveFiles(filesOutput);\n\n if (sensitiveFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from merge patch for commit ${mergeCommit.sha.slice(0, 7)}: ` +\n `${sensitiveFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n }\n\n if (files.length === 0) return null;\n\n const diff = await this.git.exec([\n \"diff\", firstParent, mergeCommit.sha, \"--\", ...files\n ]);\n if (!diff.trim()) return null;\n\n const contentHash = this.computeContentHash(diff);\n if (lock.patches.some((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {\n return null;\n }\n\n // Snapshot THEIRS from the merge commit's tree (post-merge content).\n const theirsSnapshot = await capturePatchSnapshot(this.git, files, mergeCommit.sha);\n\n return {\n id: `patch-merge-${mergeCommit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: mergeCommit.sha,\n original_message: mergeCommit.message,\n original_author: `${mergeCommit.authorName} <${mergeCommit.authorEmail}>`,\n base_generation: lastGen.commit_sha,\n files,\n patch_content: diff,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(diff) ? { user_owned: true } : {})\n };\n }\n\n /**\n * Detect patches via tree diff for non-linear history. Returns a composite patch.\n * Revert reconciliation is skipped here because tree-diff produces a single composite\n * patch from the aggregate diff — individual revert commits are not distinguishable.\n */\n private async detectPatchesViaTreeDiff(\n lastGen: GenerationRecord,\n commitKnownMissing: boolean\n ): Promise<DetectionResult> {\n // Use commit_sha if reachable, fall back to tree_hash for unreachable commits.\n // git diff accepts both commit and tree objects as arguments.\n const diffBase = await this.resolveDiffBase(lastGen, commitKnownMissing);\n if (!diffBase) {\n // Both commit and tree are gone (aggressive GC). Fall back to scanning\n // all commits from HEAD and filtering against known lockfile patches.\n return this.detectPatchesViaCommitScan();\n }\n\n // Data-integrity guard: composite patches must anchor on a recorded\n // [fern-generated] commit. When the original generation commit is\n // gone and diffBase resolves to some pre-Fern commit, emitting a\n // composite patch with that diffBase as base_generation would\n // orphan the patch — `resolveBaseGeneration` only finds SHAs in\n // `lock.generations`. Re-anchor on the lockfile's recorded\n // generation instead so downstream remains consistent.\n const lockForGuard = this.lockManager.read();\n const knownGenerations = new Set(lockForGuard.generations.map((g) => g.commit_sha));\n let resolvedBaseGeneration = commitKnownMissing ? diffBase : lastGen.commit_sha;\n if (commitKnownMissing && !knownGenerations.has(diffBase)) {\n const fallback = lockForGuard.current_generation\n ?? lockForGuard.generations[lockForGuard.generations.length - 1]?.commit_sha;\n if (!fallback) {\n this.warnings.push(\n `Composite-patch fallback skipped: diff base ${diffBase.slice(0, 7)} ` +\n `is not a recorded generation and the lockfile has no recorded generations ` +\n `to anchor on. Customer customizations on disk are preserved; tracked ` +\n `patches will resume on the next regeneration.`\n );\n return { patches: [], revertedPatchIds: [] };\n }\n resolvedBaseGeneration = fallback;\n }\n\n // Get changed files first, then filter before computing the diff\n const filesOutput = await this.git.exec([\"diff\", \"--name-only\", diffBase, \"HEAD\"]);\n const { files, sensitiveFiles } = filterInfrastructureAndSensitiveFiles(filesOutput);\n\n if (sensitiveFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from composite patch: ` +\n `${sensitiveFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n }\n\n if (files.length === 0) return { patches: [], revertedPatchIds: [] };\n\n // Compute diff only for the filtered files\n const diff = await this.git.exec([\"diff\", diffBase, \"HEAD\", \"--\", ...files]);\n if (!diff.trim()) return { patches: [], revertedPatchIds: [] };\n\n const contentHash = this.computeContentHash(diff);\n\n // Dedup against existing patches and forgotten hashes — if an existing patch\n // already captures this content, or it was explicitly forgotten, skip it.\n const lock = this.lockManager.read();\n if (lock.patches.some((p) => p.content_hash === contentHash) || (lock.forgotten_hashes ?? []).includes(contentHash)) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const headSha = (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n\n // Snapshot THEIRS from HEAD (the diff is diffBase → HEAD).\n const theirsSnapshot = await capturePatchSnapshot(this.git, files, \"HEAD\");\n\n const compositePatch: StoredPatch = {\n id: `patch-composite-${headSha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: headSha,\n original_message: \"Customer customizations (composite)\",\n original_author: \"composite\",\n // Anchor `base_generation` on a SHA the applicator's\n // `resolveBaseGeneration` can find — always a member of\n // `lock.generations`. When `diffBase` is a recorded\n // generation, use it directly; otherwise the guard above\n // has already mapped it onto `current_generation`.\n base_generation: resolvedBaseGeneration,\n files,\n patch_content: diff,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n ...(this.isCreationOnlyPatch(diff) ? { user_owned: true } : {})\n };\n\n return { patches: [compositePatch], revertedPatchIds: [] };\n }\n\n /**\n * Last-resort detection when both generation commit and tree are unreachable.\n * Scans all commits from HEAD, filters against known lockfile patches, and\n * skips creation-only commits (squashed history after force push).\n *\n * Detected patches use the commit's parent as base_generation so the applicator\n * can find base file content from the parent's tree (which IS reachable).\n */\n private async detectPatchesViaCommitScan(): Promise<DetectionResult> {\n const lock = this.lockManager.read();\n const knownGenerations = new Set(lock.generations.map((g) => g.commit_sha));\n // Anchor for emitted patches when the parent commit isn't itself a\n // recorded generation: prefer current_generation, fall back to the\n // last generation in the list. This keeps `base_generation` pointing\n // at a SHA that the applicator's `resolveBaseGeneration` can find,\n // even when the actual git history is rewritten or shallow.\n const fallbackAnchor =\n lock.current_generation ?? lock.generations[lock.generations.length - 1]?.commit_sha;\n const log = await this.git.exec([\n \"log\",\n \"--max-count=200\",\n \"--format=%H%x00%an%x00%ae%x00%s\",\n \"HEAD\",\n \"--\",\n this.sdkOutputDir\n ]);\n\n if (!log.trim()) {\n return { patches: [], revertedPatchIds: [] };\n }\n\n const commits = this.parseGitLog(log);\n const newPatches: StoredPatch[] = [];\n const forgottenHashes = new Set(lock.forgotten_hashes ?? []);\n const existingHashes = new Set(lock.patches.map((p) => p.content_hash));\n const existingCommits = new Set(lock.patches.map((p) => p.original_commit));\n\n for (const commit of commits) {\n if (isGenerationCommit(commit)) {\n continue;\n }\n\n const parents = await this.git.getCommitParents(commit.sha);\n if (parents.length > 1) {\n continue;\n }\n\n if (existingCommits.has(commit.sha)) {\n continue;\n }\n\n let patchContent: string;\n try {\n patchContent = await this.git.formatPatch(commit.sha);\n } catch {\n continue;\n }\n\n let contentHash = this.computeContentHash(patchContent);\n if (existingHashes.has(contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n // Skip creation-only commits (all diffs are new-file additions).\n // After force push, squashed commits create all files from scratch — these\n // aren't user customizations, they're history-rewriting artifacts.\n if (this.isCreationOnlyPatch(patchContent)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n const { files, sensitiveFiles } = filterInfrastructureAndSensitiveFiles(filesOutput);\n\n if (sensitiveFiles.length > 0) {\n this.warnings.push(\n `Sensitive file(s) excluded from patch for commit ${commit.sha.slice(0, 7)}: ` +\n `${sensitiveFiles.join(\", \")}. These files will not be tracked by replay.`\n );\n\n // Regenerate patch content scoped to non-sensitive files only.\n // Recompute content hash to match the actual stored content.\n if (files.length > 0) {\n if (parents.length === 0) {\n continue;\n }\n try {\n patchContent = await this.git.exec([\"diff\", parents[0]!, commit.sha, \"--\", ...files]);\n } catch {\n continue;\n }\n if (!patchContent.trim()) continue;\n contentHash = this.computeContentHash(patchContent);\n }\n }\n\n if (files.length === 0) {\n continue;\n }\n\n // Use the parent commit as base_generation when it's a recorded\n // generation, so the applicator can find base file content from\n // a known anchor. Otherwise fall back to the lockfile's most\n // recent recorded generation — patches with a parent SHA outside\n // `lock.generations` would otherwise create orphans the\n // applicator's `resolveBaseGeneration` cannot resolve, cascading\n // into spurious unresolved-conflict classifications.\n // Root commits (no parents) can't use this strategy — skip them.\n if (parents.length === 0) {\n continue;\n }\n const parentSha = parents[0]!;\n let baseGeneration: string;\n if (knownGenerations.has(parentSha)) {\n baseGeneration = parentSha;\n } else if (fallbackAnchor) {\n baseGeneration = fallbackAnchor;\n } else {\n // No recorded generations at all — nothing safe to anchor on.\n this.warnings.push(\n `Skipping commit ${commit.sha.slice(0, 7)} (${commit.message.split(\"\\n\")[0]}): ` +\n `no recorded generation in the lockfile to anchor on. The customer's ` +\n `state on disk is preserved; tracked patches will resume on the next regeneration.`\n );\n continue;\n }\n\n // user_owned not tagged here — see known-divergences.md §3.\n const theirsSnapshot = await capturePatchSnapshot(this.git, files, commit.sha);\n newPatches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: baseGeneration,\n files,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {})\n });\n }\n\n newPatches.reverse();\n return { patches: newPatches, revertedPatchIds: [] };\n }\n\n /**\n * Check if a format-patch consists entirely of new-file creations.\n * Used to identify squashed commits after force push, which create all files\n * from scratch (--- /dev/null) rather than modifying existing files.\n */\n private isCreationOnlyPatch(patchContent: string): boolean {\n const diffOldHeaders = patchContent.split(\"\\n\").filter((l) => l.startsWith(\"--- \"));\n if (diffOldHeaders.length === 0) {\n return false;\n }\n return diffOldHeaders.every((l) => l === \"--- /dev/null\");\n }\n\n /**\n * Resolve the best available diff base for a generation record.\n * Prefers commit_sha, falls back to tree_hash for unreachable commits.\n * When commitKnownMissing is true, skips the redundant commitExists check.\n */\n private async resolveDiffBase(gen: GenerationRecord, commitKnownMissing: boolean): Promise<string | null> {\n if (!commitKnownMissing && await this.git.commitExists(gen.commit_sha)) {\n return gen.commit_sha;\n }\n if (await this.git.treeExists(gen.tree_hash)) {\n return gen.tree_hash;\n }\n return null;\n }\n\n private parseGitLog(log: string): CommitInfo[] {\n return log\n .trim()\n .split(\"\\n\")\n .map((line) => {\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n });\n }\n\n private getLastGeneration(lock: GenerationLock) {\n return lock.generations.find((g) => g.commit_sha === lock.current_generation);\n }\n}\n","import { extname } from \"node:path\";\n\n/**\n * File extensions that replay treats as binary. Binary files are skipped\n * during merge — no diff3, no patch_content extraction, no theirs_snapshot.\n *\n * Covers images, documents, archives, fonts, media, databases, and\n * compiled artifacts. Detection is extension-based (not magic-byte) — fast\n * and good enough for SDK-generation outputs.\n */\nexport const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".bmp\",\n \".ico\",\n \".webp\",\n \".svg\",\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".zip\",\n \".gz\",\n \".tar\",\n \".bz2\",\n \".7z\",\n \".rar\",\n \".jar\",\n \".war\",\n \".ear\",\n \".class\",\n \".exe\",\n \".dll\",\n \".so\",\n \".dylib\",\n \".o\",\n \".a\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".otf\",\n \".mp3\",\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wav\",\n \".flac\",\n \".sqlite\",\n \".db\",\n \".pyc\",\n \".pyo\",\n \".DS_Store\",\n]);\n\nexport function isBinaryFile(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\n}\n","import { diff3Merge, diffPatch } from \"node-diff3\";\nimport type { IPatchRes } from \"node-diff3\";\nimport type { ConflictRegion, MergeResult } from \"./types.js\";\n\n/**\n * Performs a 3-way merge using the diff3 algorithm.\n *\n * @param base - The common ancestor (pristine generated state user edited against)\n * @param ours - The new generated version\n * @param theirs - The user's customized version\n * @returns MergeResult with content, conflict flag, and conflict regions\n */\nexport function threeWayMerge(base: string, ours: string, theirs: string): MergeResult {\n const baseLines = base.split(\"\\n\");\n const oursLines = ours.split(\"\\n\");\n const theirsLines = theirs.split(\"\\n\");\n\n const regions = diff3Merge(oursLines, baseLines, theirsLines);\n\n const outputLines: string[] = [];\n const conflicts: ConflictRegion[] = [];\n let currentLine = 1;\n\n for (const region of regions) {\n if (region.ok) {\n outputLines.push(...region.ok);\n currentLine += region.ok.length;\n } else if (region.conflict) {\n // Attempt to resolve false conflicts caused by adjacent non-overlapping changes.\n // node-diff3 groups adjacent edits into one conflict region even when the\n // generator and user changed completely different lines within that region.\n const resolved = tryResolveConflict(\n region.conflict.a, // ours (generator)\n region.conflict.o, // base\n region.conflict.b // theirs (user)\n );\n\n if (resolved !== null) {\n outputLines.push(...resolved);\n currentLine += resolved.length;\n } else {\n const startLine = currentLine;\n\n outputLines.push(\"<<<<<<< Generated\");\n outputLines.push(...region.conflict.a);\n outputLines.push(\"=======\");\n outputLines.push(...region.conflict.b);\n outputLines.push(\">>>>>>> Your customization\");\n\n // Total lines in conflict block: 3 markers + a.length + b.length\n // endLine is the line number of the \">>>>>>>\" marker\n const conflictLines = region.conflict.a.length + region.conflict.b.length + 3;\n conflicts.push({\n startLine,\n endLine: startLine + conflictLines - 1,\n ours: region.conflict.a,\n theirs: region.conflict.b\n });\n\n currentLine += conflictLines;\n }\n }\n }\n\n const result: MergeResult = {\n content: outputLines.join(\"\\n\"),\n hasConflicts: conflicts.length > 0,\n conflicts\n };\n\n // Detect lines that were unchanged context in the customer's THEIRS but\n // got silently deleted by the generator. Only meaningful when no\n // conflicts surfaced — when conflicts exist, the customer already has a\n // marker to review. We compare against the lines diff3 actually emitted,\n // which means a deleted-once-but-still-present-elsewhere line counts as\n // dropped if its multiplicity decreased; that's accurate for the auth0\n // case (each wiring line is a unique signature).\n if (conflicts.length === 0) {\n const dropped = computeDroppedContextLines(baseLines, theirsLines, outputLines);\n if (dropped.length > 0) {\n result.droppedContextLines = dropped;\n }\n }\n\n return result;\n}\n\n/**\n * Lines present in BOTH base and theirs but absent from the merge output.\n * These are lines the customer's THEIRS treated as context (didn't edit);\n * OURS deleted; diff3 sided with the deletion. Returns empty array when\n * none. Order preserved per first occurrence in `base`.\n */\nfunction computeDroppedContextLines(\n baseLines: string[],\n theirsLines: string[],\n mergedLines: string[]\n): string[] {\n const baseCounts = countLines(baseLines);\n const theirsCounts = countLines(theirsLines);\n const mergedCounts = countLines(mergedLines);\n\n const dropped: string[] = [];\n const seen = new Set<string>();\n\n for (const line of baseLines) {\n if (seen.has(line)) continue;\n const inBase = baseCounts.get(line) ?? 0;\n const inTheirs = theirsCounts.get(line) ?? 0;\n const inMerged = mergedCounts.get(line) ?? 0;\n\n // Line was in BOTH base and theirs (unchanged context) AND its\n // multiplicity went down in the merge. The deletion came from OURS.\n if (inBase > 0 && inTheirs > 0 && inMerged < Math.min(inBase, inTheirs)) {\n dropped.push(line);\n seen.add(line);\n }\n }\n\n return dropped;\n}\n\nfunction countLines(lines: string[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const line of lines) {\n counts.set(line, (counts.get(line) ?? 0) + 1);\n }\n return counts;\n}\n\n/**\n * Attempts to resolve a false conflict by checking if ours and theirs\n * changed non-overlapping lines within the conflict region's base.\n * Returns merged lines if resolvable, or null for a real conflict.\n */\nfunction tryResolveConflict(\n oursLines: string[],\n baseLines: string[],\n theirsLines: string[]\n): string[] | null {\n if (baseLines.length === 0) {\n return null;\n }\n\n const oursPatches = diffPatch(baseLines, oursLines);\n const theirsPatches = diffPatch(baseLines, theirsLines);\n\n if (oursPatches.length === 0) return theirsLines;\n if (theirsPatches.length === 0) return oursLines;\n\n if (patchesOverlap(oursPatches, theirsPatches)) {\n return null;\n }\n\n return applyBothPatches(baseLines, oursPatches, theirsPatches);\n}\n\n/**\n * Checks if any patch ranges overlap in base coordinates.\n */\nfunction patchesOverlap(\n oursPatches: IPatchRes<string>[],\n theirsPatches: IPatchRes<string>[]\n): boolean {\n for (const op of oursPatches) {\n const oStart = op.buffer1.offset;\n const oEnd = oStart + op.buffer1.length;\n for (const tp of theirsPatches) {\n const tStart = tp.buffer1.offset;\n const tEnd = tStart + tp.buffer1.length;\n\n // Both are pure insertions at the same point\n if (op.buffer1.length === 0 && tp.buffer1.length === 0 && oStart === tStart) {\n return true;\n }\n // Insertion at the exact boundary of a deletion/replacement.\n // Example: generator deletes lines [0,2) and user inserts at offset 2.\n // The insertion's surrounding context has been rewritten, so splicing\n // both into base would produce a semantically broken result (e.g. user\n // content appended after a file-deletion). Treating this as overlap is\n // conservative — it keeps the conflict for manual resolution rather than\n // silently producing a bad merge.\n if (tp.buffer1.length === 0 && tStart === oEnd) {\n return true;\n }\n if (op.buffer1.length === 0 && oStart === tEnd) {\n return true;\n }\n // Standard range overlap\n if (oStart < tEnd && tStart < oEnd) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Applies both sets of non-overlapping patches to base.\n * Patches are sorted by descending offset and applied via splice\n * to avoid index invalidation.\n */\nfunction applyBothPatches(\n baseLines: string[],\n oursPatches: IPatchRes<string>[],\n theirsPatches: IPatchRes<string>[]\n): string[] {\n const allPatches = [\n ...oursPatches.map(p => ({\n offset: p.buffer1.offset,\n length: p.buffer1.length,\n replacement: p.buffer2.chunk,\n })),\n ...theirsPatches.map(p => ({\n offset: p.buffer1.offset,\n length: p.buffer1.length,\n replacement: p.buffer2.chunk,\n })),\n ];\n\n allPatches.sort((a, b) => b.offset - a.offset);\n\n const result = [...baseLines];\n for (const p of allPatches) {\n result.splice(p.offset, p.length, ...p.replacement);\n }\n return result;\n}\n","import { mkdir, mkdtemp, readFile, rm, unlink, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { MergeAccumulator, type AccumulatorEntry } from \"./accumulator/MergeAccumulator.js\";\nimport { buildMergePlan, resolveInputs, runMergeAndRecord } from \"./applicator/index.js\";\nimport { stripConflictMarkers } from \"./conflict-utils.js\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport { isBinaryFile } from \"./shared/binary.js\";\nimport type {\n ConflictReason,\n FileResult,\n GenerationRecord,\n ReplayResult,\n StoredPatch\n} from \"./types.js\";\n\n// Re-exported from `./shared/binary.js` — kept here for back-compat with\n// external imports (`@fern-api/replay/dist/ReplayApplicator`). New code\n// should import from `./shared/binary.js` directly.\nexport { isBinaryFile } from \"./shared/binary.js\";\n\nexport class ReplayApplicator {\n private git: GitClient;\n private lockManager: LockfileManager;\n private outputDir: string;\n private renameCache = new Map<string, Array<{ from: string; to: string }>>();\n private treeExistsCache = new Map<string, boolean>();\n\n /**\n * Inter-patch THEIRS coordination. Created fresh in each `applyPatches`\n * invocation with the run's apply mode + precomputed shared-file set.\n * See `src/accumulator/MergeAccumulator.ts` for the full contract.\n *\n * Initialized to an empty default in the constructor so type narrowing\n * works for callers that read it before any `applyPatches` invocation\n * (e.g., the `getAccumulatorSnapshot` test accessor).\n */\n private accumulator = new MergeAccumulator(\"replay\", new Set());\n\n constructor(git: GitClient, lockManager: LockfileManager, outputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.outputDir = outputDir;\n }\n\n /**\n * Resolve the GenerationRecord for a patch's base_generation.\n * Falls back to constructing an ad-hoc record from the commit's tree\n * when base_generation isn't a tracked generation (commit-scan patches).\n */\n private async resolveBaseGeneration(baseGeneration: string): Promise<GenerationRecord | undefined> {\n const gen = this.lockManager.getGeneration(baseGeneration);\n if (gen) return gen;\n try {\n const treeHash = await this.git.getTreeHash(baseGeneration);\n return {\n commit_sha: baseGeneration,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: \"unknown\",\n generator_versions: {}\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * @internal Test-only.\n * Returns a defensive copy of the inter-patch accumulator. Used by\n * invariant I2 to assert that after every applied patch, the\n * accumulator has an entry for each file the patch touched, and the\n * entry's content matches on-disk.\n */\n getAccumulatorSnapshot(): ReadonlyMap<string, AccumulatorEntry> {\n return this.accumulator.snapshot();\n }\n\n /**\n * Apply all patches, returning results for each.\n * Skips patches that match exclude patterns in replay.yml\n *\n * `applyMode` controls the post-conflict marker strategy:\n * - `\"replay\"` (default): strip conflict markers from disk between\n * iterations whenever a later patch touches the same file. Lets the\n * follow-up patch's `git apply --3way` see clean OURS content,\n * which is what the silent-loss fix (PR #73) relies on. The replay\n * pipeline calls `revertConflictingFiles` after the loop to clean\n * any markers that survive.\n * - `\"resolve\"`: keep markers on disk. The resolve command needs the\n * customer to see them. Slow-path 3-way merge naturally preserves\n * A's markers and B's clean writes when their regions don't overlap;\n * when they do overlap, the customer gets nested markers and\n * resolves manually. Either way they aren't silently dropped.\n */\n async applyPatches(\n patches: StoredPatch[],\n opts?: { applyMode?: \"replay\" | \"resolve\" }\n ): Promise<ReplayResult[]> {\n const applyMode = opts?.applyMode ?? \"replay\";\n\n // Compute set of files shared by 2+ patches in this run. Used by\n // the accumulator to gate snapshot-as-primary in mergeFile and\n // populateAccumulatorForPatch — see cross-patch isolation.\n const fileFreq = new Map<string, number>();\n for (const p of patches) {\n for (const f of p.files) {\n fileFreq.set(f, (fileFreq.get(f) ?? 0) + 1);\n }\n }\n const sharedFiles = new Set(\n Array.from(fileFreq.entries())\n .filter(([, n]) => n > 1)\n .map(([f]) => f),\n );\n\n // Fresh accumulator per apply cycle — single-use, single owner.\n this.accumulator = new MergeAccumulator(applyMode, sharedFiles);\n\n const results: ReplayResult[] = [];\n\n for (let i = 0; i < patches.length; i++) {\n const patch = patches[i]!;\n\n if (this.isExcluded(patch)) {\n results.push({\n patch,\n status: \"skipped\",\n method: \"git-am\"\n });\n continue;\n }\n\n const result = await this.applyPatchWithFallback(patch);\n results.push(result);\n\n // Strip conflict markers from files that a later patch will also\n // touch. This prevents marker cascade into the next patch's OURS\n // while preserving markers on files only this patch touches (needed\n // by the resolve workflow for user resolution). Only fires in\n // replay mode — resolve mode keeps markers on disk so the customer\n // can see and edit them.\n if (applyMode !== \"resolve\" && result.status === \"conflict\" && result.fileResults) {\n // Later patches list original (pre-rename) paths in their files array.\n const laterFiles = new Set<string>();\n for (let j = i + 1; j < patches.length; j++) {\n for (const f of patches[j]!.files) {\n laterFiles.add(f);\n }\n }\n\n // Build reverse rename map: resolved path → original path.\n // fileResult.file is the resolved path, but laterFiles has originals.\n const resolvedToOriginal = new Map<string, string>();\n if (result.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(result.resolvedFiles)) {\n resolvedToOriginal.set(resolved, orig);\n }\n }\n\n for (const fileResult of result.fileResults) {\n if (fileResult.status !== \"conflict\") continue;\n // Check both resolved and original paths against later patches\n const originalPath = resolvedToOriginal.get(fileResult.file) ?? fileResult.file;\n if (laterFiles.has(fileResult.file) || laterFiles.has(originalPath)) {\n const filePath = join(this.outputDir, fileResult.file);\n try {\n const content = await readFile(filePath, \"utf-8\");\n const stripped = stripConflictMarkers(content);\n await writeFile(filePath, stripped);\n } catch {\n // File doesn't exist or can't be read — skip\n }\n }\n }\n }\n }\n\n return results;\n }\n\n /**\n * Populate accumulator after git apply succeeds, AND collect per-file\n * results including any \"dropped context lines\" — lines that were\n * present in BASE and THEIRS (unchanged context) but absent from the\n * final on-disk state because OURS deleted them. This is the fast-path\n * counterpart to ThreeWayMerge.computeDroppedContextLines used by the\n * 3-way slow path; both must surface the same warning.\n */\n private async populateAccumulatorForPatch(\n patch: StoredPatch,\n baseGen: GenerationRecord | undefined,\n currentTreeHash: string\n ): Promise<FileResult[]> {\n const fileResults: FileResult[] = [];\n if (!baseGen) return fileResults;\n\n // Create temp git repo to apply patches to base content\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-acc-\"));\n const { GitClient } = await import(\"./git/GitClient.js\");\n const tempGit = new GitClient(tempDir);\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"replay@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay\"]);\n\n try {\n for (const filePath of patch.files) {\n if (isBinaryFile(filePath)) continue;\n\n const resolvedPath = await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);\n\n const base = await this.git.showFile(baseGen.tree_hash, filePath);\n\n // For non-shared-file patches, the stored snapshot IS this\n // patch's THEIRS for the accumulator (individual contribution\n // by definition: only this patch touches the file). Skip\n // reconstruction. For shared-file patches, fall back to\n // line-anchored reconstruction so the accumulator entry is\n // each patch's INDIVIDUAL contribution (cross-patch isolation).\n // See `mergeFile` for the full rationale.\n const snapshotForFile =\n patch.theirs_snapshot?.[resolvedPath] ?? patch.theirs_snapshot?.[filePath];\n const fileIsShared =\n this.accumulator.isShared(resolvedPath) || this.accumulator.isShared(filePath);\n const theirs = !fileIsShared && snapshotForFile != null\n ? snapshotForFile\n : await this.applyPatchToContent(base, patch.patch_content, filePath, tempGit, tempDir);\n\n // For user-created files (base=null), applyPatchToContent may return null\n // for modification diffs. Fall back to reading the on-disk content that\n // git apply --3way just wrote successfully.\n const finalOnDisk = await readFile(join(this.outputDir, resolvedPath), \"utf-8\").catch(() => null);\n const effectiveTheirs = theirs ?? finalOnDisk;\n if (effectiveTheirs != null) {\n this.accumulator.recordMerge(resolvedPath, effectiveTheirs, patch.base_generation);\n }\n\n // Detect lines that were in BOTH base and theirs but absent\n // from the final on-disk state — silently dropped by OURS.\n if (base != null && effectiveTheirs != null && finalOnDisk != null) {\n const dropped = computeDroppedContextLinesForFile(base, effectiveTheirs, finalOnDisk);\n if (dropped.length > 0) {\n fileResults.push({\n file: resolvedPath,\n status: \"merged\",\n droppedContextLines: dropped\n });\n }\n }\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\n return fileResults;\n }\n\n private async applyPatchWithFallback(patch: StoredPatch): Promise<ReplayResult> {\n // Resolve all file paths to check accumulator (need baseGen for resolution)\n const baseGen = await this.resolveBaseGeneration(patch.base_generation);\n const lock = this.lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n const currentTreeHash = currentGen?.tree_hash ?? baseGen?.tree_hash ?? \"\";\n\n // Check if any file in this patch needs accumulation\n // If so, skip fast path to ensure we benefit from pre-merge logic\n const needsAccumulation = await Promise.all(\n patch.files.map(async (f) => {\n if (!baseGen) return false;\n const resolved = await this.resolveFilePath(f, baseGen.tree_hash, currentTreeHash);\n return this.accumulator.has(resolved);\n })\n ).then((results) => results.some(Boolean));\n\n // Pre-compute resolved paths. If the tree-level rename/copy detection says\n // a file moved but the patch content itself doesn't describe the rename,\n // this is a GENERATOR rename and the git-apply fast path is unsafe: it would\n // apply the content diff against the original path (even if still on disk)\n // rather than the resolved new path. The 3-way merge path uses `resolvedPath`\n // for OURS and for the output write, so it handles this correctly.\n //\n // USER renames (patch contains `rename from`/`rename to` headers) go through\n // the fast path because git apply handles those natively — skipping the fast\n // path there would break user-rename scenarios.\n const resolvedFiles: Record<string, string> = {};\n for (const filePath of patch.files) {\n const resolvedPath = baseGen\n ? await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash)\n : filePath;\n if (resolvedPath !== filePath) {\n resolvedFiles[filePath] = resolvedPath;\n }\n }\n const patchIsRenameAware = /^rename from /m.test(patch.patch_content);\n const hasGeneratorRename = Object.keys(resolvedFiles).length > 0 && !patchIsRenameAware;\n\n // Strategy 1: Try git apply --3way (skip if accumulation needed or a generator rename was detected)\n if (!needsAccumulation && !hasGeneratorRename) {\n // Snapshot files before git apply (may leave conflict markers on failure)\n const snapshots = new Map<string, string | null>();\n for (const filePath of patch.files) {\n const fullPath = join(this.outputDir, filePath);\n snapshots.set(filePath, await readFile(fullPath, \"utf-8\").catch(() => null));\n }\n\n try {\n await this.git.execWithInput([\"apply\", \"--3way\"], patch.patch_content);\n\n // Success! Populate accumulator so subsequent patches on these files\n // will skip fast path and use the pre-merge logic instead.\n // Also collect per-file results (notably droppedContextLines).\n const fastPathFileResults = await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);\n\n return {\n patch,\n status: \"applied\",\n method: \"git-am\",\n ...(fastPathFileResults.length > 0 && { fileResults: fastPathFileResults }),\n ...(Object.keys(resolvedFiles).length > 0 && { resolvedFiles })\n };\n } catch {\n // git apply --3way failed and may have left conflict markers on disk\n // Restore files from snapshot to undo any corruption before fallback\n for (const [filePath, content] of snapshots) {\n const fullPath = join(this.outputDir, filePath);\n if (content != null) {\n await writeFile(fullPath, content);\n } else {\n // Delete files created by the failed git apply that didn't exist before\n await unlink(fullPath).catch(() => {});\n }\n }\n }\n }\n\n // Strategy 2: Fall back to file-by-file 3-way merge (uses accumulator)\n return this.applyWithThreeWayMerge(patch);\n }\n\n private async applyWithThreeWayMerge(patch: StoredPatch): Promise<ReplayResult> {\n const fileResults: FileResult[] = [];\n const resolvedFiles: Record<string, string> = {};\n\n const tempDir = await mkdtemp(join(tmpdir(), \"replay-\"));\n const { GitClient } = await import(\"./git/GitClient.js\");\n const tempGit = new GitClient(tempDir);\n await tempGit.exec([\"init\"]);\n await tempGit.exec([\"config\", \"user.email\", \"replay@fern.com\"]);\n await tempGit.exec([\"config\", \"user.name\", \"Fern Replay\"]);\n\n try {\n for (const filePath of patch.files) {\n if (isBinaryFile(filePath)) {\n fileResults.push({\n file: filePath,\n status: \"skipped\",\n reason: \"binary-file\"\n });\n continue;\n }\n const result = await this.mergeFile(patch, filePath, tempGit, tempDir);\n if (result.file !== filePath) {\n resolvedFiles[filePath] = result.file;\n }\n fileResults.push(result);\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\n\n const conflictFiles = fileResults.filter((r) => r.status === \"conflict\");\n const hasConflicts = conflictFiles.length > 0;\n\n // Aggregate conflict reason from file-level to patch-level\n const conflictReason: ConflictReason | undefined = hasConflicts\n ? conflictFiles.some((f) => f.conflictReason === \"base-generation-mismatch\")\n ? \"base-generation-mismatch\"\n : conflictFiles[0]?.conflictReason\n : undefined;\n\n return {\n patch,\n status: hasConflicts ? \"conflict\" : \"applied\",\n method: \"3way-merge\",\n fileResults,\n conflictReason,\n ...(Object.keys(resolvedFiles).length > 0 && { resolvedFiles })\n };\n }\n\n private async mergeFile(\n patch: StoredPatch,\n filePath: string,\n tempGit: GitClient,\n tempDir: string\n ): Promise<FileResult> {\n try {\n const inputs = await resolveInputs({\n patch,\n filePath,\n git: this.git,\n lockManager: this.lockManager,\n outputDir: this.outputDir,\n isTreeReachable: (h) => this.isTreeReachable(h),\n resolveBaseGeneration: (s) => this.resolveBaseGeneration(s),\n resolveFilePath: (f, b, c) => this.resolveFilePath(f, b, c),\n extractRenameSource: (p, f) => this.extractRenameSource(p, f),\n extractFileDiff: (p, f) => this.extractFileDiff(p, f),\n });\n if (inputs.earlyExit) {\n return { file: filePath, ...inputs.earlyExit };\n }\n const plan = await buildMergePlan({\n inputs,\n patch,\n filePath,\n accumulator: this.accumulator,\n tempGit,\n tempDir,\n applyPatchToContent: (b, p, f, g, d, s) =>\n this.applyPatchToContent(b, p, f, g, d, s),\n isPatchAlreadyApplied: (p, f, c, g, d) =>\n this.isPatchAlreadyApplied(p, f, c, g, d),\n });\n return await runMergeAndRecord({\n plan,\n inputs,\n patch,\n accumulator: this.accumulator,\n });\n } catch (error) {\n return {\n file: filePath,\n status: \"skipped\",\n reason: `error: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n }\n\n private async isTreeReachable(treeHash: string): Promise<boolean> {\n let result = this.treeExistsCache.get(treeHash);\n if (result === undefined) {\n result = await this.git.treeExists(treeHash);\n this.treeExistsCache.set(treeHash, result);\n }\n return result;\n }\n\n private isExcluded(patch: StoredPatch): boolean {\n const config = this.lockManager.getCustomizationsConfig();\n if (!config.exclude) return false;\n\n return patch.files.some((file) => config.exclude!.some((pattern) => minimatch(file, pattern)));\n }\n\n private async resolveFilePath(filePath: string, baseTreeHash: string, currentTreeHash: string): Promise<string> {\n // Priority 1: Manual moves from replay.yml\n const config = this.lockManager.getCustomizationsConfig();\n if (config.moves) {\n for (const move of config.moves) {\n if (minimatch(filePath, move.from) || filePath === move.from) {\n // For exact matches, replace directly\n if (filePath === move.from) {\n return move.to;\n }\n // For glob matches, replace the matching prefix\n // e.g., from: \"src/api/**\" to: \"src/resources/**\"\n // filePath: \"src/api/client.ts\" → \"src/resources/client.ts\"\n const fromBase = move.from.replace(/\\*\\*.*$/, \"\");\n const toBase = move.to.replace(/\\*\\*.*$/, \"\");\n if (filePath.startsWith(fromBase)) {\n return toBase + filePath.slice(fromBase.length);\n }\n }\n }\n }\n\n // Priority 2: Git rename detection (cached per tree pair)\n const cacheKey = `${baseTreeHash}:${currentTreeHash}`;\n let renames = this.renameCache.get(cacheKey);\n if (!renames) {\n renames = await this.git.detectRenames(baseTreeHash, currentTreeHash);\n this.renameCache.set(cacheKey, renames);\n }\n\n const gitRename = renames.find((r) => r.from === filePath);\n if (gitRename) {\n return gitRename.to;\n }\n\n // Priority 3: No rename detected\n return filePath;\n }\n\n private async applyPatchToContent(\n base: string | null,\n patchContent: string,\n filePath: string,\n tempGit: GitClient,\n tempDir: string,\n sourceFilePath?: string\n ): Promise<string | null> {\n if (!base) {\n // New file - extract content directly from patch\n return this.extractNewFileFromPatch(patchContent, filePath);\n }\n\n // Extract only the diff for this specific file\n const fileDiff = this.extractFileDiff(patchContent, filePath);\n if (!fileDiff) return null;\n\n try {\n if (sourceFilePath) {\n // Rename case: write base at the OLD path, apply the rename diff,\n // then read from the NEW path (filePath).\n const tempSourcePath = join(tempDir, sourceFilePath);\n await mkdir(dirname(tempSourcePath), { recursive: true });\n await writeFile(tempSourcePath, base);\n\n await tempGit.exec([\"add\", sourceFilePath]);\n await tempGit.exec([\n \"commit\",\n \"-m\",\n `base for rename ${sourceFilePath} -> ${filePath}`,\n \"--allow-empty\"\n ]);\n\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n const tempTargetPath = join(tempDir, filePath);\n return await readFile(tempTargetPath, \"utf-8\");\n }\n\n // Normal case: write base at filePath, apply diff, read back\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, base);\n\n // Stage and commit so git apply has a clean base\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `base for ${filePath}`, \"--allow-empty\"]);\n\n // Apply this file's diff\n await tempGit.execWithInput([\"apply\", \"--allow-empty\"], fileDiff);\n\n return await readFile(tempFilePath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n /**\n * Detects whether a patch's additions are already present in `content`.\n * Uses `git apply --reverse --check` — if the reverse patch applies cleanly,\n * the forward patch is effectively a no-op (its +lines are already there and\n * its -lines are already gone). Used to distinguish \"patch already applied\"\n * from \"patch base mismatch\" after a forward-apply fails.\n */\n private async isPatchAlreadyApplied(\n patchContent: string,\n filePath: string,\n content: string,\n tempGit: GitClient,\n tempDir: string\n ): Promise<boolean> {\n const fileDiff = this.extractFileDiff(patchContent, filePath);\n if (!fileDiff) return false;\n try {\n const tempFilePath = join(tempDir, filePath);\n await mkdir(dirname(tempFilePath), { recursive: true });\n await writeFile(tempFilePath, content);\n await tempGit.exec([\"add\", filePath]);\n await tempGit.exec([\"commit\", \"-m\", `check already-applied ${filePath}`, \"--allow-empty\"]);\n await tempGit.execWithInput([\"apply\", \"--reverse\", \"--check\", \"--allow-empty\"], fileDiff);\n return true;\n } catch {\n return false;\n }\n }\n\n private extractFileDiff(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const diffLines: string[] = [];\n let inTargetFile = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) {\n // Hit the next file's diff, stop collecting\n break;\n }\n if (isDiffLineForFile(line, filePath)) {\n inTargetFile = true;\n diffLines.push(line);\n }\n continue;\n }\n\n if (inTargetFile) {\n diffLines.push(line);\n }\n }\n\n return diffLines.length > 0 ? diffLines.join(\"\\n\") + \"\\n\" : null;\n }\n\n private extractRenameSource(patchContent: string, targetFilePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n let inTargetFile = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) break; // past the target block\n inTargetFile = isDiffLineForFile(line, targetFilePath);\n continue;\n }\n if (!inTargetFile) continue;\n\n // Stop at first hunk — rename headers appear before @@\n if (line.startsWith(\"@@\")) break;\n\n if (line.startsWith(\"rename from \")) {\n return line.slice(\"rename from \".length);\n }\n }\n\n return null;\n }\n\n private extractNewFileFromPatch(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const addedLines: string[] = [];\n let inTargetFile = false;\n let inHunk = false;\n let isNewFile = false;\n let noTrailingNewline = false;\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTargetFile) break; // hit next file's diff\n inTargetFile = isDiffLineForFile(line, filePath);\n inHunk = false;\n isNewFile = false;\n continue;\n }\n if (!inTargetFile) continue;\n\n if (!inHunk) {\n if (line === \"--- /dev/null\" || line.startsWith(\"new file mode\")) {\n isNewFile = true;\n }\n }\n\n if (line.startsWith(\"@@\")) {\n if (!isNewFile) return null; // modification diff, not a new-file creation\n inHunk = true;\n continue;\n }\n if (!inHunk) continue;\n\n if (line === \"\\\\") {\n noTrailingNewline = true;\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n addedLines.push(line.slice(1));\n }\n }\n\n if (addedLines.length === 0) return null;\n return addedLines.join(\"\\n\") + (noTrailingNewline ? \"\" : \"\\n\");\n }\n}\n\n/**\n * Lines present in BOTH base and theirs (unchanged context in customer's\n * THEIRS) but absent from finalContent. Mirrors the slow-path detection in\n * ThreeWayMerge.computeDroppedContextLines so the warning surfaces\n * regardless of whether `git apply --3way` (fast path) or per-file diff3\n * (slow path) produced finalContent. Order preserved per first occurrence\n * in `base`. Multi-occurrence lines are reported as dropped when their\n * multiplicity decreased.\n */\nfunction computeDroppedContextLinesForFile(\n base: string,\n theirs: string,\n finalContent: string\n): string[] {\n const baseLines = base.split(\"\\n\");\n const theirsLines = theirs.split(\"\\n\");\n const finalLines = finalContent.split(\"\\n\");\n\n const baseCounts = new Map<string, number>();\n const theirsCounts = new Map<string, number>();\n const finalCounts = new Map<string, number>();\n\n for (const l of baseLines) baseCounts.set(l, (baseCounts.get(l) ?? 0) + 1);\n for (const l of theirsLines) theirsCounts.set(l, (theirsCounts.get(l) ?? 0) + 1);\n for (const l of finalLines) finalCounts.set(l, (finalCounts.get(l) ?? 0) + 1);\n\n const dropped: string[] = [];\n const seen = new Set<string>();\n for (const line of baseLines) {\n if (seen.has(line)) continue;\n const inBase = baseCounts.get(line) ?? 0;\n const inTheirs = theirsCounts.get(line) ?? 0;\n const inFinal = finalCounts.get(line) ?? 0;\n if (inBase > 0 && inTheirs > 0 && inFinal < Math.min(inBase, inTheirs)) {\n dropped.push(line);\n seen.add(line);\n }\n }\n return dropped;\n}\n\n/**\n * Check if a `diff --git` line targets the given file path.\n * Uses a regex anchored to the line format to avoid substring false positives\n * (e.g., `lib/foo.ts` matching `b/lib/foo.ts-backup`).\n */\nfunction isDiffLineForFile(diffLine: string, filePath: string): boolean {\n const match = diffLine.match(/^diff --git a\\/.+ b\\/(.+)$/);\n return match !== null && match[1] === filePath;\n}\n","import type { StoredPatch } from \"../types.js\";\n\nexport interface AccumulatorEntry {\n readonly content: string;\n readonly baseGeneration: string;\n}\n\n/**\n * Inter-patch THEIRS coordination across `applyPatches()`.\n *\n * When two patches modify the same file, the second patch's 3-way merge has\n * to know about the first patch's edits — otherwise it overwrites them. The\n * accumulator threads each patch's computed THEIRS by resolved file path so\n * subsequent patches can use it as a merge base / pre-merge.\n *\n * # API\n *\n * - `isShared(path)` — is this file touched by 2+ patches in this run?\n * - `has(path)` / `lookup(path)` — has any prior patch already stored a\n * result for this path? Returns the stored entry.\n * - `shouldSkipFastPath(patch)` — true if any of the patch's files have\n * prior accumulator entries; the fast path (`git apply --3way`) cannot\n * see accumulator state, so we route through the slow path.\n * - `recordMerge(path, content, baseGen)` — store a successful merge result.\n * Always populates.\n * - `recordConflict(path, content, baseGen)` — store a conflicted merge\n * result. Populates only in `\"resolve\"` mode (replay mode keeps the\n * accumulator free of marker-laden content).\n * - `snapshot()` — defensive copy for test introspection (invariant I2).\n *\n * # Mode semantics (`recordConflict`)\n *\n * Replay mode strips conflict markers off-disk after the apply loop and\n * commits clean files; the accumulator must NOT carry marker-laden content\n * forward to subsequent patches. In resolve mode the customer is going to\n * see and edit markers, so storing them lets a later patch use the\n * conflicted file as a structurally-correct merge base.\n *\n * # Lifecycle\n *\n * One accumulator instance per `applyPatches()` invocation. Constructed\n * with the run's apply mode and the precomputed set of shared files. The\n * instance is single-use — tests that want to inspect post-run state call\n * `snapshot()`, then the next `applyPatches()` constructs a fresh one.\n */\nexport class MergeAccumulator {\n private readonly entries = new Map<string, AccumulatorEntry>();\n\n constructor(\n private readonly mode: \"replay\" | \"resolve\",\n private readonly sharedFiles: ReadonlySet<string>,\n ) {}\n\n /** Was this file touched by 2+ patches in the current `applyPatches` invocation? */\n isShared(path: string): boolean {\n return this.sharedFiles.has(path);\n }\n\n /** Has any prior patch already recorded a result for this path? */\n has(path: string): boolean {\n return this.entries.has(path);\n }\n\n /** Look up the accumulated content + base generation for this path. */\n lookup(path: string): AccumulatorEntry | undefined {\n return this.entries.get(path);\n }\n\n /**\n * True if any of the patch's files have a prior accumulator entry — in\n * which case the fast path (`git apply --3way`) cannot honor prior\n * patches' contributions and we must route through the slow path.\n */\n shouldSkipFastPath(patch: StoredPatch): boolean {\n return patch.files.some((f) => this.entries.has(f));\n }\n\n /** Record a successful (clean) merge result. */\n recordMerge(path: string, content: string, baseGeneration: string): void {\n this.entries.set(path, { content, baseGeneration });\n }\n\n /**\n * Record a conflicted merge result. Populates only in `\"resolve\"` mode\n * — replay mode keeps the accumulator clean of marker-laden content\n * since markers will be stripped from disk after the apply loop.\n */\n recordConflict(path: string, content: string, baseGeneration: string): void {\n if (this.mode === \"resolve\") {\n this.entries.set(path, { content, baseGeneration });\n }\n }\n\n /**\n * Defensive copy for test introspection. Used by invariant I2 to assert\n * that after every applied patch, the accumulator has an entry for each\n * file the patch touched (see `__tests__/invariants/i2-accumulator-correctness.ts`).\n *\n * @internal\n */\n snapshot(): ReadonlyMap<string, AccumulatorEntry> {\n const copy = new Map<string, AccumulatorEntry>();\n for (const [path, entry] of this.entries) {\n copy.set(path, { content: entry.content, baseGeneration: entry.baseGeneration });\n }\n return copy;\n }\n}\n","// resolveInputs.ts — Phase 1 of the mergeFile pipeline (FER-10394).\n//\n// Owns: base-generation lookup, file-path resolution (rename detection),\n// metadata construction, BASE/OURS content fetches (with rename-source\n// fallback), and ghost-commit hybrid reconstruction when the base tree is\n// unreachable.\n//\n// Behavioral equivalence claim: for every input combination, the returned\n// `ResolvedInputs` (or `earlyExit`) carries the same values as the\n// pre-refactor `mergeFile` had at line 442 (just before the snapshot\n// decision block).\n\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { GitClient } from \"../git/GitClient.js\";\nimport type { LockfileManager } from \"../LockfileManager.js\";\nimport type { ConflictMetadata, GenerationRecord, StoredPatch } from \"../types.js\";\nimport type { ResolvedInputs } from \"./MergePlan.js\";\n\nexport interface ResolveInputsArgs {\n patch: StoredPatch;\n filePath: string;\n git: GitClient;\n lockManager: LockfileManager;\n outputDir: string;\n isTreeReachable: (treeHash: string) => Promise<boolean>;\n resolveBaseGeneration: (sha: string) => Promise<GenerationRecord | undefined>;\n resolveFilePath: (filePath: string, baseTree: string, currentTree: string) => Promise<string>;\n extractRenameSource: (patchContent: string, filePath: string) => string | null;\n extractFileDiff: (patchContent: string, filePath: string) => string | null;\n}\n\nexport async function resolveInputs(args: ResolveInputsArgs): Promise<ResolvedInputs> {\n const {\n patch,\n filePath,\n git,\n lockManager,\n outputDir,\n isTreeReachable,\n resolveBaseGeneration,\n resolveFilePath,\n extractRenameSource,\n extractFileDiff,\n } = args;\n\n const baseGen = await resolveBaseGeneration(patch.base_generation);\n if (!baseGen) {\n return {\n resolvedPath: filePath,\n metadata: {\n patchId: patch.id,\n patchMessage: patch.original_message,\n baseGeneration: patch.base_generation,\n currentGeneration: lockManager.read().current_generation,\n },\n base: null,\n ours: null,\n oursPath: join(outputDir, filePath),\n renameSourcePath: undefined,\n ghostTheirs: null,\n earlyExit: { status: \"skipped\", reason: \"base-generation-not-found\" },\n };\n }\n\n const lock = lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n const currentTreeHash = currentGen?.tree_hash ?? baseGen.tree_hash;\n const resolvedPath = await resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);\n\n const metadata: ConflictMetadata = {\n patchId: patch.id,\n patchMessage: patch.original_message,\n baseGeneration: patch.base_generation,\n currentGeneration: lock.current_generation,\n };\n\n let base = await git.showFile(baseGen.tree_hash, filePath);\n\n let renameSourcePath: string | undefined;\n if (!base) {\n const renameSource = extractRenameSource(patch.patch_content, filePath);\n if (renameSource) {\n base = await git.showFile(baseGen.tree_hash, renameSource);\n renameSourcePath = renameSource;\n }\n }\n\n const oursPath = join(outputDir, resolvedPath);\n const ours = await readFile(oursPath, \"utf-8\").catch(() => null);\n\n let ghostTheirs: string | null = null;\n\n // Ghost-commit reconstruction: when the base tree is unreachable (GC'd\n // after squash merge, shallow clone), reconstruct hybrid BASE and THEIRS\n // from the unified diff's context/removed/added lines matched against OURS.\n if (!base && ours && !renameSourcePath) {\n const treeReachable = await isTreeReachable(baseGen.tree_hash);\n if (!treeReachable) {\n const fileDiff = extractFileDiff(patch.patch_content, filePath);\n if (fileDiff) {\n const { reconstructFromGhostPatch } = await import(\"../HybridReconstruction.js\");\n const result = reconstructFromGhostPatch(fileDiff, ours);\n if (result) {\n base = result.base;\n ghostTheirs = result.theirs;\n }\n }\n }\n }\n\n return {\n resolvedPath,\n metadata,\n base,\n ours,\n oursPath,\n renameSourcePath,\n ghostTheirs,\n };\n}\n","/**\n * Strip conflict markers from file content, keeping the OURS (Generated) side.\n *\n * Two-pass parser that only recognizes replay-specific markers:\n * Opener: \"<<<<<<< Generated\"\n * Separator: \"=======\"\n * Closer: \">>>>>>> Your customization\"\n *\n * Pass 1: Scan for complete valid triplets (opener + separator + closer).\n * Nested openers abandon the current triplet.\n * Pass 2: Build output keeping OURS lines, skipping THEIRS and marker lines.\n */\n\nconst CONFLICT_OPENER = \"<<<<<<< Generated\";\nconst CONFLICT_SEPARATOR = \"=======\";\nconst CONFLICT_CLOSER = \">>>>>>> Your customization\";\n\ninterface ConflictRange {\n start: number;\n separator: number;\n end: number;\n}\n\nfunction trimCR(line: string): string {\n return line.endsWith(\"\\r\") ? line.slice(0, -1) : line;\n}\n\nfunction findConflictRanges(lines: string[]): ConflictRange[] {\n const ranges: ConflictRange[] = [];\n let i = 0;\n while (i < lines.length) {\n if (trimCR(lines[i]) === CONFLICT_OPENER) {\n let separatorIdx = -1;\n let j = i + 1;\n let found = false;\n while (j < lines.length) {\n const trimmed = trimCR(lines[j]);\n if (trimmed === CONFLICT_OPENER) {\n break; // nested opener, abandon current triplet\n }\n if (separatorIdx === -1 && trimmed === CONFLICT_SEPARATOR) {\n separatorIdx = j;\n } else if (separatorIdx !== -1 && trimmed === CONFLICT_CLOSER) {\n ranges.push({ start: i, separator: separatorIdx, end: j });\n i = j;\n found = true;\n break;\n }\n j++;\n }\n if (!found) {\n i++;\n continue;\n }\n }\n i++;\n }\n return ranges;\n}\n\nexport function stripConflictMarkers(content: string): string {\n const lines = content.split(/\\r?\\n/);\n const ranges = findConflictRanges(lines);\n\n if (ranges.length === 0) {\n return content;\n }\n\n const result: string[] = [];\n let rangeIdx = 0;\n\n for (let i = 0; i < lines.length; i++) {\n if (rangeIdx < ranges.length) {\n const range = ranges[rangeIdx];\n if (i === range.start) {\n continue;\n }\n if (i > range.start && i < range.separator) {\n result.push(lines[i]);\n continue;\n }\n if (i === range.separator) {\n continue;\n }\n if (i > range.separator && i < range.end) {\n continue;\n }\n if (i === range.end) {\n rangeIdx++;\n continue;\n }\n }\n result.push(lines[i]);\n }\n\n return result.join(\"\\n\");\n}\n\nexport function hasConflictMarkers(content: string): boolean {\n const lines = content.split(/\\r?\\n/);\n return findConflictRanges(lines).length > 0;\n}\n\n/**\n * Loose substring check: returns true if the content contains either the\n * opener or closer marker text (without verifying a complete triplet).\n *\n * Differs from `hasConflictMarkers` (which performs structural parsing of\n * complete opener+separator+closer triplets). Used at sites where the\n * presence of a marker substring — even a partial or mid-block one — is\n * a signal that something polluted the content (e.g., reconstruction\n * produced a marker-laden result, accumulator state crossed runs, etc.).\n *\n * Accepts `null` / `undefined` for ergonomic use at sites where the\n * content variable may not be set yet.\n */\nexport function hasConflictMarkerStrings(content: string | null | undefined): boolean {\n if (content == null) return false;\n return content.includes(CONFLICT_OPENER) || content.includes(CONFLICT_CLOSER);\n}\n","// buildMergePlan.ts — Phase 2 of the mergeFile pipeline (FER-10394).\n//\n// Owns: snapshot-vs-reconstruction selection, marker-rescue, stale-marker\n// detection (pre + post accumulator), accumulator-base fallback, pre-merge\n// with accumulator, baseMismatchSkipped detection, and the variant-selection\n// step that emits the discriminated `MergePlan`.\n//\n// Behavioral equivalence claim: for every input combination, the returned\n// `MergePlan` carries the same effective `theirs`, `mergeBase`,\n// `conflictReasonHint`, and (implicitly through `kind`) the same flow-control\n// decision the pre-refactor `mergeFile` would have taken into Phase 3.\n//\n// The boolean trio (`useAccumulatorAsMergeBase`, `baseMismatchSkipped`,\n// `ghostReconstructed`) is now internal to this function. Callers consume\n// only the `MergePlan` discriminant + fields.\n\nimport type { GitClient } from \"../git/GitClient.js\";\nimport { hasConflictMarkerStrings } from \"../conflict-utils.js\";\nimport { threeWayMerge } from \"../ThreeWayMerge.js\";\nimport type { ConflictReason, StoredPatch } from \"../types.js\";\nimport type { MergeAccumulator } from \"../accumulator/MergeAccumulator.js\";\nimport type { MergePlan, ResolvedInputs } from \"./MergePlan.js\";\n\nexport interface BuildMergePlanArgs {\n inputs: ResolvedInputs;\n patch: StoredPatch;\n filePath: string;\n accumulator: MergeAccumulator;\n tempGit: GitClient;\n tempDir: string;\n applyPatchToContent: (\n base: string | null,\n patchContent: string,\n filePath: string,\n tempGit: GitClient,\n tempDir: string,\n sourceFilePath?: string,\n ) => Promise<string | null>;\n isPatchAlreadyApplied: (\n patchContent: string,\n filePath: string,\n content: string,\n tempGit: GitClient,\n tempDir: string,\n ) => Promise<boolean>;\n}\n\nexport async function buildMergePlan(args: BuildMergePlanArgs): Promise<MergePlan> {\n const {\n inputs,\n patch,\n filePath,\n accumulator,\n tempGit,\n tempDir,\n applyPatchToContent,\n isPatchAlreadyApplied,\n } = args;\n const { base, ours, resolvedPath, renameSourcePath, ghostTheirs } = inputs;\n\n let theirs: string | null = ghostTheirs;\n const ghostReconstructed = ghostTheirs != null;\n\n // Snapshot-vs-reconstruction selection.\n //\n // **Snapshot-as-primary** when the patch owns its file (no other patch in\n // this run touches it): the stored `theirs_snapshot` IS the customer's\n // intent for the file post-regen. Using it directly bypasses line-anchored\n // reconstruction and survives generator structural changes that would\n // invalidate the diff's line anchors. Architectural fix for the\n // silent-loss class of bugs.\n //\n // **Reconstruction-as-primary** when the patch shares its file with\n // another patch in this run (cross-patch isolation). Snapshots from commit\n // trees are CUMULATIVE across the patches touching a shared file, so using\n // a later patch's snapshot as its individual THEIRS would propagate prior\n // patches' edits into the merge — surfacing nested conflicts at regions\n // the patch alone never touched. The line-anchored diff produces each\n // patch's INDIVIDUAL contribution, which is what the cross-patch flow\n // needs.\n //\n // For shared-file patches, snapshot is still used as a narrow\n // markers-only fallback: when reconstruction produces marker-laden\n // content (cross-patch context mismatch where the diff applies fuzzy-\n // cleanly but yields stale-base markers), snapshot rescues. The\n // pure-null-return case (strict context mismatch — patch can't apply\n // against this base at all) is left as \"skipped\" so legacy paths\n // (by-association gate, accumulator fallback) handle recovery with their\n // established UX.\n const snapshotForFile =\n patch.theirs_snapshot?.[resolvedPath] ?? patch.theirs_snapshot?.[filePath];\n const fileIsShared = accumulator.isShared(resolvedPath) || accumulator.isShared(filePath);\n const useSnapshotAsPrimary = !fileIsShared && snapshotForFile != null;\n\n // Track which path produced theirs (for the `kind` discriminant). The\n // marker-rescue case keeps \"reconstructed\" because reconstruction was the\n // primary attempt; snapshot only rescued its output.\n let primarySource: \"ghost\" | \"snapshot\" | \"reconstructed\" = ghostReconstructed\n ? \"ghost\"\n : \"reconstructed\";\n\n if (!ghostReconstructed) {\n if (useSnapshotAsPrimary) {\n // Snapshot IS THEIRS. Skip the brittle reconstruction step entirely.\n // 3-way merge below uses BASE → snapshot for \"what the customer\n // changed\", which works on content (not line anchors) and survives\n // generator structural changes.\n theirs = snapshotForFile;\n primarySource = \"snapshot\";\n } else {\n theirs = await applyPatchToContent(\n base,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir,\n renameSourcePath,\n );\n const reconstructionHasMarkers = hasConflictMarkerStrings(theirs);\n const baseHadMarkers = hasConflictMarkerStrings(base);\n if (reconstructionHasMarkers && !baseHadMarkers && snapshotForFile != null) {\n theirs = snapshotForFile;\n }\n }\n }\n\n // Detect markers that bled into THEIRS from a cross-patch context\n // mismatch: the patch's diff was authored against post-A state but we\n // tried to apply it to gen-anchor BASE. When this happens AND a prior\n // patch's accumulator entry is available with the right base_generation,\n // we want the accumulator fallback below to retry against the\n // accumulator. Treat THEIRS as null in that case so the existing fallback\n // logic fires naturally.\n //\n // Only skip outright (with `stale-conflict-markers`) when there's no\n // accumulator to fall back on — that's the original \"stale markers from\n // a crashed run\" case.\n const accumulatorEntry = accumulator.lookup(resolvedPath);\n if (theirs) {\n const theirsHasMarkers = hasConflictMarkerStrings(theirs);\n const baseHasMarkers = hasConflictMarkerStrings(base);\n if (theirsHasMarkers && !baseHasMarkers) {\n if (accumulatorEntry) {\n // Accumulator-based fallback below will try against\n // post-prior-patch state.\n theirs = null;\n } else {\n return { kind: \"skipped\", reason: \"stale-conflict-markers\" };\n }\n }\n }\n\n // Fall back to accumulator as merge base for incremental patches.\n let useAccumulatorAsMergeBase = false;\n\n if (accumulatorEntry && (theirs == null || base == null)) {\n theirs = await applyPatchToContent(\n accumulatorEntry.content,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir,\n );\n if (theirs != null) {\n useAccumulatorAsMergeBase = true;\n } else if (\n await isPatchAlreadyApplied(\n patch.patch_content,\n filePath,\n accumulatorEntry.content,\n tempGit,\n tempDir,\n )\n ) {\n // The patch's additions are already present in the accumulator.\n // This happens when preGenerationRebase's content refresh absorbs\n // a new user commit into an existing patch, and detectNewPatches\n // also creates a separate patch for that same commit. The\n // effective THEIRS is the accumulator content itself — no further\n // apply needed.\n theirs = accumulatorEntry.content;\n useAccumulatorAsMergeBase = true;\n }\n }\n\n // Re-check after accumulator fallback — git apply --3way against\n // accumulated content can also produce conflict markers.\n if (theirs) {\n const theirsHasMarkers = hasConflictMarkerStrings(theirs);\n const accBaseHasMarkers =\n accumulatorEntry != null && hasConflictMarkerStrings(accumulatorEntry.content);\n if (theirsHasMarkers && !accBaseHasMarkers && !hasConflictMarkerStrings(base)) {\n return { kind: \"skipped\", reason: \"stale-conflict-markers\" };\n }\n }\n\n // Pre-merge with accumulated customizations (skip when accumulator is\n // already serving as merge base).\n let effective_theirs = theirs;\n let conflictReasonHint: ConflictReason | undefined;\n\n if (theirs != null && base != null && !useAccumulatorAsMergeBase) {\n if (accumulatorEntry && accumulatorEntry.baseGeneration === patch.base_generation) {\n // Pre-merge: combine previous customizations with current patch.\n try {\n const preMerged = threeWayMerge(base, accumulatorEntry.content, theirs);\n if (!preMerged.hasConflicts) {\n // Clean merge — use the combined result.\n effective_theirs = preMerged.content;\n } else {\n // Pre-merge has conflicts — skip accumulator for this\n // patch to avoid nested conflict markers. User patches\n // conflict with each other and require manual resolution.\n effective_theirs = theirs;\n }\n } catch {\n // If pre-merge fails unexpectedly, fall back to current_theirs.\n effective_theirs = theirs;\n }\n } else if (accumulatorEntry) {\n // Base generations differ — accumulator pre-merge skipped. The\n // main merge below will still run, but if it conflicts we flag it\n // as a base-generation-mismatch.\n conflictReasonHint = \"base-generation-mismatch\";\n }\n }\n\n // ===== Variant selection =====\n //\n // Order mirrors the pre-refactor branch order at lines 593-708:\n // 1. new-file paths (require effective_theirs != null).\n // 2. missing-content guards.\n // 3. accumulator-base path.\n // 4. main merge against base (ghost / snapshot / reconstructed).\n\n if (base == null && ours == null && effective_theirs != null) {\n return { kind: \"new-file-only-user\", theirs: effective_theirs };\n }\n if (base == null && ours != null && effective_theirs != null && !useAccumulatorAsMergeBase) {\n return { kind: \"new-file-both\", theirs: effective_theirs };\n }\n\n if (effective_theirs == null) {\n return { kind: \"skipped\", reason: \"missing-content\" };\n }\n if ((base == null && !useAccumulatorAsMergeBase) || ours == null) {\n return { kind: \"skipped\", reason: \"missing-content\" };\n }\n\n if (useAccumulatorAsMergeBase) {\n // Invariant: useAccumulatorAsMergeBase is set only inside the\n // `if (accumulatorEntry && ...)` block above, so accumulatorEntry\n // is non-null here. The fallback to base preserves pre-refactor\n // behavior at line 645 in the unreachable case.\n const mergeBase = accumulatorEntry?.content ?? base;\n if (mergeBase == null) {\n return { kind: \"skipped\", reason: \"missing-content\" };\n }\n return {\n kind: \"accumulator-base\",\n theirs: effective_theirs,\n mergeBase,\n conflictReasonHint,\n };\n }\n\n // base and ours are both non-null at this point.\n return {\n kind: primarySource,\n base: base!,\n theirs: effective_theirs,\n mergeBase: base!,\n conflictReasonHint,\n };\n}\n","// runMergeAndRecord.ts — Phase 3 of the mergeFile pipeline (FER-10394).\n//\n// Owns: dispatching on `MergePlan.kind`, running the appropriate\n// `threeWayMerge` (for non-skipped variants), writing merged content to\n// disk, populating the accumulator (mode-aware via MergeAccumulator), and\n// classifying the resulting `FileResult`.\n//\n// Behavioral equivalence claim: for every `MergePlan` + `ResolvedInputs`\n// combination, the returned `FileResult`, the on-disk content at\n// `oursPath`, and the post-call accumulator state are byte-identical to\n// the pre-refactor `mergeFile`'s outputs at the corresponding return path.\n//\n// Two deliberately-preserved divergences in the new-file-both branch\n// (FER-10399): clean merge stores `merged.content` (not `plan.theirs`),\n// conflict path skips the accumulator entirely. Both flagged with\n// inline comments referencing FER-10399.\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { MergeAccumulator } from \"../accumulator/MergeAccumulator.js\";\nimport { threeWayMerge } from \"../ThreeWayMerge.js\";\nimport type { FileResult, StoredPatch } from \"../types.js\";\nimport type { MergePlan, ResolvedInputs } from \"./MergePlan.js\";\n\nexport interface RunMergeAndRecordArgs {\n plan: MergePlan;\n inputs: ResolvedInputs;\n patch: StoredPatch;\n accumulator: MergeAccumulator;\n}\n\nexport async function runMergeAndRecord(args: RunMergeAndRecordArgs): Promise<FileResult> {\n const { plan, inputs, patch, accumulator } = args;\n const { resolvedPath, metadata, oursPath, ours } = inputs;\n\n if (plan.kind === \"skipped\") {\n return { file: resolvedPath, status: \"skipped\", reason: plan.reason };\n }\n\n // New-file-only-user: file user-created, generator never produced it.\n // Order matters: accumulator BEFORE writeFile, so the next patch's\n // fast-path-fallback sees the entry. Pre-refactor matches.\n if (plan.kind === \"new-file-only-user\") {\n accumulator.recordMerge(resolvedPath, plan.theirs, patch.base_generation);\n await mkdir(dirname(oursPath), { recursive: true });\n await writeFile(oursPath, plan.theirs);\n return { file: resolvedPath, status: \"merged\", reason: \"new-file\" };\n }\n\n // New-file-both: file created by both generator and user. Run 3-way\n // merge against an empty BASE so the diff3 algorithm can interleave\n // the two contributions.\n if (plan.kind === \"new-file-both\") {\n // ours is non-null here by buildMergePlan's variant invariant\n // (this branch is only emitted when base==null && ours!=null).\n const merged = threeWayMerge(\"\", ours!, plan.theirs);\n await mkdir(dirname(oursPath), { recursive: true });\n await writeFile(oursPath, merged.content);\n if (merged.hasConflicts) {\n // FER-10399 preserved: no accumulator population on this path.\n // Asymmetric vs the main-merge conflict path (which calls\n // recordConflict). Tracked for triage; do not touch in\n // this refactor.\n return {\n file: resolvedPath,\n status: \"conflict\",\n conflicts: merged.conflicts,\n conflictReason: \"new-file-both\",\n conflictMetadata: metadata,\n };\n }\n // FER-10399 preserved: stores `merged.content` (with potentially\n // interleaved generator bytes), not `plan.theirs`. The\n // MergeAccumulator docstring says \"stores each patch's THEIRS\";\n // this site stores the merged result instead. Tracked for triage.\n accumulator.recordMerge(resolvedPath, merged.content, patch.base_generation);\n return { file: resolvedPath, status: \"merged\" };\n }\n\n // Main 3-way merge path: ghost / snapshot / reconstructed / accumulator-base.\n // ours is non-null here by buildMergePlan's variant invariant.\n const merged = threeWayMerge(plan.mergeBase, ours!, plan.theirs);\n await mkdir(dirname(oursPath), { recursive: true });\n await writeFile(oursPath, merged.content);\n\n // Update accumulator after merge so subsequent patches on the same file\n // have a structurally-correct THEIRS to anchor against.\n //\n // Cross-patch isolation guard: in REPLAY mode, `recordConflict` is a\n // no-op — the next iteration's intra-loop strip will reset disk to OURS,\n // and a poisoned accumulator entry could cause the next patch to see\n // false conflicts on regions it never touched.\n //\n // RESOLVE mode: `recordConflict` populates. We store `plan.theirs` (the\n // clean THEIRS, NOT `merged.content` with markers), so there's no marker\n // poisoning. A follow-up patch authored against post-this-patch\n // structure NEEDS this entry to anchor against.\n //\n // Mode dispatch lives entirely inside MergeAccumulator.recordConflict.\n if (merged.hasConflicts) {\n accumulator.recordConflict(resolvedPath, plan.theirs, patch.base_generation);\n return {\n file: resolvedPath,\n status: \"conflict\",\n conflicts: merged.conflicts,\n conflictReason: plan.conflictReasonHint ?? \"same-line-edit\",\n conflictMetadata: metadata,\n };\n }\n accumulator.recordMerge(resolvedPath, plan.theirs, patch.base_generation);\n\n return {\n file: resolvedPath,\n status: \"merged\",\n ...(merged.droppedContextLines && merged.droppedContextLines.length > 0\n ? { droppedContextLines: merged.droppedContextLines }\n : {}),\n };\n}\n","import type { GitClient } from \"./git/GitClient.js\";\nimport type { GenerationRecord, StoredPatch } from \"./types.js\";\n\nexport interface CommitOptions {\n cliVersion: string;\n generatorVersions: Record<string, string>;\n baseBranchHead?: string;\n}\n\nexport class ReplayCommitter {\n private git: GitClient;\n private outputDir: string;\n\n constructor(git: GitClient, outputDir: string) {\n this.git = git;\n this.outputDir = outputDir;\n }\n\n async commitGeneration(message: string, options?: CommitOptions): Promise<string> {\n await this.stageAll();\n\n if (!(await this.hasStagedChanges())) {\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n let fullMessage = `[fern-generated] ${message}\\n\\nGenerated by Fern`;\n\n if (options?.cliVersion) {\n fullMessage += `\\nCLI Version: ${options.cliVersion}`;\n }\n\n if (options?.generatorVersions && Object.keys(options.generatorVersions).length > 0) {\n fullMessage += \"\\nGenerators:\";\n for (const [name, version] of Object.entries(options.generatorVersions)) {\n fullMessage += `\\n - ${name}: ${version}`;\n }\n }\n\n await this.git.exec([\"commit\", \"-m\", fullMessage]);\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n async commitReplay(\n _patchCount: number,\n patches?: StoredPatch[],\n message?: string,\n options?: {\n buckets?: {\n applied: StoredPatch[];\n unresolved: StoredPatch[];\n absorbed: StoredPatch[];\n };\n }\n ): Promise<string> {\n await this.stageAll();\n\n if (!(await this.hasStagedChanges())) {\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n let fullMessage = message ?? `[fern-replay] Applied customizations`;\n\n const buckets = options?.buckets;\n if (buckets) {\n // Honest, bucketed body so the customer can tell at a glance\n // which patches truly applied, which need their attention via\n // `fern replay resolve`, and which the generator now emits\n // natively. Empty buckets are omitted.\n if (buckets.applied.length > 0) {\n fullMessage += `\\n\\nPatches applied (${buckets.applied.length}):`;\n for (const p of buckets.applied) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n }\n if (buckets.unresolved.length > 0) {\n fullMessage += `\\n\\nPatches with unresolved conflicts (${buckets.unresolved.length}):`;\n for (const p of buckets.unresolved) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n fullMessage += `\\n Run \\`fern-replay resolve\\` to apply these customizations.`;\n }\n if (buckets.absorbed.length > 0) {\n fullMessage += `\\n\\nPatches absorbed by generator (${buckets.absorbed.length}):`;\n for (const p of buckets.absorbed) {\n fullMessage += `\\n - ${p.id}: ${p.original_message}`;\n }\n fullMessage += `\\n The generator now produces these customizations natively.`;\n }\n } else if (patches && patches.length > 0) {\n // Legacy flat-list path (used by `commands/resolve.ts` after\n // hand-resolution and by tests that don't pass buckets). Every\n // patch is presumed applied at this point.\n fullMessage += \"\\n\\nPatches replayed:\";\n for (const patch of patches) {\n fullMessage += `\\n - ${patch.id}: ${patch.original_message}`;\n }\n }\n\n await this.git.exec([\"commit\", \"-m\", fullMessage]);\n return (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n }\n\n async createGenerationRecord(options?: CommitOptions): Promise<GenerationRecord> {\n const commitSha = (await this.git.exec([\"rev-parse\", \"HEAD\"])).trim();\n const treeHash = await this.getTreeHash(commitSha);\n\n return {\n commit_sha: commitSha,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: options?.cliVersion ?? \"unknown\",\n generator_versions: options?.generatorVersions ?? {},\n base_branch_head: options?.baseBranchHead\n };\n }\n\n async stageAll(): Promise<void> {\n await this.git.exec([\"add\", \"-A\", this.outputDir]);\n }\n\n async hasStagedChanges(): Promise<boolean> {\n const output = await this.git.exec([\"diff\", \"--cached\", \"--name-only\"]);\n return output.trim().length > 0;\n }\n\n async getTreeHash(commitSha: string): Promise<string> {\n return this.git.getTreeHash(commitSha);\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { readFile as readFileAsync } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { isGenerationCommit } from \"./git/CommitDetection.js\";\nimport { GitClient } from \"./git/GitClient.js\";\nimport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nimport { ReplayApplicator } from \"./ReplayApplicator.js\";\nimport { isBinaryFile } from \"./shared/binary.js\";\nimport { ReplayCommitter } from \"./ReplayCommitter.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { stripConflictMarkers } from \"./conflict-utils.js\";\nimport { computePerPatchDiffWithFallback, synthesizeNewFileDiff, unifiedDiff } from \"./PatchRegionDiff.js\";\nimport { FileOwnership } from \"./classifier/FileOwnership.js\";\nimport {\n type Flow,\n FirstGenerationFlow,\n NoPatchesFlow,\n NormalRegenerationFlow,\n SkipApplicationFlow,\n} from \"./flows/index.js\";\nimport type { FileResult, FlowKind, GenerationRecord, ReplayConfig, ReplayResult, StoredPatch } from \"./types.js\";\n\nexport interface ConflictDetail {\n patchId: string;\n patchMessage: string;\n reason?: string;\n files: FileResult[];\n /** Files that applied cleanly in a patch that also had conflicts. */\n cleanFiles?: string[];\n}\n\nexport interface UnresolvedPatchInfo {\n patchId: string;\n patchMessage: string;\n files: string[];\n conflictDetails: FileResult[];\n}\n\nexport interface ReplayReport {\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\";\n patchesDetected: number;\n patchesApplied: number;\n patchesWithConflicts: number;\n patchesSkipped: number;\n patchesAbsorbed?: number;\n patchesRepointed?: number;\n patchesContentRebased?: number;\n patchesKeptAsUserOwned?: number;\n patchesPartiallyApplied?: number;\n patchesConflictResolved?: number;\n patchesReverted?: number;\n patchesRefreshed?: number;\n conflicts: FileResult[];\n conflictDetails?: ConflictDetail[];\n /** Patches that conflicted and need local resolution via `fern-replay resolve` */\n unresolvedPatches?: UnresolvedPatchInfo[];\n wouldApply?: StoredPatch[];\n warnings?: string[];\n}\n\nexport interface ReplayOptions {\n /** Log what would happen but don't modify anything */\n dryRun?: boolean;\n /** Write files and stage changes, but don't commit */\n stageOnly?: boolean;\n /** CLI version for commit metadata */\n cliVersion?: string;\n /** Generator versions for commit metadata */\n generatorVersions?: Record<string, string>;\n /** Commit generation + update lockfile, skip detection/application */\n skipApplication?: boolean;\n /** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */\n baseBranchHead?: string;\n}\n\n/**\n * Options honored by `applyPreparedReplay()`. `cliVersion`, `generatorVersions`,\n * `baseBranchHead`, `dryRun`, and `skipApplication` were all captured in phase 1\n * and re-supplying them here is meaningless.\n */\nexport interface ApplyOptions {\n /** Write files and stage changes, but don't commit */\n stageOnly?: boolean;\n}\n\n/**\n * Opaque handle returned by `prepareReplay()`. Consumed by `applyPreparedReplay()`\n * to complete the run.\n *\n * Contract for consumers (e.g., generator-cli pipeline inserting AutoVersionStep):\n *\n * - Between `prepareReplay` and `applyPreparedReplay`, HEAD is at the new\n * `[fern-generated]` commit (unless `_prepared.kind === \"terminal\"`, e.g. dry-run).\n * - Consumers MAY land additional commits on HEAD between phases. `applyPatches`\n * runs against current HEAD at phase-2 call time, so mid-phase commits are\n * respected. `rebasePatches` uses `currentGenerationSha` (the pure `[fern-generated]`\n * SHA), NOT HEAD — mid-phase commits do not retarget patches' `base_generation`.\n * - The service instance is single-use across the phase boundary: do not call\n * other service methods (`syncFromDivergentMerge`, another `prepareReplay`, etc.)\n * between phases. In-memory lockfile and warning state would be corrupted.\n * - If the caller's mid-phase work throws or `applyPreparedReplay` is never called,\n * the repo is left with the new `[fern-generated]` commit but a stale lockfile.\n * Consumers MUST either (a) still call `applyPreparedReplay` so the lockfile\n * advances, or (b) reset HEAD to `previousGenerationSha` and surface the failure.\n *\n * To decide whether to run autoversion between phases, use:\n * prep.previousGenerationSha != null && prep.flow !== \"skip-application\"\n */\nexport interface ReplayPreparation {\n flow: FlowKind;\n /** lockfile.current_generation from BEFORE this run; null iff no prior generation exists */\n previousGenerationSha: string | null;\n /** SHA of the new [fern-generated] commit created by prepareReplay (or HEAD for dry-run terminals) */\n currentGenerationSha: string;\n /** options.baseBranchHead passed through */\n baseBranchHead: string | null;\n /** @internal Opaque state consumed by applyPreparedReplay */\n readonly _prepared: InternalPreparationState;\n}\n\n/**\n * @internal\n * Opaque state passed from `prepareReplay` to `applyPreparedReplay`.\n *\n * Discriminated by `kind`:\n * - `\"terminal\"` — phase 2 returns `preparedReport` without disk/git work\n * (dry-run, first-generation with no patch work, no-patches with no\n * detection results). Apply is a no-op.\n * - `\"active\"` — phase 2 must apply patches, rebase, save lockfile, commit.\n * Carries the patch set + cached phase-1 state.\n */\ntype InternalPreparationState = InternalPreparationTerminal | InternalPreparationActive;\n\ninterface InternalPreparationTerminal {\n readonly kind: \"terminal\";\n readonly flow: FlowKind;\n readonly preparedReport: ReplayReport;\n}\n\ninterface InternalPreparationActive {\n readonly kind: \"active\";\n readonly flow: FlowKind;\n /** post-preGenRebase, post-detection, post-absorption (references, not copies) */\n patchesToApply: StoredPatch[];\n /** subset of patchesToApply that were freshly detected this cycle (vs already in the lockfile) */\n newPatchIds: Set<string>;\n preRebaseCounts?: { conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number };\n /** detector warnings snapshotted at end of phase 1 */\n detectorWarnings: string[];\n revertedCount: number;\n /** [fern-generated] SHA; passed to rebasePatches as currentGenSha */\n genSha: string;\n /** cached phase-1 options for constructing the final ReplayReport in phase 2 */\n optionsSnapshot?: ReplayOptions;\n}\n\n/** ReplayPreparation narrowed to its active variant (terminal cases handled by dispatcher). */\ntype ActiveReplayPreparation = ReplayPreparation & { readonly _prepared: InternalPreparationActive };\n\n/**\n * Narrow `ReplayPreparation` to its active variant at the entry of each\n * Flow's `apply()`. Terminal cases are short-circuited in `applyPreparedReplay`\n * before any flow's apply method is called, so this should never fire in practice.\n *\n * @internal Used by Flow implementations in `src/flows/`.\n */\nexport function assertActive(prep: ReplayPreparation): asserts prep is ActiveReplayPreparation {\n if (prep._prepared.kind !== \"active\") {\n throw new Error(\n `Flow.apply() called with terminal preparation (kind=${prep._prepared.kind}); ` +\n `terminal cases must be handled by applyPreparedReplay's dispatcher`\n );\n }\n}\n\nexport class ReplayService {\n /** @internal Used by Flow implementations in `src/flows/`. */\n git: GitClient;\n /** @internal Used by Flow implementations in `src/flows/`. */\n detector: ReplayDetector;\n /** @internal Used by Flow implementations in `src/flows/`. */\n applicator: ReplayApplicator;\n /** @internal Used by Flow implementations in `src/flows/`. */\n committer: ReplayCommitter;\n /** @internal Used by Flow implementations in `src/flows/`. */\n lockManager: LockfileManager;\n /** @internal Used by Flow implementations in `src/flows/`. */\n fileOwnership!: FileOwnership;\n /** @internal Used by Flow implementations in `src/flows/`. */\n outputDir: string;\n /** @internal Test-only. Captures the last ReplayResult[] returned from applicator.applyPatches(). */\n _lastApplyResults: ReplayResult[] = [];\n /**\n * Service-level warnings accumulated during a single runReplay() call.\n * Merged with `detector.warnings` into `ReplayReport.warnings` by each flow handler.\n * Populated by `FileOwnership.resolveCanonical` when a patch's base generation tree\n * is unreachable (shallow clone / aggressive `git gc --prune`) and we fall back to a\n * conservative heuristic. Cleared at the top of `runReplay()`.\n *\n * @internal Used by Flow implementations in `src/flows/`.\n */\n warnings: string[] = [];\n\n /**\n * @internal Test-only accessor.\n * Returns the ReplayApplicator instance used for the last run. Tests use this\n * to inspect the inter-patch accumulator after runReplay() completes (invariant I2).\n */\n get applicatorRef(): ReplayApplicator {\n return this.applicator;\n }\n\n /**\n * @internal Test-only accessor.\n * Returns the ReplayResult[] from the most recent applyPatches() call. Tests use\n * this to filter applied-vs-conflicted-vs-absorbed patches for invariant\n * assertions. Returns an empty array if no patches have been applied yet.\n */\n getLastResults(): ReadonlyArray<ReplayResult> {\n return this._lastApplyResults;\n }\n\n constructor(outputDir: string, _config: ReplayConfig) {\n const git = new GitClient(outputDir);\n this.git = git;\n this.outputDir = outputDir;\n this.lockManager = new LockfileManager(outputDir);\n this.detector = new ReplayDetector(git, this.lockManager, outputDir);\n this.applicator = new ReplayApplicator(git, this.lockManager, outputDir);\n this.committer = new ReplayCommitter(git, outputDir);\n this.fileOwnership = new FileOwnership(git);\n }\n\n /**\n * Phase 1 of the two-phase replay flow. Runs preGenerationRebase (when applicable),\n * detects new patches, and creates the `[fern-generated]` commit. Leaves HEAD at\n * the generation commit (or unchanged for dry-run).\n *\n * Does NOT apply patches — the returned handle must be passed to\n * `applyPreparedReplay()` to complete the run. No disk writes to the lockfile\n * happen here; lockfile persistence is deferred to phase 2.\n *\n * Callers may land additional commits on HEAD between `prepareReplay` and\n * `applyPreparedReplay` (e.g., `[fern-autoversion]`).\n */\n async prepareReplay(options?: ReplayOptions): Promise<ReplayPreparation> {\n // Reset per-run state so warnings from prior invocations don't leak.\n // Both the service-level and detector-level warnings must be cleared —\n // the two-phase API (`prepareReplay` + `applyPreparedReplay`) enlarges\n // the observability window for callers like generator-cli's autoversion\n // step, so we tighten the per-call cleanup here.\n this.warnings = [];\n this.detector.warnings.length = 0;\n return this.selectFlow(options).prepare(options);\n }\n\n /**\n * Phase 2 of the two-phase replay flow. Applies patches, rebases them against\n * the generation, saves the lockfile, and commits `[fern-replay]` (or stages\n * under `stageOnly`). Operates on HEAD at call time — mid-phase commits are\n * respected.\n *\n * For terminal handles (dry-run, first-gen has no patch work, skip-app does\n * its own post-commit logic), this returns the precomputed report.\n */\n async applyPreparedReplay(\n prep: ReplayPreparation,\n options?: ApplyOptions\n ): Promise<ReplayReport> {\n if (prep._prepared.kind === \"terminal\") {\n // Dry-run path: report was fully built in phase 1 and no disk/git work\n // is needed in phase 2.\n return prep._prepared.preparedReport;\n }\n return this.flowForKind(prep._prepared.flow).apply(prep, options);\n }\n\n /**\n * Construct the flow for the current run. `selectFlow` is called from\n * `prepareReplay` and decides based on options + lockfile state.\n */\n private selectFlow(options?: ReplayOptions): Flow {\n if (options?.skipApplication) return new SkipApplicationFlow(this);\n return this.flowForKind(this.determineFlow());\n }\n\n /**\n * Construct a flow given its kind. Used by `applyPreparedReplay` to\n * route to the same kind that was selected in phase 1.\n */\n private flowForKind(kind: FlowKind): Flow {\n switch (kind) {\n case \"first-generation\":\n return new FirstGenerationFlow(this);\n case \"no-patches\":\n return new NoPatchesFlow(this);\n case \"normal-regeneration\":\n return new NormalRegenerationFlow(this);\n case \"skip-application\":\n return new SkipApplicationFlow(this);\n }\n }\n\n /**\n * Backwards-compatible atomic entry point. Composes `prepareReplay` + `applyPreparedReplay`.\n * Behavior is byte-identical to the pre-split implementation for all existing callers.\n */\n async runReplay(options?: ReplayOptions): Promise<ReplayReport> {\n const prep = await this.prepareReplay(options);\n return this.applyPreparedReplay(prep, options);\n }\n\n /**\n * Sync the lockfile after a divergent PR was squash-merged.\n * Call this BEFORE runReplay() when the CLI detects a merged divergent PR.\n *\n * After updating the generation record, re-detects customer patches via\n * tree diff between the generation tag (pure generation tree) and HEAD\n * (which includes customer customizations after squash merge). This ensures\n * patches survive the squash merge → regenerate cycle even when the lockfile\n * was restored from the base branch during conflict PR creation.\n */\n async syncFromDivergentMerge(\n generationCommitSha: string,\n options?: { cliVersion?: string; generatorVersions?: Record<string, string>; baseBranchHead?: string }\n ): Promise<void> {\n const treeHash = await this.git.getTreeHash(generationCommitSha);\n const timestamp = (await this.git.exec([\"log\", \"-1\", \"--format=%aI\", generationCommitSha])).trim();\n\n const record: GenerationRecord = {\n commit_sha: generationCommitSha,\n tree_hash: treeHash,\n timestamp,\n cli_version: options?.cliVersion ?? \"unknown\",\n generator_versions: options?.generatorVersions ?? {},\n base_branch_head: options?.baseBranchHead\n };\n\n let resolvedPatches: StoredPatch[] | undefined;\n\n if (!this.lockManager.exists()) {\n this.lockManager.initializeInMemory(record);\n } else {\n this.lockManager.read();\n // Preserve unresolved patches — they represent conflicts that the\n // customer hasn't resolved yet. Since we strip conflict markers from\n // committed files, these patches won't appear in the tree diff.\n const unresolvedPatches = [\n ...this.lockManager.getUnresolvedPatches(),\n ...this.lockManager.getResolvingPatches(),\n ];\n // Snapshot resolved patches before clearing — if re-detection\n // fails, we restore them to prevent silent data loss.\n resolvedPatches = this.lockManager.getPatches().filter(p => p.status == null);\n this.lockManager.addGeneration(record);\n this.lockManager.clearPatches();\n\n // Re-add unresolved patches so they carry through the squash merge.\n for (const patch of unresolvedPatches) {\n this.lockManager.addPatch(patch);\n }\n }\n\n // Re-detect customer patches via tree diff. The generation tag has the\n // pure generation tree, so any differences between it and HEAD represent\n // customer customizations that survived the squash merge.\n try {\n const { patches: redetectedPatches } = await this.detector.detectNewPatches();\n if (redetectedPatches.length > 0) {\n // Remove preserved unresolved patches that overlap with\n // re-detected ones (customer resolved them before merging).\n const redetectedFiles = new Set(redetectedPatches.flatMap((p) => p.files));\n const currentPatches = this.lockManager.getPatches();\n for (const patch of currentPatches) {\n if (patch.status != null && patch.files.some((f) => redetectedFiles.has(f))) {\n this.lockManager.removePatch(patch.id);\n }\n }\n\n for (const patch of redetectedPatches) {\n this.lockManager.addPatch(patch);\n }\n }\n } catch (error) {\n // Re-detection failed — restore resolved patches so they aren't\n // permanently lost. The normal replay flow will still attempt detection.\n for (const patch of resolvedPatches ?? []) {\n this.lockManager.addPatch(patch);\n }\n this.detector.warnings.push(\n `Patch re-detection failed after divergent merge sync. ` +\n `${(resolvedPatches ?? []).length} previously resolved patch(es) preserved. ` +\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n this.lockManager.save();\n this.detector.warnings.push(...this.lockManager.warnings);\n }\n\n private determineFlow(): \"first-generation\" | \"no-patches\" | \"normal-regeneration\" {\n try {\n const lock = this.lockManager.read();\n return lock.patches.length === 0 ? \"no-patches\" : \"normal-regeneration\";\n } catch (error) {\n if (error instanceof LockfileNotFoundError) {\n return \"first-generation\";\n }\n throw error;\n }\n }\n\n /**\n * Rebase cleanly applied patches so they are relative to the current generation.\n * This prevents recurring conflicts on subsequent regenerations.\n * Returns the number of patches rebased.\n *\n * @internal Used by Flow implementations in `src/flows/`.\n */\n async rebasePatches(\n results: ReplayResult[],\n currentGenSha: string\n ): Promise<{\n absorbed: number;\n repointed: number;\n contentRebased: number;\n keptAsUserOwned: number;\n absorbedPatchIds: Set<string>;\n }> {\n let absorbed = 0;\n let repointed = 0;\n let contentRebased = 0;\n let keptAsUserOwned = 0;\n // Track content hashes seen this rebase cycle. When two patches end\n // up with byte-identical post-rebase patch_content, they encode the\n // SAME customer-side delta — applying both back-to-back would corrupt\n // the file via duplicate-apply. Consolidate to one (the first seen)\n // and remove the rest. Per-commit attribution is recoverable from\n // `git log`. Map value is the surviving patch's id, used in the\n // consolidation warning.\n const seenContentHashes = new Map<string, string>();\n const absorbedPatchIds = new Set<string>();\n // Cache once — used per patch below to classify protected vs non-protected files.\n const fernignorePatterns = this.readFernignorePatterns();\n // `resolveCanonical` may push a one-time unreachable-base warning per\n // base SHA when `patch.base_generation` is GC'd. Sharing one set across\n // every patch in this rebase keeps the warning to one line per affected\n // base, not one per file.\n const warnedGens = new Set<string>();\n\n // Pre-pass: Update patch.files with resolved (renamed) paths from application.\n // This ensures downstream operations (user-owned check, git diff, git show)\n // use the current file paths rather than stale pre-rename paths.\n for (const result of results) {\n if (result.resolvedFiles && Object.keys(result.resolvedFiles).length > 0) {\n const patch = result.patch;\n const updatedFiles = patch.files.map((f) => result.resolvedFiles![f] ?? f);\n patch.files = updatedFiles;\n try {\n this.lockManager.updatePatch(patch.id, { files: updatedFiles });\n } catch {\n // New patches aren't in lockfile yet — in-memory update sufficient\n }\n }\n }\n\n // Build set of file paths that any earlier patch CONFLICTED on in this\n // run. The absorption branch below uses this to detect a clean follow-up\n // patch whose disk state was reset to OURS by revertConflictingFiles or\n // applyPatches' cross-patch marker stripping (ReplayApplicator.ts:157-189).\n // Such a patch shows an empty diff vs currentGen and would otherwise be\n // silently absorbed — masking a real customization. Preserve as\n // unresolved instead so the customer can recover via `fern replay resolve`.\n const conflictedFilePaths = new Set<string>();\n for (const r of results) {\n if (r.status !== \"conflict\") continue;\n if (r.fileResults) {\n for (const fr of r.fileResults) {\n if (fr.status !== \"conflict\") continue;\n conflictedFilePaths.add(fr.file);\n if (r.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(r.resolvedFiles)) {\n if (resolved === fr.file) conflictedFilePaths.add(orig);\n }\n }\n }\n } else {\n // Defensive: a conflict result without fileResults isn't produced\n // by the current applicator, but if a future change introduces\n // one, fall back to patch.files so we don't silently regress.\n for (const f of r.patch.files) conflictedFilePaths.add(f);\n }\n }\n\n for (const result of results) {\n if (result.status === \"conflict\" && result.fileResults) {\n // For conflict patches with mixed results, trim any clean files\n // that were absorbed by the generator. This prevents absorbed files\n // from poisoning the pre-generation rebase conflict marker check.\n await this.trimAbsorbedFiles(result, currentGenSha);\n continue;\n }\n\n // Only rebase cleanly applied patches.\n // Conflicted patches keep their old base_generation so they retry.\n if (result.status !== \"applied\") continue;\n\n const patch = result.patch;\n\n // Skip if already based on the current generation\n if (patch.base_generation === currentGenSha) continue;\n\n try {\n // Classify file ownership via the single canonical resolver.\n // Widens \"protected = .fernignore only\" to every user-owned\n // file: persisted `user_owned` flag, `.fernignore` patterns,\n // patch_content `--- /dev/null` creation signal, and a tree\n // lookup against `patch.base_generation` (with a fall-back to\n // `currentGenSha` for legacy one-gen lockfiles). This keeps\n // user-created files in mixed composites from being absorbed\n // alongside the generator-modified half.\n const originalByResolved: Record<string, string> = {};\n if (result.resolvedFiles) {\n for (const [orig, resolved] of Object.entries(result.resolvedFiles)) {\n originalByResolved[resolved] = orig;\n }\n }\n const isUserOwnedPerFile = await Promise.all(\n patch.files.map((file) =>\n this.fileOwnership.resolveCanonical({\n file,\n originalFileName: originalByResolved[file],\n patch,\n currentGenSha,\n fernignorePatterns,\n warnedGens,\n warnings: this.warnings,\n })\n )\n );\n // Match main's \"protected\" semantics for the compact subset:\n // .fernignore itself OR fernignore-pattern-matched files. These\n // must never be absorbed even on empty diff.\n const hasProtectedFiles = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n // The \"keep\" branch fires only when EVERY file in the patch\n // is user-owned. Mixed composite patches (user + gen files,\n // e.g. from tree-diff fallback) still flow through the\n // absorption/rebase branch below so the gen-file halves get\n // content-rebased; this also avoids regressing the long-horizon\n // accumulator invariants on mixed-ownership composites.\n const allUserOwned = isUserOwnedPerFile.every(Boolean);\n\n if (allUserOwned && patch.files.length > 0) {\n const baseChanged = patch.base_generation !== currentGenSha;\n\n // Rebase content hash against current generation so both the\n // no-patches and normal-regeneration flows produce identical\n // hashes for user-owned patches. preGenerationRebase (normal\n // flow) converts patch_content to `git diff currentGen HEAD`\n // and recomputes the hash. Without this, the no-patches flow\n // keeps the original formatPatch hash, which differs because\n // the diff base and format are both different.\n const userDiff = await this.git\n .exec([\"diff\", currentGenSha, \"--\", ...patch.files])\n .catch(() => null);\n let userDiffSnapshot: Record<string, string> | null = null;\n if (userDiff != null && userDiff.trim()) {\n const newHash = this.detector.computeContentHash(userDiff);\n patch.patch_content = userDiff;\n patch.content_hash = newHash;\n // rebasePatches only operates on `status === \"applied\"`\n // patches (clean merges). Working tree is the correctly\n // merged customer state at the new generation —\n // including any path renames carried by `patch.files`.\n // Snapshot capture here is what keeps snapshot keys\n // aligned with current paths across regen cycles\n // (W5 rename-churn relies on this).\n const snap = await this.readSnapshotFromDisk(patch.files);\n if (Object.keys(snap).length > 0) {\n userDiffSnapshot = snap;\n patch.theirs_snapshot = snap;\n }\n }\n\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n ...(!patch.user_owned ? { user_owned: true } : {}),\n ...(userDiff != null && userDiff.trim()\n ? {\n patch_content: patch.patch_content,\n content_hash: patch.content_hash,\n ...(userDiffSnapshot != null && Object.keys(userDiffSnapshot).length > 0\n ? { theirs_snapshot: userDiffSnapshot }\n : {})\n }\n : {})\n });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n patch.user_owned = true;\n keptAsUserOwned++;\n // Count as repointed when base advanced — tests track this.\n if (baseChanged) repointed++;\n continue;\n }\n\n // Mixed or generator-only patch — compute diff vs currentGen\n // for absorption/rebase decisions.\n //\n // Note: rebasePatches uses the cumulative diff here (matching\n // preGenerationRebase's behavior). The content-hash dedup at\n // line ~1140 below preserves patches with distinct\n // `original_commit`s when their rebased content_hash\n // converges. Per-patch surgical scoping in this hot path\n // interacts badly with bundled user-owned files (file already\n // in currentGen due to commitGeneration), causing false\n // absorption — kept cumulative here for safety. The\n // customer-facing per-patch-region fix lives in\n // `commands/resolve.ts`.\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", ...patch.files]).catch(() => null);\n\n if (diff === null) continue;\n\n if (!diff.trim()) {\n if (hasProtectedFiles) {\n // Protected files — never absorb. Advance base_generation only.\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGenSha });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n keptAsUserOwned++;\n continue;\n }\n // Conflict-by-association guard: do not absorb if a predecessor\n // in this run conflicted on any of this patch's files. Empty\n // diff is suspicious here — disk was reset to OURS by marker\n // stripping, masking a real customization. Preserve as\n // unresolved so `fern replay resolve` can recover it.\n const overlapsConflicted = patch.files.some((f) => conflictedFilePaths.has(f));\n if (overlapsConflicted) {\n patch.status = \"unresolved\";\n try {\n this.lockManager.updatePatch(patch.id, { status: \"unresolved\" });\n } catch {\n // New patch — addPatch() in the caller carries the\n // in-memory status through into the lockfile.\n }\n this.warnings.push(\n `Patch ${patch.id} (${patch.original_message}) was preserved as unresolved ` +\n `because an earlier patch conflicted on the same file(s) (${patch.files.join(\", \")}). ` +\n `Run \\`fern replay resolve\\` to apply this customization manually.`\n );\n continue;\n }\n // Generator file with empty net effect — absorb.\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n\n if (hasProtectedFiles) {\n // Protected files with a real diff: keep patch_content as-is.\n // Only advance base_generation.\n patch.base_generation = currentGenSha;\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGenSha });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n keptAsUserOwned++;\n continue;\n }\n\n // Generator files OR mixed patches with some user-owned files:\n // rebase patch_content to the canonical git-diff against new\n // generation.\n const newContentHash = this.detector.computeContentHash(diff);\n\n // Consolidate when another patch already captured this exact\n // diff. Two patches with byte-identical post-rebase\n // patch_content encode the SAME customer-side delta — applying\n // both back-to-back at the next regen produces duplicate-apply\n // corruption (the same lines spliced in twice). Consolidate\n // to one canonical patch; per-commit attribution is recoverable\n // from `git log -- <file>`. See preGenerationRebase for the\n // full rationale.\n const priorPatchId = seenContentHashes.get(newContentHash);\n if (priorPatchId !== undefined) {\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n if (priorPatchId !== patch.id) {\n this.warnings.push(\n `Consolidated patch ${patch.id} (commit ${(patch.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into prior patch ${priorPatchId}: byte-identical patch_content after rebase. ` +\n `Per-commit attribution preserved in git log.`\n );\n }\n continue;\n } else {\n seenContentHashes.set(newContentHash, patch.id);\n }\n\n // Mutate in-memory AND lockfile. For new patches (not yet added to\n // the lockfile), updatePatch throws; the in-memory mutation ensures\n // the correct values end up persisted when addPatch runs later.\n patch.base_generation = currentGenSha;\n patch.patch_content = diff;\n patch.content_hash = newContentHash;\n // Snapshot from working tree. Same rationale as the\n // user-owned branch above: only fires for cleanly-applied\n // patches (`status === \"applied\"` filter at the top of\n // the loop), so disk = correctly-merged customer state at\n // the new generation. Captures rename keys for next regen.\n const snapshot = await this.readSnapshotFromDisk(patch.files);\n const snapshotIsNonEmpty = Object.keys(snapshot).length > 0;\n if (snapshotIsNonEmpty) {\n patch.theirs_snapshot = snapshot;\n }\n try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash,\n ...(snapshotIsNonEmpty ? { theirs_snapshot: snapshot } : {})\n });\n } catch {\n // Not in lockfile yet — in-memory mutation is sufficient.\n }\n contentRebased++;\n } catch {\n // If rebasing fails for any reason, keep the original patch unchanged\n }\n }\n\n return { absorbed, repointed, contentRebased, keptAsUserOwned, absorbedPatchIds };\n }\n\n /**\n * Read THEIRS snapshot (post-customer-edit content) for a list of files\n * from the working tree on disk. Used by `rebasePatches` after a clean\n * apply — disk = correctly-merged customer state at the new generation.\n * Skips binary files (matches `mergeFile`/`populateAccumulatorForPatch`\n * policy — binary content as `utf-8` is lossy and snapshots of it would\n * never be used during apply anyway).\n */\n private async readSnapshotFromDisk(files: string[]): Promise<Record<string, string>> {\n const snapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n try {\n const content = await readFileAsync(join(this.outputDir, file), \"utf-8\");\n snapshot[file] = content;\n } catch {\n // Missing file — omit (the file might have been deleted by the customer).\n }\n }\n return snapshot;\n }\n\n /**\n * Detects autoversion contamination — returns true when a\n * `[fern-autoversion]` commit between `fromSha` and `toSha` touched any\n * of the patch's `files`. Re-classifies each grep match via\n * `isGenerationCommit` so a customer commit that merely quotes the\n * marker in its body doesn't false-positive.\n *\n * Used by preGenerationRebase to skip the customer-content rebuild for\n * patches whose files were last touched by an autoversion step — a\n * naive `git diff currentGen HEAD` there would capture the\n * placeholder→semver swap as customer customization.\n */\n private async hasAutoversionContamination(\n fromSha: string,\n toSha: string,\n files: string[],\n ): Promise<boolean> {\n if (files.length === 0) return false;\n const log = await this.git\n .exec([\n \"log\",\n `${fromSha}..${toSha}`,\n \"--grep=\\\\[fern-autoversion\\\\]\",\n \"--extended-regexp\",\n \"--format=%H%x09%aN%x09%ae%x09%s\",\n \"--\",\n ...files,\n ])\n .catch(() => \"\");\n if (!log.trim()) return false;\n for (const line of log.trim().split(\"\\n\")) {\n const [sha, authorName, authorEmail, message] = line.split(\"\\t\");\n if (sha == null) continue;\n if (\n isGenerationCommit({\n sha,\n authorName: authorName ?? \"\",\n authorEmail: authorEmail ?? \"\",\n message: message ?? \"\",\n })\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Rebuild patch_content from `theirs_snapshot` (captured at detection\n * time, predates pipeline content) rather than a HEAD-relative diff.\n * Returns `null` when snapshot is missing or doesn't cover every file\n * in `patch.files` — caller leaves the patch unchanged.\n *\n * Used as the autoversion-contamination escape hatch: when the\n * HEAD-relative diff would capture pipeline content (autoversion's\n * placeholder swap) as customer customization, the snapshot path\n * preserves the customer's actual intent.\n */\n private async computeSnapshotBasedPatchDiff(\n patch: StoredPatch,\n currentGen: string,\n ): Promise<string | null> {\n if (!patch.theirs_snapshot) return null;\n if (Object.keys(patch.theirs_snapshot).length === 0) return null;\n for (const file of patch.files) {\n if (patch.theirs_snapshot[file] == null) return null;\n }\n\n const fragments: string[] = [];\n for (const file of patch.files) {\n const theirsContent = patch.theirs_snapshot[file]!;\n const oursContent = await this.git.showFile(currentGen, file).catch(() => null);\n if (oursContent == null) {\n fragments.push(synthesizeNewFileDiff(file, theirsContent));\n continue;\n }\n if (oursContent === theirsContent) continue;\n const fileDiff = await unifiedDiff(oursContent, theirsContent, file);\n if (fileDiff.trim()) {\n fragments.push(fileDiff);\n }\n }\n return fragments.join(\"\");\n }\n\n /**\n * Read THEIRS snapshot from a git tree-ish (commit, branch, or tree).\n * Used when the diff that produced `patch_content` was relative to that\n * tree (e.g., `git diff currentGen HEAD --` → snapshot from HEAD).\n * Skips binary files.\n */\n private async readSnapshotFromTree(treeRef: string, files: string[]): Promise<Record<string, string>> {\n const snapshot: Record<string, string> = {};\n for (const file of files) {\n if (isBinaryFile(file)) continue;\n const content = await this.git.showFile(treeRef, file).catch(() => null);\n if (content != null) snapshot[file] = content;\n }\n return snapshot;\n }\n\n /**\n * One-shot auto-migration: backfill `theirs_snapshot` on existing\n * patches that predate the snapshot encoding. Computes the snapshot by\n * applying the patch's `patch_content` to its `base_generation` tree —\n * yielding the patch's INDIVIDUAL contribution.\n *\n * **Skips patches sharing files with other patches.** HEAD's content\n * for a file shared by N patches is cumulative across all of them, so\n * a HEAD-fallback would falsely encode other patches' contributions\n * into one patch's snapshot — breaking cross-patch isolation\n * if the snapshot fallback later fires. Per-patch snapshots only\n * make sense when the patch owns its file. Multi-patch-same-file\n * legacy lockfiles keep using line-anchored reconstruction (the\n * existing path); they're no worse than pre-upgrade.\n *\n * **Does not fall back to HEAD when BASE-reconstruction fails.** Same\n * reason — HEAD content can be cumulative. Patches whose\n * reconstruction fails just don't get a snapshot; legacy paths\n * (PR #73's by-association gate, accumulator fallback) handle them.\n *\n * Skips patches that already have a snapshot.\n */\n private async migratePatchesToSnapshot(patches: StoredPatch[]): Promise<void> {\n const { applyPatchToContent } = await import(\"./PatchApplyTheirs.js\");\n // Identify files that appear in MULTIPLE patches in the lockfile.\n const fileFreq = new Map<string, number>();\n for (const p of patches) {\n for (const f of p.files) {\n fileFreq.set(f, (fileFreq.get(f) ?? 0) + 1);\n }\n }\n let migrated = 0;\n let skipped = 0;\n for (const patch of patches) {\n if (patch.theirs_snapshot != null) continue;\n const sharesAnyFile = patch.files.some((f) => (fileFreq.get(f) ?? 0) > 1);\n if (sharesAnyFile) {\n skipped++;\n continue;\n }\n const snapshot: Record<string, string> = {};\n for (const file of patch.files) {\n if (isBinaryFile(file)) continue;\n try {\n const base = await this.git.showFile(patch.base_generation, file).catch(() => null);\n if (base != null) {\n const content = await applyPatchToContent(base, patch.patch_content, file);\n if (content != null) snapshot[file] = content;\n }\n } catch {\n // Reconstruction failed — leave this file out of the snapshot.\n }\n }\n // Only persist when at least one file's snapshot was computed.\n // Empty snapshots provide no value and would suppress retries.\n if (Object.keys(snapshot).length > 0) {\n patch.theirs_snapshot = snapshot;\n try {\n this.lockManager.updatePatch(patch.id, { theirs_snapshot: snapshot });\n migrated++;\n } catch {\n // Patch not in lockfile yet (shouldn't happen here, but be defensive).\n }\n }\n }\n if (migrated > 0) {\n this.warnings.push(\n `Migrated ${migrated} patch(es) to snapshot encoding. Future regens use 3-way merge ` +\n `with stored THEIRS, robust to generator structural changes.`\n );\n }\n if (skipped > 0) {\n this.warnings.push(\n `Skipped snapshot migration for ${skipped} patch(es) sharing files with other patches. ` +\n `These continue to use line-anchored reconstruction (the existing path).`\n );\n }\n }\n\n /**\n * For conflict patches with mixed results (some files merged, some conflicted),\n * check if the cleanly merged files were absorbed by the generator (empty diff).\n * If so, remove them from patch.files so they don't pollute the pre-generation\n * rebase conflict marker check (`git grep <<<<<<< -- ...patch.files`).\n *\n * Non-absorbed clean files stay in patch.files — removing them would lose\n * the customization on the next generation.\n */\n private async trimAbsorbedFiles(result: ReplayResult, currentGenSha: string): Promise<void> {\n const cleanFiles = result.fileResults!.filter((f) => f.status === \"merged\").map((f) => f.file);\n if (cleanFiles.length === 0) return;\n\n const patch = result.patch;\n // If the entire patch is persisted as user-owned, nothing is ever a\n // generator-clean candidate for trimming — short-circuit.\n if (patch.user_owned) return;\n\n const fernignorePatterns = this.readFernignorePatterns();\n const warnedGens = new Set<string>();\n\n // Filter to only generator-produced clean files (not user-owned)\n const generatorCleanFiles: string[] = [];\n for (const file of cleanFiles) {\n const userOwned = await this.fileOwnership.resolveCanonical({\n file,\n patch,\n currentGenSha,\n fernignorePatterns,\n warnedGens,\n warnings: this.warnings,\n });\n if (userOwned) {\n continue; // user-owned file — never a candidate for absorption trimming\n }\n generatorCleanFiles.push(file);\n }\n if (generatorCleanFiles.length === 0) return;\n\n // Check which clean files have an empty diff (absorbed by generator)\n const absorbedFiles = new Set<string>();\n for (const file of generatorCleanFiles) {\n try {\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", file]).catch(() => null);\n if (!diff || !diff.trim()) {\n absorbedFiles.add(file);\n }\n } catch {\n // If diff fails, leave the file in the patch\n }\n }\n if (absorbedFiles.size === 0) return;\n\n // Remove absorbed files from the patch's file list\n const remainingFiles = patch.files.filter((f) => !absorbedFiles.has(f));\n if (remainingFiles.length === patch.files.length) return; // nothing changed\n\n try {\n this.lockManager.updatePatch(patch.id, { files: remainingFiles });\n } catch {\n // New patches aren't in lockfile yet — update in-memory only\n patch.files = remainingFiles;\n }\n }\n\n /**\n * Pre-generation rebase: update patches using the customer's current state.\n * Called BEFORE commitGeneration() while HEAD has customer code.\n */\n /** @internal Used by Flow implementations in `src/flows/`. */\n async preGenerationRebase(\n patches: StoredPatch[]\n ): Promise<{ conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number }> {\n const lock = this.lockManager.read();\n const currentGen = lock.current_generation;\n\n // If the previous run was skip-application, clear the marker and\n // skip all revert detection. Patches are preserved as-is.\n if (this.lockManager.isReplaySkipped()) {\n this.lockManager.clearReplaySkippedAt();\n return { conflictResolved: 0, conflictAbsorbed: 0, contentRefreshed: 0 };\n }\n\n // Auto-migrate legacy patches lacking `theirs_snapshot` to the new\n // encoding. One-shot per existing patch — once migrated, future\n // regens use the snapshot path. Compute snapshot from BASE +\n // patch_content (same logic the slow apply path uses today and\n // already trusts). Falls back to HEAD content if BASE is GC'd.\n await this.migratePatchesToSnapshot(patches);\n\n // Detect whether HEAD is a [fern-generated] commit AND it changed\n // *source* files (vs HEAD~1) — the discriminator for the\n // \"manually-staged-generation-at-HEAD\" bug case where `git diff\n // currentGen HEAD -- file` would produce generator-vs-generator\n // content (not customer intent) and corrupt patch_content/snapshot.\n //\n // Test helpers and infrastructure commits (e.g.,\n // `[fern-generated] store patches` that only touches .fern/) are\n // also generation commits but DON'T change source — they're safe\n // to content-refresh against. The HEAD~1 source-diff check\n // distinguishes these: the bug case mutates a source file vs its\n // parent (customer's last code → generator output), while infra\n // commits don't.\n //\n // Per-patch evaluation happens below — this just precomputes the\n // generation-author signal.\n const headMessage = await this.git.exec([\"log\", \"-1\", \"--format=%s%n%aN%n%ae\", \"HEAD\"]).catch(() => \"\");\n const [headMsgLine, headAuthorName, headAuthorEmail] = headMessage.split(\"\\n\");\n const headIsGeneration = headMsgLine\n ? isGenerationCommit({\n sha: \"HEAD\",\n authorName: headAuthorName ?? \"\",\n authorEmail: headAuthorEmail ?? \"\",\n message: headMsgLine\n })\n : false;\n const headParentChangedFiles = async (patchFiles: string[]): Promise<Set<string>> => {\n if (patchFiles.length === 0) return new Set();\n const diff = await this.git\n .exec([\"diff\", \"--name-only\", \"HEAD~1\", \"HEAD\", \"--\", ...patchFiles])\n .catch(() => \"\");\n return new Set(diff.trim().split(\"\\n\").filter(Boolean));\n };\n\n let conflictResolved = 0;\n let conflictAbsorbed = 0;\n let contentRefreshed = 0;\n const fernignorePatterns = this.readFernignorePatterns();\n const warnedGens = new Set<string>();\n // Cache reachability checks per-SHA to avoid repeating commitExists/treeExists\n // git subprocess calls for the same base across many patches (N patches ×\n // 2 calls is the main per-cycle cost in long-horizon scenarios like W11).\n const reachabilityCache = new Map<string, boolean>();\n const isReachable = async (sha: string): Promise<boolean> => {\n const cached = reachabilityCache.get(sha);\n if (cached !== undefined) return cached;\n const reachable =\n (await this.git.commitExists(sha)) || (await this.git.treeExists(sha));\n reachabilityCache.set(sha, reachable);\n return reachable;\n };\n\n // A patch whose every file is user-owned produces an empty diff\n // between currentGen and HEAD (because commitGeneration bundled the file\n // into currentGen — both sides are identical). That empty diff is NOT a\n // revert signal. Only patches with at least one generator-produced file\n // can have their emptiness legitimately interpreted as \"user reverted.\"\n const allPatchFilesUserOwned = async (patch: StoredPatch): Promise<boolean> => {\n if (patch.user_owned) return true;\n if (patch.files.length === 0) return false;\n for (const file of patch.files) {\n const userOwned = await this.fileOwnership.resolveCanonical({\n file,\n patch,\n currentGenSha: currentGen,\n fernignorePatterns,\n warnedGens,\n warnings: this.warnings,\n });\n if (!userOwned) {\n return false;\n }\n }\n return true;\n };\n\n for (const patch of patches) {\n // Surface a warning when the patch's declared base_generation\n // is unreachable (shallow clone / aggressive `git gc --prune`). Check\n // this BEFORE any status gating — the warning is a reachability signal\n // independent of whether the patch is currently unresolved/resolving.\n if (\n patch.base_generation &&\n patch.base_generation !== currentGen &&\n !warnedGens.has(patch.base_generation)\n ) {\n if (!(await isReachable(patch.base_generation))) {\n warnedGens.add(patch.base_generation);\n this.warnings.push(\n `Base generation ${patch.base_generation.slice(0, 7)} is unreachable ` +\n `(shallow clone or pruned history). Treating affected files as user-owned ` +\n `to avoid silent data loss. ` +\n `Run \\`git fetch --unshallow\\` or avoid \\`git gc --prune\\` to restore full history.`\n );\n }\n }\n\n // Skip patches with any status (unresolved/resolving) — they weren't\n // successfully applied last time. Clear status so applyPatches() can\n // try them against the new generation.\n if (patch.status != null) {\n delete patch.status;\n continue;\n }\n\n // When HEAD is a generation commit AND it mutated this patch's\n // source files vs its parent, the customer manually staged a\n // new generation at HEAD without running replay. Both the\n // content-refresh and stale-base branches below would treat\n // `git diff currentGen → HEAD` as customer intent — but here\n // it's generator-vs-generator structural changes (the customer\n // overwrote their own resolved file with the generator's new\n // output). Refreshing patch_content/snapshot with that diff\n // silently erases the customization. Skip and let the patch\n // survive intact; `mergeFile`'s slow path will reconcile via\n // 3-way merge against the (still-valid) theirs_snapshot.\n //\n // Infrastructure [fern-generated] commits (e.g. test helpers,\n // store-patches commits) don't mutate source files vs parent,\n // so they fall through to the normal refresh path.\n if (headIsGeneration) {\n const parentChangedFiles = await headParentChangedFiles(patch.files);\n const headTouchedSource = patch.files.some((f) => parentChangedFiles.has(f));\n if (headTouchedSource) {\n continue;\n }\n }\n\n if (patch.base_generation === currentGen) {\n // Content refresh: check if user modified their customization\n // since the last replay commit. When an autoversion commit\n // contaminated HEAD between replay runs, route via\n // snapshot-based reconstruction to avoid baking the\n // placeholder→semver swap into customer patch_content.\n try {\n const contaminated = await this.hasAutoversionContamination(\n currentGen,\n \"HEAD\",\n patch.files,\n );\n\n if (contaminated) {\n const snapshotDiff = await this.computeSnapshotBasedPatchDiff(\n patch,\n currentGen,\n );\n if (snapshotDiff === null) continue;\n if (!snapshotDiff.trim()) {\n if (await allPatchFilesUserOwned(patch)) continue;\n this.lockManager.removePatch(patch.id);\n contentRefreshed++;\n continue;\n }\n const snapHasStaleMarkers = snapshotDiff.split(\"\\n\").some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (snapHasStaleMarkers) continue;\n const isProtectedSnap = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n if (isProtectedSnap) continue;\n const snapHash = this.detector.computeContentHash(snapshotDiff);\n if (snapHash !== patch.content_hash) {\n this.lockManager.updatePatch(patch.id, {\n patch_content: snapshotDiff,\n content_hash: snapHash,\n });\n contentRefreshed++;\n }\n continue;\n }\n\n const ppResult = await computePerPatchDiffWithFallback(\n patch,\n (f) => this.git.showFile(currentGen, f),\n (f) => this.git.showFile(\"HEAD\", f),\n (files) => this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...files])\n .catch(() => null)\n );\n\n if (ppResult === null) continue;\n const diff = ppResult.diff;\n\n if (!diff.trim()) {\n // Empty diff usually means customer reverted the\n // customization. But if every file is user-owned, empty\n // diff is expected (the generator bundled the files\n // into currentGen) — preserve the patch.\n if (await allPatchFilesUserOwned(patch)) continue;\n // User reverted all customizations in this patch\n this.lockManager.removePatch(patch.id);\n contentRefreshed++;\n continue;\n }\n\n // Skip content refresh if the diff contains stale conflict\n // markers from a previous crashed run. Only check added lines\n // (prefixed with \"+\") to avoid false positives from files that\n // legitimately contain marker text (e.g., documentation).\n const diffLines = diff.split(\"\\n\");\n const hasStaleMarkers = diffLines.some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (hasStaleMarkers) {\n continue;\n }\n\n // Skip content conversion for .fernignore-protected files —\n // matches rebasePatches' behavior so both flows end with\n // identical patch_content for the same scenario.\n // User-created (non-protected) files go through the regular\n // content-refresh path so they can be deduplicated when\n // multiple incremental patches resolve to the same cumulative\n // state.\n const isProtected = patch.files.some(\n (file) => file === \".fernignore\" ||\n fernignorePatterns.some((p) => file === p || minimatch(file, p))\n );\n if (isProtected) {\n continue;\n }\n\n const newContentHash = this.detector.computeContentHash(diff);\n if (newContentHash !== patch.content_hash) {\n // User changed their customization — update patch content\n // and recalculate the files list (some files may no longer differ)\n const filesOutput = await this.git\n .exec([\"diff\", \"--name-only\", currentGen, \"HEAD\", \"--\", ...patch.files])\n .catch(() => null);\n\n const newFiles = filesOutput\n ? filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !f.startsWith(\".fern/\"))\n : patch.files;\n\n if (newFiles.length === 0) {\n this.lockManager.removePatch(patch.id);\n } else {\n // Snapshot THEIRS from HEAD (the diff is\n // currentGen → HEAD). The `headIsGeneration`\n // early-continue above already protects against\n // the manual-gen-commit-at-HEAD case (where HEAD\n // is generator content with no customer intent).\n // For genuine customer edits, HEAD is the\n // authoritative customer state — refresh\n // snapshot to match so subsequent regens see\n // the customer's latest intent.\n const snapshot = await this.readSnapshotFromTree(\"HEAD\", newFiles);\n this.lockManager.updatePatch(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n files: newFiles,\n ...(Object.keys(snapshot).length > 0 ? { theirs_snapshot: snapshot } : {})\n });\n }\n contentRefreshed++;\n }\n } catch {\n // If anything fails, leave the patch unchanged\n }\n continue;\n }\n\n try {\n // Check for unresolved conflict markers in HEAD\n const markerFiles = await this.git\n .exec([\"grep\", \"-l\", \"<<<<<<< Generated\", \"HEAD\", \"--\", ...patch.files])\n .catch(() => \"\");\n\n if (markerFiles.trim()) continue;\n\n // Snapshot-based reconstruction when autoversion contaminated.\n const contaminated = await this.hasAutoversionContamination(\n currentGen,\n \"HEAD\",\n patch.files,\n );\n\n if (contaminated) {\n const snapshotDiff = await this.computeSnapshotBasedPatchDiff(\n patch,\n currentGen,\n );\n if (snapshotDiff === null) continue;\n if (!snapshotDiff.trim()) {\n if (await allPatchFilesUserOwned(patch)) {\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGen });\n } catch {\n // New patch — not in lockfile yet\n }\n continue;\n }\n this.lockManager.removePatch(patch.id);\n conflictAbsorbed++;\n continue;\n }\n const snapHasStaleMarkers = snapshotDiff.split(\"\\n\").some(\n (l) => l.startsWith(\"+<<<<<<< Generated\") || l.startsWith(\"+>>>>>>> Your customization\")\n );\n if (snapHasStaleMarkers) continue;\n const snapHash = this.detector.computeContentHash(snapshotDiff);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: snapshotDiff,\n content_hash: snapHash,\n });\n conflictResolved++;\n continue;\n }\n\n // Per-patch-region diff with cumulative fallback for the\n // unlocatable subset (see content-refresh branch above for\n // the rationale around partially-anchorable hunks).\n const ppResult = await computePerPatchDiffWithFallback(\n patch,\n (f) => this.git.showFile(currentGen, f),\n (f) => this.git.showFile(\"HEAD\", f),\n (files) => this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...files])\n .catch(() => null)\n );\n\n // ppResult === null only when cumulative fallback explicitly\n // failed — skip the patch rather than corrupt the lockfile.\n if (ppResult === null) continue;\n const diff = ppResult.diff;\n\n if (!diff.trim()) {\n // Empty diff: for user-owned patches this is expected\n // (currentGen has bundled copies), not a revert signal.\n if (await allPatchFilesUserOwned(patch)) {\n // Repoint stale base onto current so the next cycle\n // routes via the fast content-refresh branch.\n try {\n this.lockManager.updatePatch(patch.id, { base_generation: currentGen });\n } catch {\n // New patches aren't in lockfile yet\n }\n continue;\n }\n // Empty diff — customer reverted their customization\n this.lockManager.removePatch(patch.id);\n conflictAbsorbed++;\n continue;\n }\n\n // Update the patch with the resolved content. The\n // `headIsGeneration` early-continue above protects the\n // bug case (HEAD is a generator commit with no customer\n // intent). For genuine customer resolutions, refresh\n // snapshot from HEAD too.\n const newContentHash = this.detector.computeContentHash(diff);\n const snapshot = await this.readSnapshotFromTree(\"HEAD\", patch.files);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: diff,\n content_hash: newContentHash,\n ...(Object.keys(snapshot).length > 0 ? { theirs_snapshot: snapshot } : {})\n });\n conflictResolved++;\n } catch {\n // If anything fails, leave the patch unchanged\n }\n }\n\n return { conflictResolved, conflictAbsorbed, contentRefreshed };\n }\n\n /**\n * After applyPatches(), surface a warning for each (patch × file) where\n * diff3 silently dropped lines that were unchanged context in the\n * customer's THEIRS. The deletion stays on disk (correct diff3 outcome),\n * but the customer must learn so they can re-add the lines if they\n * relied on them. This is the \"surface or preserve, never silently drop\"\n * contract for legitimate-deletion cases.\n */\n /** @internal Used by Flow implementations in `src/flows/`. */\n recordDroppedContextLineWarnings(results: ReplayResult[]): void {\n const PREVIEW_COUNT = 5;\n for (const result of results) {\n if (!result.fileResults) continue;\n for (const fr of result.fileResults) {\n const dropped = fr.droppedContextLines;\n if (!dropped || dropped.length === 0) continue;\n const preview = dropped\n .slice(0, PREVIEW_COUNT)\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n const more = dropped.length > PREVIEW_COUNT\n ? `\\n ... and ${dropped.length - PREVIEW_COUNT} more`\n : \"\";\n this.warnings.push(\n `${fr.file}: ${dropped.length} line(s) that appeared as unchanged ` +\n `context in your customization were deleted by the new generator output. ` +\n `The merge followed the deletion. First lines deleted:\\n${preview}${more}\\n` +\n `If you want to keep these lines, restore them in a follow-up commit and ` +\n `re-run replay; otherwise this warning can be safely ignored.`\n );\n }\n }\n }\n\n /**\n * After applyPatches(), strip conflict markers from conflicting files\n * so only clean content is committed. Keeps the Generated (OURS) side.\n */\n /** @internal Used by Flow implementations in `src/flows/`. */\n revertConflictingFiles(results: ReplayResult[]): void {\n for (const result of results) {\n if (result.status !== \"conflict\" || !result.fileResults) continue;\n\n for (const fileResult of result.fileResults) {\n if (fileResult.status !== \"conflict\") continue;\n\n const filePath = join(this.outputDir, fileResult.file);\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const stripped = stripConflictMarkers(content);\n writeFileSync(filePath, stripped);\n } catch {\n // If file doesn't exist or can't be read, skip\n }\n }\n }\n }\n\n /**\n * Clean up stale conflict markers left by a previous crashed run.\n * Called after commitGeneration() when HEAD is the [fern-generated] commit.\n * Restores files to their clean generated state from HEAD.\n * Skips .fernignore-protected files to prevent overwriting user content.\n */\n /** @internal Used by Flow implementations in `src/flows/`. */\n async cleanupStaleConflictMarkers(): Promise<void> {\n const markerFiles = await this.git\n .exec([\"grep\", \"-l\", \"<<<<<<< Generated\", \"--\", \".\"])\n .catch(() => \"\");\n\n const files = markerFiles.trim().split(\"\\n\").filter(Boolean);\n if (files.length === 0) return;\n\n const fernignorePatterns = this.readFernignorePatterns();\n\n for (const file of files) {\n if (fernignorePatterns.some((pattern) => minimatch(file, pattern))) continue;\n\n try {\n await this.git.exec([\"checkout\", \"HEAD\", \"--\", file]);\n } catch {\n // File may not exist in the generation tree (e.g., user-created\n // file). Skip — revertConflictingFiles will handle it later.\n }\n }\n }\n\n private readFernignorePatterns(): string[] {\n const fernignorePath = join(this.outputDir, \".fernignore\");\n if (!existsSync(fernignorePath)) return [];\n return readFileSync(fernignorePath, \"utf-8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n }\n\n /** @internal Used by Flow implementations in `src/flows/`. */\n buildReport(\n flow: \"first-generation\" | \"no-patches\" | \"normal-regeneration\" | \"skip-application\",\n patches: StoredPatch[],\n results: ReplayResult[],\n options?: ReplayOptions,\n warnings?: string[],\n rebaseCounts?: {\n absorbed: number;\n repointed: number;\n contentRebased: number;\n keptAsUserOwned: number;\n absorbedPatchIds: Set<string>;\n },\n preRebaseCounts?: { conflictResolved: number; conflictAbsorbed: number; contentRefreshed: number },\n patchesReverted?: number\n ): ReplayReport {\n const conflictResults = results.filter((r) => r.status === \"conflict\");\n const conflictDetails = conflictResults\n .map((r) => {\n const conflictFiles = r.fileResults?.filter((f) => f.status === \"conflict\") ?? [];\n const cleanFiles = r.fileResults?.filter((f) => f.status === \"merged\").map((f) => f.file) ?? [];\n return {\n patchId: r.patch.id,\n patchMessage: r.patch.original_message,\n reason: r.conflictReason,\n files: conflictFiles,\n cleanFiles: cleanFiles.length > 0 ? cleanFiles : undefined\n };\n })\n .filter((d) => d.files.length > 0);\n const partialCount = conflictDetails.filter((d) => d.cleanFiles && d.cleanFiles.length > 0).length;\n\n // Widen unresolvedPatches to include conflict-by-association entries:\n // patches whose result.status is \"applied\" but whose patch.status was\n // set to \"unresolved\" by the rebase guard (clean follow-up after\n // same-file conflict). They have no file-level merge conflicts of\n // their own but must surface so the resolve workflow handles them.\n const unresolvedResults = results.filter(\n (r) => r.status === \"conflict\" || r.patch.status === \"unresolved\"\n );\n\n return {\n flow,\n patchesDetected: patches.length,\n patchesApplied: results.filter((r) => r.status === \"applied\").length,\n patchesWithConflicts: conflictResults.length,\n patchesSkipped: results.filter((r) => r.status === \"skipped\").length,\n patchesPartiallyApplied: partialCount > 0 ? partialCount : undefined,\n patchesAbsorbed: rebaseCounts && rebaseCounts.absorbed > 0 ? rebaseCounts.absorbed : undefined,\n patchesRepointed: rebaseCounts && rebaseCounts.repointed > 0 ? rebaseCounts.repointed : undefined,\n patchesContentRebased:\n rebaseCounts && rebaseCounts.contentRebased > 0 ? rebaseCounts.contentRebased : undefined,\n patchesKeptAsUserOwned:\n rebaseCounts && rebaseCounts.keptAsUserOwned > 0 ? rebaseCounts.keptAsUserOwned : undefined,\n patchesReverted: patchesReverted && patchesReverted > 0 ? patchesReverted : undefined,\n patchesConflictResolved:\n preRebaseCounts && preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed > 0\n ? preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed\n : undefined,\n patchesRefreshed:\n preRebaseCounts && preRebaseCounts.contentRefreshed > 0 ? preRebaseCounts.contentRefreshed : undefined,\n conflicts: conflictResults.flatMap((r) => r.fileResults?.filter((f) => f.status === \"conflict\") ?? []),\n conflictDetails: conflictDetails.length > 0 ? conflictDetails : undefined,\n unresolvedPatches:\n unresolvedResults.length > 0\n ? unresolvedResults.map((r) => ({\n patchId: r.patch.id,\n patchMessage: r.patch.original_message,\n files: r.patch.files,\n conflictDetails: r.fileResults?.filter((f) => f.status === \"conflict\") ?? []\n }))\n : undefined,\n wouldApply: options?.dryRun ? patches : undefined,\n warnings: warnings && warnings.length > 0 ? warnings : undefined\n };\n }\n}\n\n/**\n * Bucket the patches given to commitReplay so the commit message body is\n * an honest reflection of outcomes. A patch is:\n * - `unresolved`: file-level merge conflict OR PR #73 conflict-by-association\n * (`patch.status === \"unresolved\"` set by `rebasePatches`)\n * - `absorbed`: in `absorbedPatchIds` (rebase removed it because the\n * generator now emits the customization natively)\n * - `applied`: everything else with status === \"applied\"\n * Skipped/binary patches don't surface in the commit message at all.\n *\n * `patchesPassedToCommit` is what the caller hands to `commitReplay` (e.g.,\n * `allPatches` for normal regen, `newPatches` for the no-patches flow).\n * The function preserves its order so the commit body matches lockfile order.\n */\n/** @internal Used by Flow implementations in `src/flows/`. */\nexport function computeCommitBuckets(\n results: ReplayResult[],\n absorbedPatchIds: Set<string>,\n patchesPassedToCommit: StoredPatch[]\n): { applied: StoredPatch[]; unresolved: StoredPatch[]; absorbed: StoredPatch[] } {\n const resultByPatchId = new Map<string, ReplayResult>();\n for (const r of results) resultByPatchId.set(r.patch.id, r);\n\n const applied: StoredPatch[] = [];\n const unresolved: StoredPatch[] = [];\n const absorbed: StoredPatch[] = [];\n\n for (const patch of patchesPassedToCommit) {\n if (absorbedPatchIds.has(patch.id)) {\n absorbed.push(patch);\n continue;\n }\n const r = resultByPatchId.get(patch.id);\n if (!r) {\n // No result (e.g., patch wasn't applied this cycle but is in\n // the lockfile). Treat as applied for legacy parity — the\n // alternative would silently disappear from the commit body.\n applied.push(patch);\n continue;\n }\n if (r.status === \"conflict\" || patch.status === \"unresolved\") {\n unresolved.push(patch);\n continue;\n }\n if (r.status === \"applied\") {\n applied.push(patch);\n continue;\n }\n // status === \"skipped\" — omit. Skipped patches typically come from\n // exclude patterns; surfacing them in the commit body is noise.\n }\n\n return { applied, unresolved, absorbed };\n}\n","/**\n * Per-patch contribution diff.\n *\n * Given a stored patch, the post-regen `currentGen` content of each file, and\n * the working-tree (post-resolution) content, compute a unified diff that\n * captures ONLY this patch's contribution — scoped to the regions identified\n * by the patch's stored hunks via context-line anchoring.\n *\n * Why this exists: `git diff currentGen -- patch.files` returns the full\n * cumulative diff for those files. When two patches share a file, the\n * cumulative diff includes BOTH patches' customizations — which means each\n * patch ends up with the same `patch_content` and `content_hash`. The\n * dedup-by-hash logic downstream then collapses them into one and silently\n * loses provenance.\n */\n\nimport { mkdtemp, writeFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport { parseHunks, locateHunksInOurs, type DiffHunk, type LocatedHunk } from \"./HybridReconstruction.js\";\n\n/**\n * Trim a hunk's body to exactly the line counts declared in its `@@` header.\n *\n * `parseHunks` keeps appending lines to a hunk's body until it hits the next\n * `@@` header or end of input. When the patch text has trailing blank lines\n * (e.g. from a trailing newline in the multi-file diff), those blanks get\n * conflated with context lines (per the helper's \"bare empty = context\"\n * heuristic), inflating the parsed body past `oldCount`/`newCount`. That\n * inflation causes `locateHunksInOurs` to overshoot when computing\n * `oursSpan` because trailing context anchoring lands on lines beyond the\n * hunk's actual region.\n */\nfunction normalizeHunkBody(hunk: DiffHunk): DiffHunk {\n let contextC = 0;\n let removeC = 0;\n let addC = 0;\n const trimmed: typeof hunk.lines = [];\n for (const line of hunk.lines) {\n const oldUsed = contextC + removeC;\n const newUsed = contextC + addC;\n if (oldUsed >= hunk.oldCount && newUsed >= hunk.newCount) break;\n trimmed.push(line);\n if (line.type === \"context\") contextC++;\n else if (line.type === \"remove\") removeC++;\n else if (line.type === \"add\") addC++;\n }\n return { ...hunk, lines: trimmed };\n}\n\nexport interface PerPatchDiffResult {\n /** Concatenated unified diff (one `diff --git` block per file). Empty string if patch contributes nothing. */\n diff: string;\n /** Files where the patch's hunks could not be anchored against either currentGen or working tree. Caller should fall back. */\n unlocatableFiles: string[];\n}\n\n/**\n * Extract the per-file unified diff for `filePath` from a multi-file unified diff.\n * Mirrors `ReplayApplicator.extractFileDiff` — kept here to avoid cross-module\n * private-method exposure.\n */\nexport function extractFileDiffForFile(patchContent: string, filePath: string): string | null {\n const lines = patchContent.split(\"\\n\");\n const out: string[] = [];\n let inTarget = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git\")) {\n if (inTarget) break;\n if (isDiffLineForFile(line, filePath)) {\n inTarget = true;\n out.push(line);\n }\n continue;\n }\n if (inTarget) out.push(line);\n }\n return out.length > 0 ? out.join(\"\\n\") + \"\\n\" : null;\n}\n\nfunction isDiffLineForFile(line: string, filePath: string): boolean {\n // Use anchored regex (matches `ReplayApplicator.ts` pattern) to avoid\n // substring false positives — e.g. `src/user.ts` matching `src/user.tsx`,\n // or `lib/foo.ts` matching `lib/foo.ts-backup`. Match on the b-path\n // (post-image) since it's the canonical destination, including for\n // renames (`diff --git a/old b/new`).\n const match = line.match(/^diff --git a\\/(.+) b\\/(.+)$/);\n return match !== null && (match[2] === filePath || match[1] === filePath);\n}\n\n/**\n * Compute the per-patch contribution diff.\n *\n * The caller owns content reads via `getCurrentGenContent` / `getWorkingTreeContent`\n * so that the helper is reusable from `resolve.ts` (reads from disk) and\n * `rebasePatches` (reads from git tree + disk).\n *\n * Algorithm:\n * 1. For each file in `patch.files`:\n * a. Parse the patch's hunks for this file.\n * b. Anchor the hunks in `currentGen` content via `locateHunksInOurs`.\n * c. Anchor the hunks in `workingTree` content via `locateHunksInOurs`.\n * d. Overlay each anchored region from working tree onto currentGen,\n * producing a \"currentGen + just this patch's contribution\" string.\n * e. Compute a unified diff between currentGen and that overlay via\n * `git diff --no-index`. This is the per-patch diff for the file.\n * 2. Concatenate per-file diffs.\n *\n * Falls back to `unlocatableFiles` for files where steps b/c fail (rename,\n * heavy generator restructure, etc.) — caller's responsibility to handle.\n */\nexport async function computePerPatchDiff(\n patch: { patch_content: string; files: string[] },\n getCurrentGenContent: (file: string) => Promise<string | null>,\n getWorkingTreeContent: (file: string) => Promise<string | null>\n): Promise<PerPatchDiffResult> {\n const fragments: string[] = [];\n const unlocatableFiles: string[] = [];\n\n for (const file of patch.files) {\n const fileDiff = extractFileDiffForFile(patch.patch_content, file);\n if (fileDiff == null) {\n // patch.files lists this path, but patch_content doesn't reference it.\n // This commonly happens after a generator rename (resolvedFiles pre-pass\n // updated patch.files to the NEW path, but patch_content still uses the\n // OLD path). Treat as unlocatable so the caller falls back to the legacy\n // cumulative-file diff for this file.\n unlocatableFiles.push(file);\n continue;\n }\n\n const hunksRaw = parseHunks(fileDiff).map(normalizeHunkBody);\n // M1: drop hunks whose body is empty after trimming or whose body\n // line counts don't match the `@@` header. Either is a sign of a\n // malformed/truncated diff; passing them downstream into\n // `locateHunksInOurs` would yield garbage offsets and silently\n // corrupt the overlay.\n const hunks = hunksRaw.filter((h) => {\n if (h.lines.length === 0) return false;\n let ctx = 0, rm = 0, add = 0;\n for (const ln of h.lines) {\n if (ln.type === \"context\") ctx++;\n else if (ln.type === \"remove\") rm++;\n else if (ln.type === \"add\") add++;\n }\n return ctx + rm === h.oldCount && ctx + add === h.newCount;\n });\n if (hunks.length === 0) {\n // If parseHunks returned hunks but none survived the body check,\n // signal unlocatable so the caller falls back to cumulative diff.\n if (hunksRaw.length > 0) unlocatableFiles.push(file);\n continue;\n }\n\n const currentGen = await getCurrentGenContent(file);\n const workingTree = await getWorkingTreeContent(file);\n\n // Determine whether the patch is a pure new-file patch (no remove lines\n // anywhere). True new-file patches have all hunks with oldCount === 0.\n const isPureNewFile = hunks.every((h) => h.oldCount === 0);\n const isPureDelete = hunks.every((h) => h.newCount === 0);\n\n // New-file patch: file didn't exist in currentGen. Only valid if patch is\n // genuinely a new-file patch — otherwise we may be in the ghost case\n // (currentGen tree unreachable for a file the patch knows existed).\n if (currentGen == null) {\n if (!isPureNewFile) {\n unlocatableFiles.push(file);\n continue;\n }\n if (workingTree == null) continue;\n fragments.push(synthesizeNewFileDiff(file, workingTree));\n continue;\n }\n\n // Pure-new-file patch where currentGen ALREADY has the file: the\n // user-owned bundling case (a previous generation commit bundled\n // the customer's file into the gen tree via `git add -A`). Compare full\n // contents directly — anchoring an empty `oldSide` would over-grab.\n // If contents match → no contribution since last cycle. If they\n // differ → customer modified, emit a full-file diff.\n if (isPureNewFile) {\n if (workingTree == null) {\n // File deleted in working tree → emit deletion diff.\n fragments.push(synthesizeDeleteFileDiff(file, currentGen));\n continue;\n }\n if (workingTree === currentGen) {\n // No change since bundling — no contribution.\n continue;\n }\n const fullDiff = await unifiedDiff(currentGen, workingTree, file);\n if (fullDiff && fullDiff.trim()) fragments.push(fullDiff);\n continue;\n }\n\n // Deleted in working tree: file existed in currentGen.\n if (workingTree == null) {\n if (!isPureDelete) {\n unlocatableFiles.push(file);\n continue;\n }\n fragments.push(synthesizeDeleteFileDiff(file, currentGen));\n continue;\n }\n\n const currentGenLines = splitLines(currentGen);\n const workingTreeLines = splitLines(workingTree);\n\n const locInCurrentGenRaw = locateHunksInOurs(hunks, currentGenLines);\n const locInWorkingTreeRaw = locateHunksInOurs(hunks, workingTreeLines);\n\n if (locInCurrentGenRaw == null || locInWorkingTreeRaw == null) {\n unlocatableFiles.push(file);\n continue;\n }\n\n // HybridReconstruction.computeOursSpan returns the context\n // count when trailing context is empty, which doesn't account for\n // remove/add lines. Re-derive span by content matching with a\n // domain hint: currentGen is expected to look like the patch's \"old\"\n // side (pre-patch); workingTree is expected to look like the \"new\"\n // side (post-patch). The hint disambiguates pure-insertion hunks\n // where oldSide is a prefix of newSide and both fit by coincidence.\n const locInCurrentGen = locInCurrentGenRaw.map((l) =>\n resolveSpan(l, currentGenLines, \"old\")\n );\n const locInWorkingTree = locInWorkingTreeRaw.map((l) =>\n resolveSpan(l, workingTreeLines, \"new\")\n );\n\n // Overlay each region from working tree onto currentGen.\n const overlay = overlayRegions(\n currentGenLines,\n locInCurrentGen,\n workingTreeLines,\n locInWorkingTree\n );\n\n // M2: overlay returned null → invariant violation (mismatched\n // anchored hunk counts). Signal unlocatable so caller falls back\n // to cumulative; do NOT silently treat as \"no contribution\".\n if (overlay === null) {\n unlocatableFiles.push(file);\n continue;\n }\n\n if (overlay === currentGen) {\n // Patch contributed nothing in this file — customer reverted or absorbed.\n continue;\n }\n\n const fileUnifiedDiff = await unifiedDiff(currentGen, overlay, file);\n if (fileUnifiedDiff && fileUnifiedDiff.trim()) {\n fragments.push(fileUnifiedDiff);\n }\n }\n\n return {\n diff: fragments.join(\"\"),\n unlocatableFiles\n };\n}\n\n/**\n * Combine a per-patch diff with a cumulative-diff fallback for any files\n * whose hunks couldn't be anchored. This is the helper used by both\n * `commands/resolve.ts` and `ReplayService.preGenerationRebase` to ensure\n * unlocatable files don't silently drop the patch when the locatable\n * subset's per-patch diff is empty.\n *\n * Algorithm:\n * 1. Run per-patch diff on `patch.files`.\n * 2. If `unlocatableFiles` is non-empty, run cumulative diff scoped to\n * ONLY those unlocatable files via `runCumulativeDiff(files)`.\n * 3. Concatenate the two. Return null if the cumulative invocation fails.\n *\n * Returns:\n * - `{ diff, hadFallback }` where `diff` may be empty (true patch revert)\n * and `hadFallback` indicates whether the cumulative subset was used.\n * - `null` if the cumulative invocation explicitly failed (callers should\n * skip the patch — same semantics as a missing diff).\n */\nexport async function computePerPatchDiffWithFallback(\n patch: { patch_content: string; files: string[] },\n getCurrentGenContent: (file: string) => Promise<string | null>,\n getWorkingTreeContent: (file: string) => Promise<string | null>,\n runCumulativeDiff: (files: string[]) => Promise<string | null>\n): Promise<{ diff: string; hadFallback: boolean; fallbackFiles: string[] } | null> {\n const ppDiff = await computePerPatchDiff(\n patch,\n getCurrentGenContent,\n getWorkingTreeContent\n );\n\n if (ppDiff.unlocatableFiles.length === 0) {\n return { diff: ppDiff.diff, hadFallback: false, fallbackFiles: [] };\n }\n\n // Run cumulative diff scoped to ONLY the unlocatable files. Merging\n // them with the per-patch diff for locatable files preserves the\n // surgical scoping for files we COULD anchor, while still capturing\n // contributions for files we couldn't.\n const cumulative = await runCumulativeDiff(ppDiff.unlocatableFiles);\n if (cumulative === null) {\n return null;\n }\n\n const merged = ppDiff.diff + (cumulative.trim() ? cumulative : \"\");\n return { diff: merged, hadFallback: true, fallbackFiles: ppDiff.unlocatableFiles };\n}\n\nfunction splitLines(content: string): string[] {\n // Match parseHunks's line semantics: split on \"\\n\", preserving trailing-newline behavior.\n return content.split(\"\\n\");\n}\n\n/**\n * Determine the correct oursSpan for an anchored hunk by content-matching.\n * The hunk's `@@` header tells us oldCount (lines if patch's \"old\" side present)\n * and newCount (lines if patch's \"new\" side present). We match the lines in\n * OURS at the anchor against both sides and pick the one that fits.\n */\n/**\n * Determine the correct `oursSpan` for an anchored hunk by content-matching.\n *\n * `prefer` tells us which side of the patch we EXPECT OURS to look like:\n * - `\"old\"` → OURS is patch's BASE (e.g. currentGen, pre-patch state).\n * Default to `oldCount` when both sides fit.\n * - `\"new\"` → OURS is patch's THEIRS (e.g. workingTree post-apply).\n * Default to `newCount` when both sides fit.\n *\n * For pure-insertion hunks (no remove lines), `oldSide` is a strict prefix\n * of `newSide`. Both sides will fit whenever oldSide does AND the next OURS\n * lines coincide with the patch's added lines — common for generic adds\n * like `}` or empty lines. Without the `prefer` hint, picking the longer\n * (or shorter) match unconditionally over-includes (or under-includes)\n * sibling-patch content. With `prefer`, we use the caller's domain\n * knowledge to pick the right span.\n */\nfunction resolveSpan(\n loc: LocatedHunk,\n oursLines: string[],\n prefer: \"old\" | \"new\"\n): LocatedHunk {\n const { hunk, oursOffset } = loc;\n\n // Build the expected \"old\" content sequence from the hunk: context + remove lines, in order.\n const oldSide: string[] = [];\n const newSide: string[] = [];\n for (const line of hunk.lines) {\n if (line.type === \"context\") {\n oldSide.push(line.content);\n newSide.push(line.content);\n } else if (line.type === \"remove\") {\n oldSide.push(line.content);\n } else if (line.type === \"add\") {\n newSide.push(line.content);\n }\n }\n\n const oldFits = sequenceMatches(oldSide, oursLines, oursOffset);\n const newFits = sequenceMatches(newSide, oursLines, oursOffset);\n\n if (prefer === \"old\") {\n if (oldFits) return { ...loc, oursSpan: hunk.oldCount };\n if (newFits) return { ...loc, oursSpan: hunk.newCount };\n } else {\n if (newFits) return { ...loc, oursSpan: hunk.newCount };\n if (oldFits) return { ...loc, oursSpan: hunk.oldCount };\n }\n\n // Neither side matches exactly — fall back to original computeOursSpan\n // value (already in loc.oursSpan). This is best-effort for unanchored\n // edges; the caller's overlay+diff will produce a best-effort diff.\n return loc;\n}\n\nfunction sequenceMatches(needle: string[], haystack: string[], offset: number): boolean {\n if (offset + needle.length > haystack.length) return false;\n for (let i = 0; i < needle.length; i++) {\n if (haystack[offset + i] !== needle[i]) return false;\n }\n return true;\n}\n\n/**\n * Reconstruct currentGen with each anchored region replaced by the\n * corresponding region from working tree. Returns the joined string, or\n * `null` to signal an irrecoverable inconsistency (caller should treat as\n * unlocatable rather than silently produce a corrupt overlay).\n */\nfunction overlayRegions(\n currentGenLines: string[],\n locInCurrentGen: LocatedHunk[],\n workingTreeLines: string[],\n locInWorkingTree: LocatedHunk[]\n): string | null {\n // Same hunks parsed against both, lengths must match. If they don't,\n // something invariant-violating happened — signal failure rather than\n // returning currentGen (which the caller would interpret as \"patch\n // contributed nothing\" and silently drop the patch).\n if (locInCurrentGen.length !== locInWorkingTree.length) {\n return null;\n }\n const out: string[] = [];\n let cursor = 0;\n for (let i = 0; i < locInCurrentGen.length; i++) {\n const cg = locInCurrentGen[i]!;\n const wt = locInWorkingTree[i]!;\n // Gap before this hunk: keep currentGen content\n if (cg.oursOffset > cursor) {\n out.push(...currentGenLines.slice(cursor, cg.oursOffset));\n }\n // Replace currentGen's region with working tree's region for this hunk\n out.push(...workingTreeLines.slice(wt.oursOffset, wt.oursOffset + wt.oursSpan));\n cursor = cg.oursOffset + cg.oursSpan;\n }\n // Trailing gap: keep currentGen content\n if (cursor < currentGenLines.length) {\n out.push(...currentGenLines.slice(cursor));\n }\n return out.join(\"\\n\");\n}\n\n/**\n * Compute a unified diff between two strings using `git diff --no-index`.\n * Headers are rewritten to `a/<file>` / `b/<file>` for compatibility with\n * `git apply` and the rest of the codebase's patch handling.\n */\nexport async function unifiedDiff(beforeContent: string, afterContent: string, filePath: string): Promise<string> {\n if (beforeContent === afterContent) return \"\";\n\n const tmp = await mkdtemp(join(tmpdir(), \"fern-replay-pp-\"));\n try {\n const beforePath = join(tmp, \"before\");\n const afterPath = join(tmp, \"after\");\n await writeFile(beforePath, beforeContent, \"utf-8\");\n await writeFile(afterPath, afterContent, \"utf-8\");\n\n const raw = await runGitDiffNoIndex(beforePath, afterPath);\n if (!raw.trim()) return \"\";\n\n return rewriteDiffHeaders(raw, filePath);\n } finally {\n await rm(tmp, { recursive: true, force: true });\n }\n}\n\nfunction runGitDiffNoIndex(beforePath: string, afterPath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"git\", [\"diff\", \"--no-index\", \"--\", beforePath, afterPath]);\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout.on(\"data\", (d: Buffer) => (stdout += d.toString()));\n proc.stderr.on(\"data\", (d: Buffer) => (stderr += d.toString()));\n proc.on(\"close\", (code) => {\n // git diff --no-index returns 0 (no diff) or 1 (diff present) on success;\n // anything else is a real error.\n if (code === 0 || code === 1) resolve(stdout);\n else reject(new Error(`git diff --no-index failed (code ${code}): ${stderr}`));\n });\n });\n}\n\n/**\n * Rewrite the `diff --git`, `---`, and `+++` headers from temp paths to\n * `a/<file>` and `b/<file>` so the diff applies cleanly via `git apply`.\n */\nfunction rewriteDiffHeaders(raw: string, filePath: string): string {\n const lines = raw.split(\"\\n\");\n const out: string[] = [];\n let seenFirstHeader = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git \")) {\n out.push(`diff --git a/${filePath} b/${filePath}`);\n seenFirstHeader = true;\n continue;\n }\n if (!seenFirstHeader) {\n // Skip preamble before first diff header\n continue;\n }\n if (line.startsWith(\"--- \")) {\n out.push(`--- a/${filePath}`);\n continue;\n }\n if (line.startsWith(\"+++ \")) {\n out.push(`+++ b/${filePath}`);\n continue;\n }\n out.push(line);\n }\n return out.join(\"\\n\");\n}\n\nexport function synthesizeNewFileDiff(file: string, content: string): string {\n const lines = content.split(\"\\n\");\n // Drop trailing empty element if file ends with newline (matches git's diff format).\n const hasTrailingNewline = content.endsWith(\"\\n\");\n const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;\n const header = [\n `diff --git a/${file} b/${file}`,\n \"new file mode 100644\",\n \"--- /dev/null\",\n `+++ b/${file}`,\n `@@ -0,0 +1,${bodyLines.length} @@`,\n ].join(\"\\n\");\n const body = bodyLines.map((l) => `+${l}`).join(\"\\n\");\n const trailer = hasTrailingNewline ? \"\" : \"\\n\\\\";\n return header + \"\\n\" + body + trailer + \"\\n\";\n}\n\nexport function synthesizeDeleteFileDiff(file: string, content: string): string {\n const lines = content.split(\"\\n\");\n const hasTrailingNewline = content.endsWith(\"\\n\");\n const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;\n const header = [\n `diff --git a/${file} b/${file}`,\n \"deleted file mode 100644\",\n `--- a/${file}`,\n \"+++ /dev/null\",\n `@@ -1,${bodyLines.length} +0,0 @@`,\n ].join(\"\\n\");\n const body = bodyLines.map((l) => `-${l}`).join(\"\\n\");\n const trailer = hasTrailingNewline ? \"\" : \"\\n\\\\";\n return header + \"\\n\" + body + trailer + \"\\n\";\n}\n","import { minimatch } from \"minimatch\";\nimport type { GitClient } from \"../git/GitClient.js\";\nimport type { StoredPatch } from \"../types.js\";\n\n/**\n * Inputs for one ownership resolution call.\n *\n * `originalFileName` is the pre-rename path used when the generator moved\n * the file between generations — tree lookups at ancestor generations need\n * the original path because that's where the generator produced the content.\n *\n * `warnedGens` and `warnings` are mutable accumulators threaded across calls\n * within a single replay run. The canonical path appends a one-time warning\n * when a base generation tree is unreachable (shallow clone / aggressive GC)\n * so the customer sees a single message per affected base, not one per file.\n */\nexport interface OwnershipContext {\n readonly file: string;\n readonly originalFileName?: string;\n readonly patch: StoredPatch;\n readonly currentGenSha: string;\n readonly fernignorePatterns: readonly string[];\n readonly warnedGens: Set<string>;\n readonly warnings: string[];\n}\n\n/**\n * Single canonical home for \"is this file user-owned?\" resolution. Every\n * service-level check (preGenerationRebase, rebasePatches, trimAbsorbedFiles)\n * routes through `resolveCanonical`.\n *\n * The earlier `rebasePatches` inline variant (`resolveAtCurrentGen`) was\n * collapsed under FER-10386 once pre-flight investigation showed its\n * narrower fall-back was harmless on every reachable scenario but worse\n * on the unreachable-base-tree case. See `docs/known-divergences.md`\n * entry 5 for the closed-out divergence record.\n */\nexport class FileOwnership {\n constructor(private readonly git: GitClient) {}\n\n /**\n * Canonical resolution. Returns true if `file` is user-owned per:\n *\n * 1. `patch.user_owned === true` — authoritative, persisted flag.\n * 2. `file === \".fernignore\"` — always user-owned.\n * 3. File matches a `.fernignore` pattern (via minimatch).\n * 4. Patch content shows `--- /dev/null` for this file (legacy-safe\n * signal for patches predating `user_owned` or whose flag was lost).\n * 5. Tree-based check against `patch.base_generation` when reachable\n * AND distinct from `currentGenSha`. Unreachable base → conservative\n * user-owned (silent-absorption safety net), with a one-time warning\n * per base SHA.\n * 6. Final fallback: check `currentGenSha` when no usable base exists\n * (legacy one-gen lockfile).\n */\n async resolveCanonical(ctx: OwnershipContext): Promise<boolean> {\n const { file, originalFileName, patch, currentGenSha, fernignorePatterns, warnedGens, warnings } = ctx;\n if (patch.user_owned) return true;\n if (file === \".fernignore\") return true;\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) return true;\n\n if (fileIsCreationInPatchContent(patch.patch_content, originalFileName ?? file)) {\n return true;\n }\n\n const base = patch.base_generation;\n if (base && base !== currentGenSha) {\n const reachable =\n (await this.git.commitExists(base)) || (await this.git.treeExists(base));\n if (!reachable) {\n if (!warnedGens.has(base)) {\n warnedGens.add(base);\n warnings.push(\n `Base generation ${base.slice(0, 7)} is unreachable (shallow clone or pruned history). ` +\n `Treating affected files as user-owned to avoid silent data loss. ` +\n `Run \\`git fetch --unshallow\\` or avoid \\`git gc --prune\\` to restore full history.`\n );\n }\n return true;\n }\n return (await this.git.showFile(base, originalFileName ?? file)) === null;\n }\n\n return (await this.git.showFile(currentGenSha, originalFileName ?? file)) === null;\n }\n}\n\n/**\n * Returns true if `file`'s diff section in `patchContent` starts with\n * `--- /dev/null`, meaning the patch introduces this file (user creation).\n *\n * Pure parser — no git access. Used as a legacy-safe fallback when\n * `patch.user_owned` is absent or cleared.\n */\nexport function fileIsCreationInPatchContent(patchContent: string, file: string): boolean {\n const lines = patchContent.split(\"\\n\");\n let inFileSection = false;\n for (const line of lines) {\n if (line.startsWith(\"diff --git \")) {\n inFileSection = line.includes(` b/${file}`) || line.endsWith(` b/${file}`);\n continue;\n }\n if (inFileSection && line.startsWith(\"--- \")) {\n return line === \"--- /dev/null\";\n }\n }\n return false;\n}\n","import type { ReplayService, ReplayOptions, ReplayPreparation, ReplayReport } from \"../ReplayService.js\";\nimport type { Flow } from \"./Flow.js\";\n\n/**\n * No prior lockfile exists. This run records the initial generation and\n * writes the lockfile. No patch detection or application happens — there's\n * nothing to compare against.\n */\nexport class FirstGenerationFlow implements Flow {\n constructor(private readonly service: ReplayService) {}\n\n async prepare(options?: ReplayOptions): Promise<ReplayPreparation> {\n if (options?.dryRun) {\n // Dry-run may be called on a repo with no commits yet (truly first-gen).\n // `git rev-parse HEAD` fails in that case; fall back to empty string.\n const headSha = await this.service.git\n .exec([\"rev-parse\", \"HEAD\"])\n .then((s) => s.trim())\n .catch(() => \"\");\n return {\n flow: \"first-generation\",\n previousGenerationSha: null,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n kind: \"terminal\",\n flow: \"first-generation\",\n preparedReport: firstGenerationReport(),\n },\n };\n }\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead,\n }\n : undefined;\n\n await this.service.committer.commitGeneration(\"Initial SDK generation\", commitOpts);\n const genRecord = await this.service.committer.createGenerationRecord(commitOpts);\n // Phase 1: in-memory only. Disk save deferred to apply().\n this.service.lockManager.initializeInMemory(genRecord);\n\n return {\n flow: \"first-generation\",\n previousGenerationSha: null,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n kind: \"active\",\n flow: \"first-generation\",\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [],\n revertedCount: 0,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options,\n },\n };\n }\n\n async apply(_prep: ReplayPreparation): Promise<ReplayReport> {\n // Save the in-memory lockfile to disk. Matches today's behavior of\n // `lockManager.initialize(genRecord)` which internally calls save().\n // No replay commit in first-gen — the lockfile file lands untracked\n // and is committed by the next cycle's [fern-replay] commit.\n this.service.lockManager.save();\n return firstGenerationReport();\n }\n}\n\n/**\n * Empty report shape returned by both the dry-run terminal and the active\n * apply path. Defined here (not on the service) because both this flow's\n * prepare and apply construct it identically.\n */\nexport function firstGenerationReport(): ReplayReport {\n return {\n flow: \"first-generation\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: [],\n };\n}\n","import { LockfileNotFoundError } from \"../LockfileManager.js\";\nimport type { ApplyOptions, ReplayService, ReplayOptions, ReplayPreparation, ReplayReport } from \"../ReplayService.js\";\nimport type { Flow } from \"./Flow.js\";\n\n/**\n * `--no-replay` mode: commit the generation, set the replay-skipped marker\n * in the lockfile, return early. The next normal run sees the marker and\n * skips revert detection in pre-rebase (patches are stale-base by definition\n * and haven't been applied).\n */\nexport class SkipApplicationFlow implements Flow {\n constructor(private readonly service: ReplayService) {}\n\n async prepare(options?: ReplayOptions): Promise<ReplayPreparation> {\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead,\n }\n : undefined;\n\n await this.service.committer.commitGeneration(\"Update SDK (replay skipped)\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n await this.service.cleanupStaleConflictMarkers();\n\n const genRecord = await this.service.committer.createGenerationRecord(commitOpts);\n\n let previousGenerationSha: string | null = null;\n try {\n const lock = this.service.lockManager.read();\n previousGenerationSha = lock.current_generation ?? null;\n this.service.lockManager.addGeneration(genRecord);\n } catch (error) {\n if (error instanceof LockfileNotFoundError) {\n this.service.lockManager.initializeInMemory(genRecord);\n } else {\n throw error;\n }\n }\n\n this.service.lockManager.setReplaySkippedAt(new Date().toISOString());\n\n return {\n flow: \"skip-application\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n kind: \"active\",\n flow: \"skip-application\",\n patchesToApply: [],\n newPatchIds: new Set(),\n detectorWarnings: [],\n revertedCount: 0,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options,\n },\n };\n }\n\n async apply(_prep: ReplayPreparation, options?: ApplyOptions): Promise<ReplayReport> {\n this.service.lockManager.save();\n const credentialWarnings = [...this.service.lockManager.warnings];\n\n // Commit the lockfile update so it's pushed with the branch.\n // Without this, the marker and generation record stay in the\n // working tree and are lost when GithubStep pushes.\n if (!options?.stageOnly) {\n await this.service.committer.commitReplay(0);\n } else {\n await this.service.committer.stageAll();\n }\n\n return {\n flow: \"skip-application\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: [],\n warnings: credentialWarnings.length > 0 ? credentialWarnings : undefined,\n };\n }\n}\n","import type {\n ApplyOptions,\n ReplayService,\n ReplayOptions,\n ReplayPreparation,\n ReplayReport,\n} from \"../ReplayService.js\";\nimport { assertActive, computeCommitBuckets } from \"../ReplayService.js\";\nimport type { ReplayResult } from \"../types.js\";\nimport type { Flow } from \"./Flow.js\";\n\n/**\n * Lockfile exists with zero tracked patches. Only newly detected patches\n * apply. Simpler than NormalRegeneration because there's no pre-rebase work\n * (no existing patches to refresh).\n */\nexport class NoPatchesFlow implements Flow {\n constructor(private readonly service: ReplayService) {}\n\n async prepare(options?: ReplayOptions): Promise<ReplayPreparation> {\n const preLock = this.service.lockManager.read();\n const previousGenerationSha = preLock.current_generation ?? null;\n\n let { patches: newPatches, revertedPatchIds } = await this.service.detector.detectNewPatches();\n // Snapshot of warnings available at detection time. Re-merged with\n // service-level warnings (populated during rebase) when the final report\n // is built in phase 2.\n const detectorWarnings = [...this.service.detector.warnings];\n\n if (options?.dryRun) {\n const dryRunWarnings = [...detectorWarnings, ...this.service.warnings];\n const preparedReport: ReplayReport = {\n flow: \"no-patches\",\n patchesDetected: newPatches.length,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n patchesReverted: revertedPatchIds.length,\n conflicts: [],\n wouldApply: newPatches,\n warnings: dryRunWarnings.length > 0 ? dryRunWarnings : undefined,\n };\n const headSha = await this.service.git\n .exec([\"rev-parse\", \"HEAD\"])\n .then((s) => s.trim())\n .catch(() => \"\");\n return {\n flow: \"no-patches\",\n previousGenerationSha,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n kind: \"terminal\",\n flow: \"no-patches\",\n preparedReport,\n },\n };\n }\n\n // Pre-apply absorption: drop patches whose net customer effect (from\n // currentGen → HEAD) on all of their files is empty. This mirrors the\n // empty-diff branch of preGenerationRebase which runs only on the\n // normal-regeneration path — without this, flows diverge when the\n // applicator cannot fully cancel a create+delete sequence (parity\n // with normal-regen's revert-detection path).\n {\n const preCurrentGen = preLock.current_generation;\n const uniqueFiles = [...new Set(newPatches.flatMap((p) => p.files))];\n const absorbedFiles = new Set<string>();\n for (const file of uniqueFiles) {\n const diff = await this.service.git\n .exec([\"diff\", preCurrentGen, \"HEAD\", \"--\", file])\n .catch(() => null);\n if (diff !== null && !diff.trim()) {\n absorbedFiles.add(file);\n }\n }\n if (absorbedFiles.size > 0) {\n newPatches = newPatches.filter(\n (p) => p.files.length === 0 || !p.files.every((f) => absorbedFiles.has(f))\n );\n }\n }\n\n // Remove reverted patches from lockfile (after dry-run check to avoid mutating state)\n for (const id of revertedPatchIds) {\n try {\n this.service.lockManager.removePatch(id);\n } catch {\n // patch may not be in lockfile\n }\n }\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead,\n }\n : undefined;\n\n await this.service.committer.commitGeneration(\"Update SDK\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n await this.service.cleanupStaleConflictMarkers();\n\n const genRecord = await this.service.committer.createGenerationRecord(commitOpts);\n\n // Add generation to lockfile BEFORE applying patches so the applicator\n // can read the current generation's tree hash for rename detection.\n this.service.lockManager.addGeneration(genRecord);\n\n return {\n flow: \"no-patches\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n kind: \"active\",\n flow: \"no-patches\",\n patchesToApply: newPatches,\n newPatchIds: new Set(newPatches.map((p) => p.id)),\n detectorWarnings,\n revertedCount: revertedPatchIds.length,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options,\n },\n };\n }\n\n async apply(prep: ReplayPreparation, options?: ApplyOptions): Promise<ReplayReport> {\n assertActive(prep);\n const newPatches = prep._prepared.patchesToApply;\n const detectorWarnings = prep._prepared.detectorWarnings;\n const genSha = prep._prepared.genSha;\n\n let results: ReplayResult[] = [];\n if (newPatches.length > 0) {\n results = await this.service.applicator.applyPatches(newPatches);\n this.service._lastApplyResults = results;\n\n // Surface \"dropped context line\" warnings — see NormalRegenerationFlow.\n this.service.recordDroppedContextLineWarnings(results);\n\n // Strip conflict markers from conflicting files so the commit is clean.\n this.service.revertConflictingFiles(results);\n\n // Mark conflict patches as unresolved on the patch objects before adding to lockfile.\n for (const result of results) {\n if (result.status === \"conflict\") {\n result.patch.status = \"unresolved\";\n }\n }\n }\n\n // Rebase cleanly applied patches to the current generation.\n // This prevents recurring conflicts on subsequent regenerations.\n const rebaseCounts = await this.service.rebasePatches(results, genSha);\n\n // Save lockfile BEFORE commit — lockfile is source of truth.\n for (const patch of newPatches) {\n if (!rebaseCounts.absorbedPatchIds.has(patch.id)) {\n this.service.lockManager.addPatch(patch);\n }\n }\n this.service.lockManager.save();\n this.service.warnings.push(...this.service.lockManager.warnings);\n\n // Preserve today's L422 guard: when no new patches were detected, neither\n // commitReplay nor stageAll runs. The in-memory `addGeneration` still\n // happened in phase 1; the save just above persisted it.\n if (newPatches.length > 0) {\n if (!options?.stageOnly) {\n // Count only cleanly applied patches for the commit message.\n const appliedCount = results.filter((r) => r.status === \"applied\").length;\n const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, newPatches);\n await this.service.committer.commitReplay(appliedCount, newPatches, undefined, { buckets });\n } else {\n await this.service.committer.stageAll();\n }\n }\n\n const warnings = [...detectorWarnings, ...this.service.warnings];\n return this.service.buildReport(\n \"no-patches\",\n newPatches,\n results,\n prep._prepared.optionsSnapshot,\n warnings,\n rebaseCounts,\n undefined,\n prep._prepared.revertedCount,\n );\n }\n}\n","import { isRevertCommit, parseRevertedMessage } from \"../git/CommitDetection.js\";\nimport type {\n ApplyOptions,\n ReplayService,\n ReplayOptions,\n ReplayPreparation,\n ReplayReport,\n} from \"../ReplayService.js\";\nimport { assertActive, computeCommitBuckets } from \"../ReplayService.js\";\nimport type { Flow } from \"./Flow.js\";\n\n/**\n * The full regeneration pipeline:\n *\n * pre-rebase → dedup → detect → apply → strip-markers → post-rebase → save → commit\n *\n * Pre-rebase runs BEFORE `commitGeneration` while HEAD has customer code.\n * Post-rebase runs AFTER `applyPatches` against the new generation tree.\n * The two phases share concerns (revert detection, content refresh, dedup,\n * user-owned classification) but operate on different reference states —\n * unifying them is tracked as FER-10387 (deferred post-GA).\n */\nexport class NormalRegenerationFlow implements Flow {\n constructor(private readonly service: ReplayService) {}\n\n async prepare(options?: ReplayOptions): Promise<ReplayPreparation> {\n const preLock = this.service.lockManager.read();\n const previousGenerationSha = preLock.current_generation ?? null;\n\n if (options?.dryRun) {\n const existingPatches = this.service.lockManager.getPatches();\n const { patches: newPatches, revertedPatchIds: dryRunReverted } =\n await this.service.detector.detectNewPatches();\n const warnings = [...this.service.detector.warnings, ...this.service.warnings];\n const allPatches = [...existingPatches, ...newPatches];\n const preparedReport: ReplayReport = {\n flow: \"normal-regeneration\",\n patchesDetected: allPatches.length,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n patchesReverted: dryRunReverted.length,\n conflicts: [],\n wouldApply: allPatches,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n const headSha = await this.service.git\n .exec([\"rev-parse\", \"HEAD\"])\n .then((s) => s.trim())\n .catch(() => \"\");\n return {\n flow: \"normal-regeneration\",\n previousGenerationSha,\n currentGenerationSha: headSha,\n baseBranchHead: options.baseBranchHead ?? null,\n _prepared: {\n kind: \"terminal\",\n flow: \"normal-regeneration\",\n preparedReport,\n },\n };\n }\n\n // Pre-generation rebase: update stale/modified patches while HEAD has customer code.\n let existingPatches = this.service.lockManager.getPatches();\n const preRebasePatchIds = new Set(existingPatches.map((p) => p.id));\n const preRebaseCounts = await this.service.preGenerationRebase(existingPatches);\n\n // Track which patches preGenRebase removed (user reverted → empty diff).\n // These are needed to reconcile re-detected commits and revert commits after detection.\n const postRebasePatchIds = new Set(this.service.lockManager.getPatches().map((p) => p.id));\n const removedByPreRebase = existingPatches.filter(\n (p) => preRebasePatchIds.has(p.id) && !postRebasePatchIds.has(p.id),\n );\n\n // Dedup patches by content hash after pre-generation rebase.\n //\n // **Consolidation, not preservation.** When two patches have\n // byte-identical `patch_content`, they encode the SAME customer-side\n // delta — neither captures its individual contribution. Applying\n // both back-to-back at the next regen produces duplicated additions\n // (e.g., the same wiring lines spliced into `__all__` twice) and\n // syntactic corruption. The customer's *file* breaks, regardless of\n // how clean the lockfile bookkeeping looks.\n //\n // PR #74's earlier \"preserve both with warning\" rule prioritized\n // provenance preservation over functional correctness — empirically\n // it produced the corruption we're now fixing. Per replay's actual\n // contract (the customer's code stays in the file across N regens,\n // automatically), the right move is to consolidate to ONE canonical\n // patch (the most-recently-seen, by `patchesToCommit` order) and\n // remove the others. Per-commit attribution is recoverable from\n // `git log -- <file>`; corrupted code is not.\n //\n // True duplicates (rebase converging two incremental patches) are\n // a special case of \"same content_hash\" — consolidating them is\n // also right; nothing changes for those tests.\n existingPatches = this.service.lockManager.getPatches();\n const seenHashes = new Map<string, string>();\n for (const p of existingPatches) {\n const priorPatchId = seenHashes.get(p.content_hash);\n if (priorPatchId !== undefined) {\n this.service.lockManager.removePatch(p.id);\n this.service.warnings.push(\n `Consolidated patch ${p.id} (commit ${(p.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into prior patch ${priorPatchId}: byte-identical patch_content. ` +\n `Per-commit attribution preserved in git log; lockfile collapsed to avoid duplicate-apply corruption on next regen.`,\n );\n } else {\n seenHashes.set(p.content_hash, p.id);\n }\n }\n existingPatches = this.service.lockManager.getPatches();\n\n let { patches: newPatches, revertedPatchIds } = await this.service.detector.detectNewPatches();\n // Snapshot of detector warnings; merged with service-level warnings\n // (populated by preGenerationRebase + rebasePatches) when the final\n // report is built in phase 2.\n const detectorWarnings = [...this.service.detector.warnings];\n\n // Post-detection reconciliation for patches removed by preGenerationRebase.\n // When a user does git revert on a tracked customization, preGenRebase sees an\n // empty diff and removes the patch. detectNewPatches then re-detects both the\n // original commit AND the revert commit as new patches (since the lockfile no\n // longer tracks the original). We need to:\n // 1. Filter out re-detected originals (already handled by preGenRebase removal)\n // 2. Filter out their corresponding revert commits\n if (removedByPreRebase.length > 0) {\n const removedOriginalCommits = new Set(removedByPreRebase.map((p) => p.original_commit));\n const removedOriginalMessages = new Set(removedByPreRebase.map((p) => p.original_message));\n\n newPatches = newPatches.filter((p) => {\n // Filter out re-detected originals\n if (removedOriginalCommits.has(p.original_commit)) return false;\n // Filter out revert commits matching removed patches\n if (isRevertCommit(p.original_message)) {\n const revertedMsg = parseRevertedMessage(p.original_message);\n if (revertedMsg && removedOriginalMessages.has(revertedMsg)) return false;\n }\n return true;\n });\n }\n\n // Remove reverted patches from lockfile and filter from existing\n for (const id of revertedPatchIds) {\n try {\n this.service.lockManager.removePatch(id);\n } catch {\n // patch may not be in lockfile\n }\n }\n const revertedSet = new Set(revertedPatchIds);\n existingPatches = existingPatches.filter((p) => !revertedSet.has(p.id));\n\n const allPatches = [...existingPatches, ...newPatches];\n\n const commitOpts = options\n ? {\n cliVersion: options.cliVersion ?? \"unknown\",\n generatorVersions: options.generatorVersions ?? {},\n baseBranchHead: options.baseBranchHead,\n }\n : undefined;\n\n await this.service.committer.commitGeneration(\"Update SDK\", commitOpts);\n\n // Clean up stale conflict markers from a previous crashed run.\n // HEAD is now the [fern-generated] commit with clean generated content.\n await this.service.cleanupStaleConflictMarkers();\n\n const genRecord = await this.service.committer.createGenerationRecord(commitOpts);\n\n // Add generation to lockfile BEFORE applying patches so the applicator\n // can read the current generation's tree hash for rename detection.\n this.service.lockManager.addGeneration(genRecord);\n\n return {\n flow: \"normal-regeneration\",\n previousGenerationSha,\n currentGenerationSha: genRecord.commit_sha,\n baseBranchHead: options?.baseBranchHead ?? null,\n _prepared: {\n kind: \"active\",\n flow: \"normal-regeneration\",\n patchesToApply: allPatches,\n newPatchIds: new Set(newPatches.map((p) => p.id)),\n preRebaseCounts,\n detectorWarnings,\n revertedCount: revertedPatchIds.length,\n genSha: genRecord.commit_sha,\n optionsSnapshot: options,\n },\n };\n }\n\n async apply(prep: ReplayPreparation, options?: ApplyOptions): Promise<ReplayReport> {\n assertActive(prep);\n const allPatches = prep._prepared.patchesToApply;\n const newPatchIds = prep._prepared.newPatchIds;\n const detectorWarnings = prep._prepared.detectorWarnings;\n const genSha = prep._prepared.genSha;\n\n const results = await this.service.applicator.applyPatches(allPatches);\n this.service._lastApplyResults = results;\n\n // Surface \"dropped context line\" warnings — lines that appeared as\n // unchanged context in customer's THEIRS but were silently deleted by\n // the new generator output. diff3 sided with the deletion correctly,\n // but the customer should know so they can re-add intentionally-kept\n // lines if needed. See ThreeWayMerge.computeDroppedContextLines.\n this.service.recordDroppedContextLineWarnings(results);\n\n // Strip conflict markers from conflicting files so the commit is clean.\n // Keeps the Generated (OURS) side, preserving clean patches' changes.\n this.service.revertConflictingFiles(results);\n\n // Mark conflict patches as unresolved on the patch objects before adding to lockfile.\n // For new patches, this object mutation is what persists — they're appended to\n // the lockfile via addPatch() below, carrying the status through.\n for (const result of results) {\n if (result.status === \"conflict\") {\n result.patch.status = \"unresolved\";\n }\n }\n\n // Rebase cleanly applied patches to the current generation.\n const rebaseCounts = await this.service.rebasePatches(results, genSha);\n\n // Save lockfile BEFORE commit — lockfile is source of truth.\n const newPatches = allPatches.filter((p) => newPatchIds.has(p.id));\n for (const patch of newPatches) {\n if (!rebaseCounts.absorbedPatchIds.has(patch.id)) {\n this.service.lockManager.addPatch(patch);\n }\n }\n\n // Also mark existing (non-new) conflict patches as unresolved in the lockfile.\n // This is a DISTINCT mutation path from the object mutation above — existing\n // patches are already in the lockfile, and we need `updatePatch(id, {status})`\n // to flag them. The try/catch handles the new-patch case where the id is not\n // yet in the lockfile (object mutation above already set the status).\n for (const result of results) {\n if (result.status === \"conflict\") {\n try {\n this.service.lockManager.markPatchUnresolved(result.patch.id);\n } catch {\n // New patches already have status set via the object mutation above\n }\n }\n }\n\n this.service.lockManager.save();\n this.service.warnings.push(...this.service.lockManager.warnings);\n\n if (options?.stageOnly) {\n await this.service.committer.stageAll();\n } else {\n // Always commit to persist the lockfile (which tracks unresolved patches).\n // Count only cleanly applied patches for the commit message.\n const appliedCount = results.filter((r) => r.status === \"applied\").length;\n const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, allPatches);\n await this.service.committer.commitReplay(appliedCount, allPatches, undefined, { buckets });\n }\n\n const warnings = [...detectorWarnings, ...this.service.warnings];\n return this.service.buildReport(\n \"normal-regeneration\",\n allPatches,\n results,\n prep._prepared.optionsSnapshot,\n warnings,\n rebaseCounts,\n prep._prepared.preRebaseCounts,\n prep._prepared.revertedCount,\n );\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { parse, stringify } from \"yaml\";\nimport type { GitClient } from \"./git/GitClient.js\";\nimport type { LockfileManager } from \"./LockfileManager.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { isBinaryFile } from \"./shared/binary.js\";\nimport type { CustomizationsConfig, StoredPatch } from \"./types.js\";\n\nexport interface MigrationAnalysis {\n /** Files in .fernignore that have git commit history (can be tracked by Replay) */\n trackedByBoth: Array<{ file: string; commit: string }>;\n /** Files in .fernignore but NO recent commit history found after last generation */\n fernignoreOnly: string[];\n /** Commits found that AREN'T in .fernignore (inline edits to generated files) */\n commitsOnly: StoredPatch[];\n /** Synthetic patches created for .fernignore files that differ from pristine generation */\n syntheticPatches: StoredPatch[];\n}\n\nexport interface MigrationResult {\n patchesCreated: number;\n filesSkipped: string[];\n warnings: string[];\n}\n\nexport class FernignoreMigrator {\n private git: GitClient;\n private lockManager: LockfileManager;\n private outputDir: string;\n\n constructor(git: GitClient, lockManager: LockfileManager, outputDir: string) {\n this.git = git;\n this.lockManager = lockManager;\n this.outputDir = outputDir;\n }\n\n fernignoreExists(): boolean {\n return existsSync(join(this.outputDir, \".fernignore\"));\n }\n\n readFernignorePatterns(): string[] {\n const fernignorePath = join(this.outputDir, \".fernignore\");\n if (!existsSync(fernignorePath)) {\n return [];\n }\n const content = readFileSync(fernignorePath, \"utf-8\");\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n }\n\n /** Analyze .fernignore patterns vs git history. Creates synthetic patches for files differing from pristine generation. */\n async analyzeMigration(): Promise<MigrationAnalysis> {\n const patterns = this.readFernignorePatterns();\n const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);\n const { patches } = await detector.detectNewPatches();\n\n const trackedByBoth: Array<{ file: string; commit: string }> = [];\n const fernignoreOnly: string[] = [];\n const commitsOnly: StoredPatch[] = [];\n const syntheticPatches: StoredPatch[] = [];\n\n // Check each fernignore pattern against recent patches\n for (const pattern of patterns) {\n const matchingPatch = patches.find((p) => p.files.some((f) => minimatch(f, pattern) || f === pattern));\n if (matchingPatch) {\n trackedByBoth.push({\n file: pattern,\n commit: matchingPatch.original_commit\n });\n } else {\n fernignoreOnly.push(pattern);\n }\n }\n\n // For fernignore-only patterns, try to create synthetic patches\n // by diffing current file state against pristine generation tree\n const lock = this.lockManager.read();\n const currentGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n\n if (currentGen && fernignoreOnly.length > 0) {\n const resolvedFiles = await this.resolvePatterns(fernignoreOnly);\n const remainingFernignoreOnly: string[] = [];\n\n for (const { pattern, files } of resolvedFiles) {\n const patchFiles: string[] = [];\n const diffParts: string[] = [];\n\n for (const filePath of files) {\n const pristine = await this.git.showFile(currentGen.tree_hash, filePath);\n const currentContent = this.readFileContent(filePath);\n\n if (currentContent === null) {\n // File in .fernignore but not on disk — nothing to track\n continue;\n }\n\n if (pristine === null) {\n // File doesn't exist in generation tree — it's a wholly new file\n patchFiles.push(filePath);\n diffParts.push(this.createNewFileDiff(filePath, currentContent));\n } else if (pristine !== currentContent) {\n // File differs from pristine — user has customized it\n patchFiles.push(filePath);\n diffParts.push(this.createFileDiff(filePath, pristine, currentContent));\n }\n // If pristine === currentContent, file is unchanged — skip\n }\n\n if (patchFiles.length > 0) {\n const patchContent = diffParts.join(\"\\n\");\n const contentHash = `sha256:${createHash(\"sha256\").update(patchContent).digest(\"hex\")}`;\n\n // Snapshot THEIRS from the customer's working tree (the\n // diff is pristine → currentContent on disk). Skip\n // binary files (utf-8 read of binary content is lossy).\n const theirsSnapshot: Record<string, string> = {};\n for (const filePath of patchFiles) {\n if (isBinaryFile(filePath)) continue;\n const c = this.readFileContent(filePath);\n if (c != null) theirsSnapshot[filePath] = c;\n }\n\n syntheticPatches.push({\n id: `patch-fernignore-${createHash(\"sha256\").update(pattern).digest(\"hex\").slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: currentGen.commit_sha,\n original_message: `[fernignore-migration] Customizations for ${pattern}`,\n original_author: \"Fern Replay <replay@buildwithfern.com>\",\n base_generation: currentGen.commit_sha,\n files: patchFiles,\n patch_content: patchContent,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {}),\n // Synthetic patches captured from .fernignore-protected files\n // are user-owned by definition — the customer's content\n // diverges from the generator's pristine output, and the\n // generator never produced this divergent content. Without\n // this flag, removing the file from .fernignore later (so\n // it leaves the protection check in `isFileUserOwned`) would\n // expose the patch to absorption on the next regen,\n // silently losing the customization.\n user_owned: true\n });\n\n trackedByBoth.push({\n file: pattern,\n commit: `synthetic (differs from generated)`\n });\n } else {\n // No diff found — file matches generated output or doesn't exist\n remainingFernignoreOnly.push(pattern);\n }\n }\n\n // Replace fernignoreOnly with only truly untrackable patterns\n fernignoreOnly.length = 0;\n fernignoreOnly.push(...remainingFernignoreOnly);\n }\n\n // Find patches that touch files NOT in .fernignore\n for (const patch of patches) {\n const hasUnprotectedFiles = patch.files.some((f) => !patterns.some((p) => minimatch(f, p) || f === p));\n if (hasUnprotectedFiles) {\n commitsOnly.push(patch);\n }\n }\n\n return { trackedByBoth, fernignoreOnly, commitsOnly, syntheticPatches };\n }\n\n private async resolvePatterns(patterns: string[]): Promise<Array<{ pattern: string; files: string[] }>> {\n const allFiles = (await this.git.exec([\"ls-files\"])).trim().split(\"\\n\").filter(Boolean);\n const results: Array<{ pattern: string; files: string[] }> = [];\n\n for (const pattern of patterns) {\n const matching = allFiles.filter(\n (f) => minimatch(f, pattern) || f === pattern || f.startsWith(pattern + \"/\")\n );\n results.push({ pattern, files: matching.length > 0 ? matching : [pattern] });\n }\n\n return results;\n }\n\n private readFileContent(filePath: string): string | null {\n const fullPath = join(this.outputDir, filePath);\n if (!existsSync(fullPath)) {\n return null;\n }\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n return null;\n }\n return readFileSync(fullPath, \"utf-8\");\n } catch {\n return null;\n }\n }\n\n private createNewFileDiff(filePath: string, content: string): string {\n const lines = content.split(\"\\n\");\n const hunks = lines.map((l) => `+${l}`).join(\"\\n\");\n return [\n `diff --git a/${filePath} b/${filePath}`,\n \"new file mode 100644\",\n `--- /dev/null`,\n `+++ b/${filePath}`,\n `@@ -0,0 +1,${lines.length} @@`,\n hunks\n ].join(\"\\n\");\n }\n\n private createFileDiff(filePath: string, pristine: string, current: string): string {\n const oldLines = pristine.split(\"\\n\");\n const newLines = current.split(\"\\n\");\n // Simple full-file replacement diff — not optimal but correct\n const removals = oldLines.map((l) => `-${l}`).join(\"\\n\");\n const additions = newLines.map((l) => `+${l}`).join(\"\\n\");\n return [\n `diff --git a/${filePath} b/${filePath}`,\n `--- a/${filePath}`,\n `+++ b/${filePath}`,\n `@@ -1,${oldLines.length} +1,${newLines.length} @@`,\n removals,\n additions\n ].join(\"\\n\");\n }\n\n async migrate(): Promise<MigrationResult> {\n const analysis = await this.analyzeMigration();\n const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);\n const { patches } = await detector.detectNewPatches();\n\n const warnings: string[] = [];\n let patchesCreated = 0;\n\n // Add all detected patches to lockfile\n for (const patch of patches) {\n this.lockManager.addPatch(patch);\n patchesCreated++;\n }\n\n if (patchesCreated > 0) {\n this.lockManager.save();\n }\n\n // Warn about fernignore-only files\n for (const file of analysis.fernignoreOnly) {\n warnings.push(\n `${file}: in .fernignore but no commit history found. Commit this file or keep in .fernignore as fallback.`\n );\n }\n\n return {\n patchesCreated,\n filesSkipped: analysis.fernignoreOnly,\n warnings\n };\n }\n\n movePatternsToReplayYml(patterns: string[]): void {\n const replayYmlPath = join(this.outputDir, \".fern\", \"replay.yml\");\n let config: CustomizationsConfig = {};\n\n if (existsSync(replayYmlPath)) {\n const content = readFileSync(replayYmlPath, \"utf-8\");\n config = (parse(content) as CustomizationsConfig) ?? {};\n }\n\n const existing = config.exclude ?? [];\n const merged = [...new Set([...existing, ...patterns])];\n config.exclude = merged;\n\n const dir = dirname(replayYmlPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(replayYmlPath, stringify(config, { lineWidth: 0 }), \"utf-8\");\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { FernignoreMigrator, type MigrationAnalysis } from \"../FernignoreMigrator.js\";\nimport { isGenerationCommit, isReplayCommit } from \"../git/CommitDetection.js\";\nimport { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport type { CommitInfo, StoredPatch } from \"../types.js\";\n\nexport interface BootstrapOptions {\n /** Log what would happen but don't modify anything */\n dryRun?: boolean;\n /** How to handle .fernignore: \"migrate\" moves patterns to replay.yml, \"delete\" removes it, \"skip\" leaves it */\n fernignoreAction?: \"migrate\" | \"delete\" | \"skip\";\n /** Maximum number of commits to scan for generation history (default: 500) */\n maxCommitsToScan?: number;\n /** Allow overwriting an existing lockfile */\n force?: boolean;\n /** When true, scan git history for existing patches. Default: false (clean start with 0 patches). */\n importHistory?: boolean;\n}\n\nexport interface BootstrapResult {\n /** The generation commit used as baseline, or null if none found */\n generationCommit: CommitInfo | null;\n /** Number of customization patches detected */\n patchesDetected: number;\n /** Number of patches written to lockfile */\n patchesCreated: number;\n /** The detected patches (for dry-run inspection) */\n patches: StoredPatch[];\n /** .fernignore patterns found, if any */\n fernignorePatterns: string[];\n /** .fernignore migration analysis, if .fernignore exists */\n fernignoreAnalysis?: MigrationAnalysis;\n /** Whether .fernignore was updated to protect replay files */\n fernignoreUpdated: boolean;\n /** Warnings about edge cases */\n warnings: string[];\n /** Number of older generation commits that were skipped (stale commits ignored) */\n staleGenerationsSkipped: number;\n /** The generation commit SHA used as cutoff for patch detection */\n scannedSinceGeneration: string;\n}\n\n/**\n * Bootstrap Replay for an existing SDK repository.\n *\n * Scans git history to find all generation commits, identifies\n * user customization patches between them, and creates the initial replay.lock.\n *\n * This is a one-time migration step for SDKs that existed before Replay.\n */\nexport async function bootstrap(outputDir: string, options?: BootstrapOptions): Promise<BootstrapResult> {\n const git = new GitClient(outputDir);\n const lockManager = new LockfileManager(outputDir);\n const maxCommits = options?.maxCommitsToScan ?? 500;\n const warnings: string[] = [];\n\n // Check for existing lockfile\n if (lockManager.exists() && !options?.force) {\n return {\n generationCommit: null,\n patchesDetected: 0,\n patchesCreated: 0,\n patches: [],\n fernignorePatterns: [],\n fernignoreUpdated: false,\n warnings: [\"Replay lockfile already exists. Use --force to overwrite.\"],\n staleGenerationsSkipped: 0,\n scannedSinceGeneration: \"\"\n };\n }\n\n // 1. Find ALL generation commits (newest first, excluding replay commits)\n const genCommits = await findAllGenerationCommits(git, maxCommits);\n\n if (genCommits.length === 0) {\n return {\n generationCommit: null,\n patchesDetected: 0,\n patchesCreated: 0,\n patches: [],\n fernignorePatterns: [],\n fernignoreUpdated: false,\n warnings: [\n \"No generation commits found in the last \" +\n maxCommits +\n \" commits. \" +\n \"Run 'fern generate' first to establish a baseline.\"\n ],\n staleGenerationsSkipped: 0,\n scannedSinceGeneration: \"\"\n };\n }\n\n const latestGen = genCommits[0]!;\n\n // 2. Set up in-memory lockfile (don't write to disk yet — we may be in dry-run mode)\n // For clean start (no importHistory), use HEAD as current_generation so that\n // the next fern generate detects 0 old commits. When importing history, use\n // the actual generation commit as the base for patch detection.\n const anchorSha = options?.importHistory ? latestGen.sha : (await git.exec([\"rev-parse\", \"HEAD\"])).trim();\n const treeHash = await git.getTreeHash(anchorSha);\n const genRecord = {\n commit_sha: anchorSha,\n tree_hash: treeHash,\n timestamp: new Date().toISOString(),\n cli_version: \"unknown\",\n generator_versions: {} as Record<string, string>\n };\n\n lockManager.initializeInMemory(genRecord);\n\n // 3. Scan for user patches (only when importing history)\n const patches: StoredPatch[] = options?.importHistory ? await findAllUserPatches(git, genCommits) : [];\n\n // 4. Handle .fernignore if present (only when importing history)\n const migrator = new FernignoreMigrator(git, lockManager, outputDir);\n const fernignorePatterns = migrator.readFernignorePatterns();\n let fernignoreAnalysis: MigrationAnalysis | undefined;\n\n if (options?.importHistory && migrator.fernignoreExists() && fernignorePatterns.length > 0) {\n fernignoreAnalysis = await migrator.analyzeMigration();\n\n // Add synthetic patches from .fernignore analysis\n if (fernignoreAnalysis.syntheticPatches.length > 0) {\n patches.push(...fernignoreAnalysis.syntheticPatches);\n }\n\n if (fernignoreAnalysis.fernignoreOnly.length > 0) {\n for (const file of fernignoreAnalysis.fernignoreOnly) {\n warnings.push(\n `${file}: in .fernignore but no recent commits found since last generation. ` +\n \"File may be stale, matches generated output, or does not exist. No customization to track.\"\n );\n }\n }\n }\n\n // In dry-run mode, don't persist anything\n if (options?.dryRun) {\n return {\n generationCommit: latestGen,\n patchesDetected: patches.length,\n patchesCreated: 0,\n patches,\n fernignorePatterns,\n fernignoreAnalysis,\n fernignoreUpdated: false,\n warnings,\n staleGenerationsSkipped: genCommits.length - 1,\n scannedSinceGeneration: latestGen.sha\n };\n }\n\n // 5. Persist patches to lockfile\n for (const patch of patches) {\n lockManager.addPatch(patch);\n }\n lockManager.save();\n\n // 6. Ensure .fernignore protects replay files from generation wipe\n const fernignoreUpdated = ensureFernignoreEntries(outputDir);\n\n // 7. Ensure .gitattributes marks replay.lock as generated (collapses diff in GitHub PRs)\n ensureGitattributesEntries(outputDir);\n\n // 8. Handle .fernignore migration\n if (migrator.fernignoreExists() && fernignorePatterns.length > 0) {\n const action = options?.fernignoreAction ?? \"skip\";\n if (action === \"migrate\") {\n // Move truly untrackable patterns (no diff from generated) to replay.yml exclude list\n const patternsToExclude = fernignoreAnalysis?.fernignoreOnly ?? [];\n if (patternsToExclude.length > 0) {\n migrator.movePatternsToReplayYml(patternsToExclude);\n }\n }\n }\n\n return {\n generationCommit: latestGen,\n patchesDetected: patches.length,\n patchesCreated: patches.length,\n patches,\n fernignorePatterns,\n fernignoreAnalysis,\n fernignoreUpdated,\n warnings,\n staleGenerationsSkipped: genCommits.length - 1,\n scannedSinceGeneration: latestGen.sha\n };\n}\n\nasync function findAllGenerationCommits(git: GitClient, maxCommits: number): Promise<CommitInfo[]> {\n const log = await git.exec([\"log\", \"--format=%H%x00%an%x00%ae%x00%s\", `-${maxCommits}`]);\n\n if (!log.trim()) {\n return [];\n }\n\n const genCommits: CommitInfo[] = [];\n for (const line of log.trim().split(\"\\n\")) {\n if (!line) continue;\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n const commit: CommitInfo = { sha, authorName, authorEmail, message };\n if (isGenerationCommit(commit) && !isReplayCommit(commit)) {\n genCommits.push(commit);\n }\n }\n\n return genCommits;\n}\n\nasync function findAllUserPatches(\n git: GitClient,\n genCommits: CommitInfo[] // newest first\n): Promise<StoredPatch[]> {\n const patches: StoredPatch[] = [];\n const seenHashes = new Set<string>();\n\n // Only scan since the LAST (most recent) generation commit to HEAD\n // This ignores \"stale\" commits that were regenerated over before the customer activated replay\n const latestGen = genCommits[0]!;\n const recentPatches = await extractUserPatches(git, latestGen.sha, \"HEAD\", latestGen.sha, seenHashes);\n patches.push(...recentPatches);\n\n return patches;\n}\n\nasync function extractUserPatches(\n git: GitClient,\n fromSha: string,\n toRef: string,\n baseGeneration: string,\n seenHashes: Set<string>\n): Promise<StoredPatch[]> {\n const log = await git.exec([\"log\", \"--format=%H%x00%an%x00%ae%x00%s\", `${fromSha}..${toRef}`]);\n\n if (!log.trim()) {\n return [];\n }\n\n const commits = parseGitLog(log);\n const patches: StoredPatch[] = [];\n\n // Process in reverse (oldest first) for chronological order\n for (const commit of commits.reverse()) {\n if (isGenerationCommit(commit)) continue;\n\n const parents = await git.getCommitParents(commit.sha);\n if (parents.length > 1) continue;\n\n const patchContent = await git.formatPatch(commit.sha);\n const contentHash = computeContentHash(patchContent);\n\n if (seenHashes.has(contentHash)) continue;\n seenHashes.add(contentHash);\n\n const filesOutput = await git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n\n patches.push({\n id: `patch-${commit.sha.slice(0, 8)}`,\n content_hash: contentHash,\n original_commit: commit.sha,\n original_message: commit.message,\n original_author: `${commit.authorName} <${commit.authorEmail}>`,\n base_generation: baseGeneration,\n files: filesOutput.trim().split(\"\\n\").filter(Boolean),\n patch_content: patchContent\n });\n }\n\n return patches;\n}\n\nfunction parseGitLog(log: string): CommitInfo[] {\n return log\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => {\n const [sha, authorName, authorEmail, message] = line.split(\"\\0\");\n return { sha, authorName, authorEmail, message };\n });\n}\n\nconst REPLAY_FERNIGNORE_ENTRIES = [\".fern/replay.lock\", \".fern/replay.yml\", \".gitattributes\"];\n\nfunction ensureFernignoreEntries(outputDir: string): boolean {\n const fernignorePath = join(outputDir, \".fernignore\");\n let content = \"\";\n\n if (existsSync(fernignorePath)) {\n content = readFileSync(fernignorePath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const entry of REPLAY_FERNIGNORE_ENTRIES) {\n if (!lines.some((line) => line.trim() === entry)) {\n toAdd.push(entry);\n }\n }\n\n if (toAdd.length === 0) {\n return false;\n }\n\n if (content && !content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n content += toAdd.join(\"\\n\") + \"\\n\";\n writeFileSync(fernignorePath, content, \"utf-8\");\n return true;\n}\n\nconst GITATTRIBUTES_ENTRIES = [\".fern/replay.lock linguist-generated=true\"];\n\nfunction ensureGitattributesEntries(outputDir: string): void {\n const gitattributesPath = join(outputDir, \".gitattributes\");\n let content = \"\";\n\n if (existsSync(gitattributesPath)) {\n content = readFileSync(gitattributesPath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const entry of GITATTRIBUTES_ENTRIES) {\n if (!lines.some((line) => line.trim() === entry)) {\n toAdd.push(entry);\n }\n }\n\n if (toAdd.length === 0) {\n return;\n }\n\n if (content && !content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n content += toAdd.join(\"\\n\") + \"\\n\";\n writeFileSync(gitattributesPath, content, \"utf-8\");\n}\n\nfunction computeContentHash(patchContent: string): string {\n const lines = patchContent.split(\"\\n\");\n\n // Strip email wrapper from format-patch output (matches ReplayDetector)\n const diffStart = lines.findIndex((l) => l.startsWith(\"diff --git \"));\n const relevantLines = diffStart > 0 ? lines.slice(diffStart) : lines;\n\n const normalized = relevantLines\n .filter((line) => !line.startsWith(\"index \"))\n .join(\"\\n\")\n .replace(/\\n-- \\n[\\d]+\\.[\\d]+[^\\n]*\\s*$/, \"\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\n}\n","import { minimatch } from \"minimatch\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport type { StoredPatch } from \"../types.js\";\n\nexport interface ForgetOptions {\n /** Don't actually remove, just show what would be removed */\n dryRun?: boolean;\n /** Remove all tracked patches (keep lockfile and generation history) */\n all?: boolean;\n /** Specific patch IDs to remove */\n patchIds?: string[];\n /** Search pattern: file path, glob, or commit message substring */\n pattern?: string;\n}\n\nexport interface DiffStat {\n additions: number;\n deletions: number;\n}\n\nexport interface MatchedPatch {\n id: string;\n message: string;\n files: string[];\n diffstat: DiffStat;\n status?: \"unresolved\" | \"resolving\";\n}\n\nexport interface ForgetResult {\n /** Whether replay is initialized (lockfile exists) */\n initialized: boolean;\n /** Patches that were (or would be in dry-run) removed */\n removed: MatchedPatch[];\n /** Number of patches remaining after removal */\n remaining: number;\n /** True if a search/pattern was given but nothing matched */\n notFound: boolean;\n /** Patch IDs that were specified but don't exist (idempotent mode) */\n alreadyForgotten: string[];\n /** Total patches before removal */\n totalPatches: number;\n /** Warnings (e.g., forgetting patches with conflict markers on disk) */\n warnings: string[];\n /** Matching patches for interactive selection (search/no-arg mode only) */\n matched?: MatchedPatch[];\n}\n\nfunction parseDiffStat(patchContent: string): DiffStat {\n let additions = 0;\n let deletions = 0;\n let inDiffHunk = false;\n for (const line of patchContent.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n inDiffHunk = true;\n continue;\n }\n if (!inDiffHunk) continue;\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n additions++;\n } else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n deletions++;\n }\n }\n return { additions, deletions };\n}\n\nfunction toMatchedPatch(patch: StoredPatch): MatchedPatch {\n return {\n id: patch.id,\n message: patch.original_message,\n files: patch.files,\n diffstat: parseDiffStat(patch.patch_content),\n ...(patch.status ? { status: patch.status } : {}),\n };\n}\n\nfunction matchesPatch(patch: StoredPatch, pattern: string): boolean {\n // File path match: exact or glob\n const fileMatch = patch.files.some(\n (file) => file === pattern || minimatch(file, pattern),\n );\n if (fileMatch) return true;\n\n // Commit message match: case-insensitive substring\n return patch.original_message.toLowerCase().includes(pattern.toLowerCase());\n}\n\nfunction buildWarnings(patches: StoredPatch[]): string[] {\n const warnings: string[] = [];\n for (const patch of patches) {\n if (patch.status === \"resolving\") {\n warnings.push(\n `patch ${patch.id} has conflict markers in these files: ${patch.files.join(\", \")}. ` +\n `Run \\`git checkout -- <files>\\` to restore the generated versions.`,\n );\n } else if (patch.status === \"unresolved\") {\n warnings.push(\n `patch ${patch.id} had unresolved conflicts (files: ${patch.files.join(\", \")}).`,\n );\n }\n }\n return warnings;\n}\n\nconst EMPTY_RESULT: ForgetResult = {\n initialized: false,\n removed: [],\n remaining: 0,\n notFound: false,\n alreadyForgotten: [],\n totalPatches: 0,\n warnings: [],\n};\n\nexport function forget(outputDir: string, options?: ForgetOptions): ForgetResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return { ...EMPTY_RESULT };\n }\n\n const lock = lockManager.read();\n const totalPatches = lock.patches.length;\n\n // --all: remove all patches\n if (options?.all) {\n const removed = lock.patches.map(toMatchedPatch);\n const warnings = buildWarnings(lock.patches);\n\n if (!options.dryRun) {\n for (const patch of lock.patches) {\n lockManager.addForgottenHash(patch.content_hash);\n }\n lockManager.clearPatches();\n lockManager.save();\n }\n\n return {\n initialized: true,\n removed,\n remaining: 0,\n notFound: false,\n alreadyForgotten: [],\n totalPatches,\n warnings,\n };\n }\n\n // Patch ID mode: remove specific patches by ID\n if (options?.patchIds && options.patchIds.length > 0) {\n const removed: MatchedPatch[] = [];\n const alreadyForgotten: string[] = [];\n const patchesToRemove: StoredPatch[] = [];\n\n for (const id of options.patchIds) {\n const patch = lock.patches.find((p) => p.id === id);\n if (patch) {\n removed.push(toMatchedPatch(patch));\n patchesToRemove.push(patch);\n } else {\n alreadyForgotten.push(id);\n }\n }\n\n const warnings = buildWarnings(patchesToRemove);\n\n if (!options.dryRun) {\n for (const patch of patchesToRemove) {\n lockManager.addForgottenHash(patch.content_hash);\n lockManager.removePatch(patch.id);\n }\n lockManager.save();\n }\n\n return {\n initialized: true,\n removed,\n remaining: totalPatches - removed.length,\n notFound: removed.length === 0 && alreadyForgotten.length > 0,\n alreadyForgotten,\n totalPatches,\n warnings,\n };\n }\n\n // Search mode: match by pattern (file path, glob, or commit message)\n if (options?.pattern) {\n const matched = lock.patches\n .filter((p) => matchesPatch(p, options.pattern!))\n .map(toMatchedPatch);\n\n return {\n initialized: true,\n removed: [],\n remaining: totalPatches,\n notFound: matched.length === 0,\n alreadyForgotten: [],\n totalPatches,\n warnings: [],\n matched,\n };\n }\n\n // No argument: return all patches for interactive selection\n return {\n initialized: true,\n removed: [],\n remaining: totalPatches,\n notFound: totalPatches === 0,\n alreadyForgotten: [],\n totalPatches,\n warnings: [],\n matched: lock.patches.map(toMatchedPatch),\n };\n}\n","import { unlinkSync } from \"node:fs\";\nimport { LockfileManager } from \"../LockfileManager.js\";\n\nexport interface ResetOptions {\n /** Don't actually delete, just show what would happen */\n dryRun?: boolean;\n}\n\nexport interface ResetResult {\n /** Whether reset was successful (or would be) */\n success: boolean;\n /** Number of patches that were (or would be) removed */\n patchesRemoved: number;\n /** Whether the lockfile was (or would be) deleted */\n lockfileDeleted: boolean;\n /** True if there was nothing to reset */\n nothingToReset: boolean;\n}\n\nexport function reset(outputDir: string, options?: ResetOptions): ResetResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return {\n success: true,\n patchesRemoved: 0,\n lockfileDeleted: false,\n nothingToReset: true\n };\n }\n\n const lock = lockManager.read();\n const patchCount = lock.patches.length;\n\n if (!options?.dryRun) {\n unlinkSync(lockManager.lockfilePath);\n }\n\n return {\n success: true,\n patchesRemoved: patchCount,\n lockfileDeleted: true,\n nothingToReset: false\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport { ReplayApplicator } from \"../ReplayApplicator.js\";\nimport { isBinaryFile } from \"../shared/binary.js\";\nimport { ReplayCommitter } from \"../ReplayCommitter.js\";\nimport { ReplayDetector } from \"../ReplayDetector.js\";\nimport { computePerPatchDiffWithFallback } from \"../PatchRegionDiff.js\";\n\nexport interface ResolveOptions {\n /** Check for remaining conflict markers before committing. Default: true */\n checkMarkers?: boolean;\n}\n\nexport interface ResolveResult {\n /** Whether the resolve succeeded */\n success: boolean;\n /** Commit SHA of the [fern-replay] commit, if created */\n commitSha?: string;\n /** Reason for failure or current state */\n reason?: string;\n /** Files that have conflict markers */\n unresolvedFiles?: string[];\n /** Phase the command executed */\n phase?: \"applied\" | \"committed\" | \"nothing-to-resolve\";\n /** Number of patches applied to working tree (phase 1) */\n patchesApplied?: number;\n /** Number of patches resolved and committed (phase 2) */\n patchesResolved?: number;\n /** Non-fatal diagnostic messages (e.g., per-patch fallbacks) */\n warnings?: string[];\n}\n\nexport async function resolve(outputDir: string, options?: ResolveOptions): Promise<ResolveResult> {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return { success: false, reason: \"no-lockfile\" };\n }\n\n const lock = lockManager.read();\n if (lock.patches.length === 0) {\n return { success: false, reason: \"no-patches\" };\n }\n\n const git = new GitClient(outputDir);\n const unresolvedPatches = lockManager.getUnresolvedPatches();\n const resolvingPatches = lockManager.getResolvingPatches();\n\n // ---- Phase 1: Apply unresolved patches to working tree ----\n if (unresolvedPatches.length > 0) {\n const applicator = new ReplayApplicator(git, lockManager, outputDir);\n // applyMode: \"resolve\" — preserve conflict markers on disk so the\n // customer sees A's conflicts (instead of having them silently\n // stripped by the intra-loop sanitize that the replay pipeline\n // depends on for clean follow-up patches). See ReplayApplicator\n // applyPatches docstring for the rationale.\n await applicator.applyPatches(unresolvedPatches, { applyMode: \"resolve\" });\n\n const markerFiles = await findConflictMarkerFiles(git);\n\n if (markerFiles.length > 0) {\n // Mark as \"resolving\" so next call knows Phase 1 happened\n for (const patch of unresolvedPatches) {\n lockManager.updatePatch(patch.id, { status: \"resolving\" });\n }\n lockManager.save();\n\n return {\n success: false,\n reason: \"conflicts-applied\",\n unresolvedFiles: markerFiles,\n phase: \"applied\",\n patchesApplied: unresolvedPatches.length\n };\n }\n\n // All patches applied cleanly — fall through to commit phase.\n // Treat these as needing commit (same as resolving patches).\n }\n\n // ---- Phase 1.5: Conflict markers still present ----\n if (options?.checkMarkers !== false) {\n const currentMarkerFiles = await findConflictMarkerFiles(git);\n if (currentMarkerFiles.length > 0) {\n return { success: false, reason: \"unresolved-conflicts\", unresolvedFiles: currentMarkerFiles };\n }\n }\n\n // ---- Phase 2: Commit resolution ----\n // Includes both \"resolving\" patches (from a previous Phase 1 call) and\n // \"unresolved\" patches that applied cleanly (from Phase 1 above).\n const patchesToCommit = [...resolvingPatches, ...unresolvedPatches];\n if (patchesToCommit.length > 0) {\n const currentGen = lock.current_generation;\n const detector = new ReplayDetector(git, lockManager, outputDir);\n const warnings: string[] = [];\n let patchesResolved = 0;\n\n // Two-pass: pass 1 computes per-patch attribution; pass 2 applies\n // it with consolidation when multiple patches end up with byte-\n // identical content (which would otherwise duplicate-apply at the\n // next regen and corrupt the customer's file).\n type PassResult =\n | { kind: \"skip\" }\n | { kind: \"revert\" }\n | { kind: \"apply\"; diff: string; hash: string; hadFallback: boolean; fallbackFiles: string[] };\n\n const pass1: PassResult[] = [];\n for (const patch of patchesToCommit) {\n // Per-patch contribution diff. Using a cumulative\n // `git diff currentGen -- patch.files` would assign byte-\n // identical patch_content to every patch sharing a file —\n // which the consolidation pass below catches, but per-patch\n // attribution (when achievable) preserves better provenance.\n const result = await computePerPatchDiffWithFallback(\n patch,\n (f) => git.showFile(currentGen, f),\n (f) => readFile(join(outputDir, f), \"utf-8\").catch(() => null),\n (files) => git.exec([\"diff\", currentGen, \"--\", ...files]).catch(() => null)\n );\n\n if (result === null) {\n warnings.push(\n `Patch ${patch.id}: cumulative-diff fallback failed for unlocatable files; preserving patch unchanged`\n );\n pass1.push({ kind: \"skip\" });\n continue;\n }\n\n const diff = result.diff;\n if (!diff.trim()) {\n pass1.push({ kind: \"revert\" });\n continue;\n }\n\n const hash = detector.computeContentHash(diff);\n pass1.push({\n kind: \"apply\",\n diff,\n hash,\n hadFallback: result.hadFallback,\n fallbackFiles: result.fallbackFiles,\n });\n }\n\n // Pass 2 setup: identify the LAST occurrence of each content hash —\n // that's the canonical patch (most recent customer intent). Earlier\n // patches with the same hash get consolidated into that one. Per\n // user direction (criterion #5 in the brief): \"consolidate to ONE\n // canonical patch rather than copying cumulative content into all.\"\n const lastIndexByHash = new Map<string, number>();\n for (let i = 0; i < pass1.length; i++) {\n const r = pass1[i]!;\n if (r.kind === \"apply\") lastIndexByHash.set(r.hash, i);\n }\n\n for (let i = 0; i < patchesToCommit.length; i++) {\n const patch = patchesToCommit[i]!;\n const r = pass1[i]!;\n if (r.kind === \"skip\") continue;\n if (r.kind === \"revert\") {\n // Genuine revert: customer dropped this patch entirely.\n lockManager.removePatch(patch.id);\n continue;\n }\n\n // r.kind === \"apply\"\n if (lastIndexByHash.get(r.hash) !== i) {\n // Duplicate of a later patch — consolidate by removing.\n // The customer's contribution survives on the canonical\n // patch (the last one with this hash). Per-commit\n // attribution is recoverable from `git log -- <file>`.\n const canonicalIdx = lastIndexByHash.get(r.hash)!;\n const canonical = patchesToCommit[canonicalIdx]!;\n lockManager.removePatch(patch.id);\n warnings.push(\n `Consolidated patch ${patch.id} (commit ${(patch.original_commit || \"<missing>\").slice(0, 7)}) ` +\n `into patch ${canonical.id} (commit ${(canonical.original_commit || \"<missing>\").slice(0, 7)}): ` +\n `byte-identical patch_content after resolution. Per-commit attribution preserved in git log; ` +\n `lockfile collapsed to avoid duplicate-apply corruption on next regen.`\n );\n continue;\n }\n\n if (r.hadFallback) {\n warnings.push(\n `Patch ${patch.id}: ${r.fallbackFiles.join(\", \")} could not be anchored; cumulative-diff fallback applied for those files`\n );\n }\n\n const changedFiles = r.hadFallback\n ? await getChangedFiles(git, currentGen, patch.files)\n : extractFilesFromDiff(r.diff);\n\n // Capture THEIRS as a snapshot of the customer's resolved file\n // content. This is what THEIRS *means* — the post-customer-edit\n // state. Storing it directly (instead of relying on\n // patch_content's diff to reconstruct it) makes future regens\n // robust to generator structural changes that would invalidate\n // the diff's line anchors.\n const filesForSnapshot = changedFiles.length > 0 ? changedFiles : patch.files;\n const theirsSnapshot: Record<string, string> = {};\n for (const file of filesForSnapshot) {\n if (isBinaryFile(file)) continue;\n const content = await readFile(join(outputDir, file), \"utf-8\").catch(() => null);\n if (content != null) {\n theirsSnapshot[file] = content;\n }\n }\n\n lockManager.markPatchResolved(patch.id, {\n patch_content: r.diff,\n content_hash: r.hash,\n base_generation: currentGen,\n files: filesForSnapshot,\n ...(Object.keys(theirsSnapshot).length > 0 ? { theirs_snapshot: theirsSnapshot } : {})\n });\n patchesResolved++;\n }\n\n lockManager.save();\n\n const committer = new ReplayCommitter(git, outputDir);\n await committer.stageAll();\n const commitSha = await committer.commitReplay(\n lock.patches.length,\n lock.patches,\n \"[fern-replay] Resolved conflicts\"\n );\n\n return {\n success: true,\n commitSha,\n phase: \"committed\",\n patchesResolved,\n warnings: warnings.length > 0 ? warnings : undefined\n };\n }\n\n // ---- No unresolved/resolving patches → legacy behavior ----\n const committer = new ReplayCommitter(git, outputDir);\n await committer.stageAll();\n const commitSha = await committer.commitReplay(lock.patches.length, lock.patches);\n\n return { success: true, commitSha, phase: \"committed\" };\n}\n\nasync function findConflictMarkerFiles(git: GitClient): Promise<string[]> {\n const output = await git.exec([\"grep\", \"-l\", \"<<<<<<<\", \"--\", \".\"]).catch(() => \"\");\n return output.trim() ? output.trim().split(\"\\n\").filter(Boolean) : [];\n}\n\nasync function getChangedFiles(git: GitClient, currentGen: string, files: string[]): Promise<string[]> {\n const filesOutput = await git.exec([\"diff\", \"--name-only\", currentGen, \"--\", ...files]).catch(() => null);\n\n if (!filesOutput || !filesOutput.trim()) return files;\n\n const changed = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !f.startsWith(\".fern/\"));\n\n return changed.length > 0 ? changed : files;\n}\n\n/**\n * Parse `diff --git a/<X> b/<Y>` headers from a unified diff and return the\n * destination paths. For renames, the \"to\" side is preferred. Filters out\n * `.fern/` paths.\n */\nfunction extractFilesFromDiff(unifiedDiff: string): string[] {\n const out = new Set<string>();\n const renameSources = new Set<string>();\n let currentTarget: string | null = null;\n\n for (const line of unifiedDiff.split(\"\\n\")) {\n const headerMatch = line.match(/^diff --git a\\/(.+?) b\\/(.+)$/);\n if (headerMatch) {\n currentTarget = headerMatch[2]!;\n if (!currentTarget.startsWith(\".fern/\")) out.add(currentTarget);\n continue;\n }\n if (currentTarget && line.startsWith(\"rename from \")) {\n renameSources.add(line.slice(\"rename from \".length));\n }\n }\n // Drop rename sources (we want the post-rename path, not the pre-rename path).\n for (const src of renameSources) out.delete(src);\n return Array.from(out);\n}\n","import { LockfileManager } from \"../LockfileManager.js\";\n\nexport interface StatusResult {\n /** Whether replay is initialized (lockfile exists) */\n initialized: boolean;\n /** Total number of generations tracked */\n generationCount: number;\n /** Last generation info, if available */\n lastGeneration: StatusGeneration | undefined;\n /** Tracked customization patches */\n patches: StatusPatch[];\n /** Count of patches with \"unresolved\" or \"resolving\" status */\n unresolvedCount: number;\n /** Exclude patterns from replay.yml */\n excludePatterns: string[];\n}\n\nexport interface StatusPatch {\n /** Patch ID (e.g. \"patch-def45678\") */\n id: string;\n /** \"added\" if patch_content contains \"new file mode\", otherwise \"modified\" */\n type: \"added\" | \"modified\";\n /** Original commit message */\n message: string;\n /** Author name (without email) */\n author: string;\n /** Short SHA of the original commit (7 chars) */\n sha: string;\n /** Files touched by this patch */\n files: string[];\n /** Number of files */\n fileCount: number;\n /** Patch resolution status, if any */\n status?: \"unresolved\" | \"resolving\";\n}\n\nexport interface StatusGeneration {\n /** Short commit SHA (7 chars) */\n sha: string;\n /** Generation timestamp */\n timestamp: string;\n /** CLI version used for generation */\n cliVersion: string;\n /** Generator versions (e.g. { \"fern-java-sdk\": \"3.35.0\" }) */\n generatorVersions: Record<string, string>;\n}\n\nexport function status(outputDir: string): StatusResult {\n const lockManager = new LockfileManager(outputDir);\n\n if (!lockManager.exists()) {\n return {\n initialized: false,\n generationCount: 0,\n lastGeneration: undefined,\n patches: [],\n unresolvedCount: 0,\n excludePatterns: [],\n };\n }\n\n const lock = lockManager.read();\n\n const patches: StatusPatch[] = lock.patches.map((patch) => ({\n id: patch.id,\n type: patch.patch_content.includes(\"new file mode\") ? \"added\" as const : \"modified\" as const,\n message: patch.original_message,\n author: patch.original_author.split(\"<\")[0]?.trim() || \"unknown\",\n sha: patch.original_commit.slice(0, 7),\n files: patch.files,\n fileCount: patch.files.length,\n ...(patch.status ? { status: patch.status } : {}),\n }));\n\n const unresolvedCount = lock.patches.filter(\n (p) => p.status === \"unresolved\" || p.status === \"resolving\"\n ).length;\n\n let lastGeneration: StatusGeneration | undefined;\n const lastGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);\n if (lastGen) {\n lastGeneration = {\n sha: lastGen.commit_sha.slice(0, 7),\n timestamp: lastGen.timestamp,\n cliVersion: lastGen.cli_version,\n generatorVersions: lastGen.generator_versions,\n };\n }\n\n const config = lockManager.getCustomizationsConfig();\n const excludePatterns = config.exclude ?? [];\n\n return {\n initialized: true,\n generationCount: lock.generations.length,\n lastGeneration,\n patches,\n unresolvedCount,\n excludePatterns,\n };\n}\n"],"mappings":"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","names":["spawn","resolve","contextCount","import_promises","import_node_os","import_node_path","content","import_node_path","import_promises","import_node_path","import_node_path","extractFileDiff","reconstructFromGhostPatch","applyPatchToContent","import_promises","import_node_path","merged","GitClient","import_node_fs","import_promises","import_node_path","import_minimatch","import_promises","import_node_os","import_node_path","isDiffLineForFile","rm","resolve","import_minimatch","existingPatches","newPatches","allPatches","readFileAsync","applyPatchToContent","import_node_crypto","import_node_fs","import_node_path","import_minimatch","import_yaml","import_node_crypto","import_node_fs","import_node_path","import_minimatch","import_node_fs","import_promises","import_node_path","committer","commitSha","unifiedDiff"]}
|