@fern-api/replay 0.11.0 → 0.13.0
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/dist/cli.cjs +269 -37
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +269 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -8
- package/dist/index.d.ts +133 -8
- package/dist/index.js +269 -37
- 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/index.ts","../src/credentials.ts","../src/git/CommitDetection.ts","../src/LockfileManager.ts","../src/ReplayDetector.ts","../src/ThreeWayMerge.ts","../src/ReplayApplicator.ts","../src/conflict-utils.ts","../src/ReplayCommitter.ts","../src/ReplayService.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","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 { ReplayService, type ReplayReport, type ReplayOptions, type ConflictDetail, type UnresolvedPatchInfo } 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.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 or reference sensitive files.\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 credentialMatches = scanForCredentials(patch.patch_content);\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\">>,\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\">,\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 { 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): fall back to tree-diff detection.\n const isAncestor = await this.git.isAncestor(lastGen.commit_sha, \"HEAD\");\n if (!isAncestor) {\n return this.detectPatchesViaTreeDiff(lastGen, /* commitKnownMissing */ false);\n }\n\n const log = await this.git.exec([\n \"log\",\n \"--first-parent\",\n \"--format=%H%x00%an%x00%ae%x00%s\",\n `${lastGen.commit_sha}..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 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 ...(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 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 ...(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 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 ...(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 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 });\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 { 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 return {\n content: outputLines.join(\"\\n\"),\n hasConflicts: conflicts.length > 0,\n conflicts\n };\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, 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 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 async applyPatches(patches: StoredPatch[]): Promise<ReplayResult[]> {\n this.resetAccumulator(); // Clear accumulator for this apply cycle\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).\n if (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 /** Populate accumulator after git apply succeeds. */\n private async populateAccumulatorForPatch(\n patch: StoredPatch,\n baseGen: GenerationRecord | undefined,\n currentTreeHash: string\n ): Promise<void> {\n if (!baseGen) return;\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 const theirs = 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 effectiveTheirs = theirs ?? await readFile(join(this.outputDir, resolvedPath), \"utf-8\").catch(() => null);\n if (effectiveTheirs != null) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: effectiveTheirs,\n baseGeneration: patch.base_generation\n });\n }\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\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 await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);\n\n return {\n patch,\n status: \"applied\",\n method: \"git-am\",\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 (apply patch to base using original path)\n if (!ghostReconstructed) {\n theirs = await this.applyPatchToContent(\n base,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir,\n renameSourcePath\n );\n }\n\n // Skip files where THEIRS contains stale conflict markers from a\n // previous crashed run. applyPatchToContent uses git apply --3way\n // internally, which can produce markers when patch context doesn't\n // match. Only skip when the markers are NEW in THEIRS (not in BASE),\n // to avoid false positives from files that legitimately contain\n // marker text (e.g., documentation describing the replay format).\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 return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"stale-conflict-markers\"\n };\n }\n }\n\n // Fall back to accumulator as merge base for incremental patches.\n let useAccumulatorAsMergeBase = false;\n const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);\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 successful merge\n // This allows subsequent patches on the same file to benefit from pre-merge\n // Skip on conflict to prevent poisoning subsequent patches (FER-9525)\n if (effective_theirs != null && !merged.hasConflicts) {\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 { file: resolvedPath, status: \"merged\" };\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\nfunction isBinaryFile(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\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 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(_patchCount: number, patches?: StoredPatch[], message?: string): 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 if (patches && patches.length > 0) {\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 { join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { isRevertCommit, parseRevertedMessage } from \"./git/CommitDetection.js\";\nimport { GitClient } from \"./git/GitClient.js\";\nimport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nimport { ReplayApplicator } from \"./ReplayApplicator.js\";\nimport { ReplayCommitter } from \"./ReplayCommitter.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { stripConflictMarkers } from \"./conflict-utils.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\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 async runReplay(options?: ReplayOptions): Promise<ReplayReport> {\n // Reset per-run state so warnings from prior invocations don't leak.\n this.warnings = [];\n\n if (options?.skipApplication) {\n return this.handleSkipApplication(options);\n }\n\n const flow = this.determineFlow();\n\n switch (flow) {\n case \"first-generation\":\n return this.handleFirstGeneration(options);\n case \"no-patches\":\n return this.handleNoPatchesRegeneration(options);\n case \"normal-regeneration\":\n return this.handleNormalRegeneration(options);\n }\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 async handleFirstGeneration(options?: ReplayOptions): Promise<ReplayReport> {\n if (options?.dryRun) {\n return {\n flow: \"first-generation\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: []\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 this.lockManager.initialize(genRecord);\n\n return {\n flow: \"first-generation\",\n patchesDetected: 0,\n patchesApplied: 0,\n patchesWithConflicts: 0,\n patchesSkipped: 0,\n conflicts: []\n };\n }\n\n /**\n * Skip-application mode: commit the generation and update the lockfile\n * but don't detect or apply patches. Sets a marker so the next normal\n * run skips revert detection in preGenerationRebase().\n */\n private async handleSkipApplication(options?: ReplayOptions): Promise<ReplayReport> {\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 try {\n this.lockManager.read();\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 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 handleNoPatchesRegeneration(options?: ReplayOptions): Promise<ReplayReport> {\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) at buildReport time.\n const detectorWarnings = [...this.detector.warnings];\n\n if (options?.dryRun) {\n const dryRunWarnings = [...detectorWarnings, ...this.warnings];\n return {\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 }\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 preLock = this.lockManager.read();\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 let results: ReplayResult[] = [];\n if (newPatches.length > 0) {\n results = await this.applicator.applyPatches(newPatches);\n this._lastApplyResults = 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, genRecord.commit_sha);\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 if (newPatches.length > 0) {\n if (!options?.stageOnly) {\n // Always commit to persist the lockfile (which may track unresolved patches).\n const appliedCount = results.filter((r) => r.status === \"applied\").length;\n await this.committer.commitReplay(appliedCount, newPatches);\n } else {\n await this.committer.stageAll();\n }\n }\n\n const warnings = [...detectorWarnings, ...this.warnings];\n return this.buildReport(\"no-patches\", newPatches, results, options, warnings, rebaseCounts, undefined, revertedPatchIds.length);\n }\n\n private async handleNormalRegeneration(options?: ReplayOptions): Promise<ReplayReport> {\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 return {\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 }\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 existingPatches = this.lockManager.getPatches();\n const seenHashes = new Set<string>();\n for (const p of existingPatches) {\n if (seenHashes.has(p.content_hash)) {\n this.lockManager.removePatch(p.id);\n } else {\n seenHashes.add(p.content_hash);\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) at buildReport time.\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 const results = await this.applicator.applyPatches(allPatches);\n this._lastApplyResults = 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 (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, genRecord.commit_sha);\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\n // Also mark existing (non-new) conflict patches as unresolved in lockfile.\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 await this.committer.commitReplay(appliedCount, allPatches);\n }\n\n const warnings = [...detectorWarnings, ...this.warnings];\n return this.buildReport(\n \"normal-regeneration\",\n allPatches,\n results,\n options,\n warnings,\n rebaseCounts,\n preRebaseCounts,\n revertedPatchIds.length\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 to deduplicate converging incremental patches.\n const seenContentHashes = new Set<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 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 if (userDiff != null && userDiff.trim()) {\n const newHash = this.detector.computeContentHash(userDiff);\n patch.patch_content = userDiff;\n patch.content_hash = newHash;\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 ? { patch_content: patch.patch_content, content_hash: patch.content_hash }\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 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 // 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 // If another patch already captured this exact diff, this patch\n // is redundant (e.g., incremental patches that both resolve to\n // the same cumulative state after rebase).\n if (seenContentHashes.has(newContentHash)) {\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n seenContentHashes.add(newContentHash);\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 try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash\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 * 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 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 if (patch.base_generation === currentGen) {\n // Content refresh: check if user modified their customization\n // since the last replay commit.\n try {\n const diff = await this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...patch.files])\n .catch(() => null);\n\n if (diff === null) continue;\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 this.lockManager.updatePatch(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n files: newFiles\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 // Compute customer's resolved state relative to current generation\n const diff = await this.git.exec([\"diff\", currentGen, \"HEAD\", \"--\", ...patch.files]).catch(() => null);\n\n // Diff command failed (e.g., invalid SHA) — skip this patch\n if (diff === null) continue;\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\n const newContentHash = this.detector.computeContentHash(diff);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: diff,\n content_hash: newContentHash\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(), 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 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 conflictResults.length > 0\n ? conflictResults.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","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 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 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 });\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 { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport { ReplayApplicator } from \"../ReplayApplicator.js\";\nimport { ReplayCommitter } from \"../ReplayCommitter.js\";\nimport { ReplayDetector } from \"../ReplayDetector.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}\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 await applicator.applyPatches(unresolvedPatches);\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 let patchesResolved = 0;\n\n for (const patch of patchesToCommit) {\n const diff = await git.exec([\"diff\", currentGen, \"--\", ...patch.files]).catch(() => null);\n\n if (!diff || !diff.trim()) {\n // Customer reverted the customization → remove patch entirely\n lockManager.removePatch(patch.id);\n continue;\n }\n\n // Update patch with the customer's resolution\n const newContentHash = detector.computeContentHash(diff);\n const changedFiles = await getChangedFiles(git, currentGen, patch.files);\n\n lockManager.markPatchResolved(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n base_generation: currentGen,\n files: changedFiles\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 };\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","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":["resolve","contextCount","import_node_path","GitClient","reconstructFromGhostPatch","outDir","merged","import_node_fs","import_node_path","import_minimatch","existingPatches","newPatches","warnings","allPatches","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","committer","commitSha"]}
|
|
1
|
+
{"version":3,"sources":["../src/git/GitClient.ts","../src/HybridReconstruction.ts","../src/index.ts","../src/credentials.ts","../src/git/CommitDetection.ts","../src/LockfileManager.ts","../src/ReplayDetector.ts","../src/ThreeWayMerge.ts","../src/ReplayApplicator.ts","../src/conflict-utils.ts","../src/ReplayCommitter.ts","../src/ReplayService.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","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 or reference sensitive files.\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 credentialMatches = scanForCredentials(patch.patch_content);\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\">>,\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\">,\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 { 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 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 ...(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 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 ...(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 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 ...(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 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 });\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 { 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 return {\n content: outputLines.join(\"\\n\"),\n hasConflicts: conflicts.length > 0,\n conflicts\n };\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, 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 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 async applyPatches(patches: StoredPatch[]): Promise<ReplayResult[]> {\n this.resetAccumulator(); // Clear accumulator for this apply cycle\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).\n if (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 /** Populate accumulator after git apply succeeds. */\n private async populateAccumulatorForPatch(\n patch: StoredPatch,\n baseGen: GenerationRecord | undefined,\n currentTreeHash: string\n ): Promise<void> {\n if (!baseGen) return;\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 const theirs = 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 effectiveTheirs = theirs ?? await readFile(join(this.outputDir, resolvedPath), \"utf-8\").catch(() => null);\n if (effectiveTheirs != null) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: effectiveTheirs,\n baseGeneration: patch.base_generation\n });\n }\n }\n } finally {\n await rm(tempDir, { recursive: true }).catch(() => {});\n }\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 await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);\n\n return {\n patch,\n status: \"applied\",\n method: \"git-am\",\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 (apply patch to base using original path)\n if (!ghostReconstructed) {\n theirs = await this.applyPatchToContent(\n base,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir,\n renameSourcePath\n );\n }\n\n // Skip files where THEIRS contains stale conflict markers from a\n // previous crashed run. applyPatchToContent uses git apply --3way\n // internally, which can produce markers when patch context doesn't\n // match. Only skip when the markers are NEW in THEIRS (not in BASE),\n // to avoid false positives from files that legitimately contain\n // marker text (e.g., documentation describing the replay format).\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 return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"stale-conflict-markers\"\n };\n }\n }\n\n // Fall back to accumulator as merge base for incremental patches.\n let useAccumulatorAsMergeBase = false;\n const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);\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 successful merge\n // This allows subsequent patches on the same file to benefit from pre-merge\n // Skip on conflict to prevent poisoning subsequent patches (FER-9525)\n if (effective_theirs != null && !merged.hasConflicts) {\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 { file: resolvedPath, status: \"merged\" };\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\nfunction isBinaryFile(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return BINARY_EXTENSIONS.has(ext);\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 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(_patchCount: number, patches?: StoredPatch[], message?: string): 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 if (patches && patches.length > 0) {\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 { join } from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport { isRevertCommit, parseRevertedMessage } from \"./git/CommitDetection.js\";\nimport { GitClient } from \"./git/GitClient.js\";\nimport { LockfileManager, LockfileNotFoundError } from \"./LockfileManager.js\";\nimport { ReplayApplicator } from \"./ReplayApplicator.js\";\nimport { ReplayCommitter } from \"./ReplayCommitter.js\";\nimport { ReplayDetector } from \"./ReplayDetector.js\";\nimport { stripConflictMarkers } from \"./conflict-utils.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 // 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 await this.committer.commitReplay(appliedCount, newPatches);\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 existingPatches = this.lockManager.getPatches();\n const seenHashes = new Set<string>();\n for (const p of existingPatches) {\n if (seenHashes.has(p.content_hash)) {\n this.lockManager.removePatch(p.id);\n } else {\n seenHashes.add(p.content_hash);\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 // 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 await this.committer.commitReplay(appliedCount, allPatches);\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 to deduplicate converging incremental patches.\n const seenContentHashes = new Set<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 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 if (userDiff != null && userDiff.trim()) {\n const newHash = this.detector.computeContentHash(userDiff);\n patch.patch_content = userDiff;\n patch.content_hash = newHash;\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 ? { patch_content: patch.patch_content, content_hash: patch.content_hash }\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 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 // 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 // If another patch already captured this exact diff, this patch\n // is redundant (e.g., incremental patches that both resolve to\n // the same cumulative state after rebase).\n if (seenContentHashes.has(newContentHash)) {\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n seenContentHashes.add(newContentHash);\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 try {\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash\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 * 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 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 if (patch.base_generation === currentGen) {\n // Content refresh: check if user modified their customization\n // since the last replay commit.\n try {\n const diff = await this.git\n .exec([\"diff\", currentGen, \"HEAD\", \"--\", ...patch.files])\n .catch(() => null);\n\n if (diff === null) continue;\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 this.lockManager.updatePatch(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n files: newFiles\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 // Compute customer's resolved state relative to current generation\n const diff = await this.git.exec([\"diff\", currentGen, \"HEAD\", \"--\", ...patch.files]).catch(() => null);\n\n // Diff command failed (e.g., invalid SHA) — skip this patch\n if (diff === null) continue;\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\n const newContentHash = this.detector.computeContentHash(diff);\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGen,\n patch_content: diff,\n content_hash: newContentHash\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(), 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 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 conflictResults.length > 0\n ? conflictResults.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","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 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 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 });\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 { GitClient } from \"../git/GitClient.js\";\nimport { LockfileManager } from \"../LockfileManager.js\";\nimport { ReplayApplicator } from \"../ReplayApplicator.js\";\nimport { ReplayCommitter } from \"../ReplayCommitter.js\";\nimport { ReplayDetector } from \"../ReplayDetector.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}\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 await applicator.applyPatches(unresolvedPatches);\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 let patchesResolved = 0;\n\n for (const patch of patchesToCommit) {\n const diff = await git.exec([\"diff\", currentGen, \"--\", ...patch.files]).catch(() => null);\n\n if (!diff || !diff.trim()) {\n // Customer reverted the customization → remove patch entirely\n lockManager.removePatch(patch.id);\n continue;\n }\n\n // Update patch with the customer's resolution\n const newContentHash = detector.computeContentHash(diff);\n const changedFiles = await getChangedFiles(git, currentGen, patch.files);\n\n lockManager.markPatchResolved(patch.id, {\n patch_content: diff,\n content_hash: newContentHash,\n base_generation: currentGen,\n files: changedFiles\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 };\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","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":["resolve","contextCount","import_node_path","GitClient","reconstructFromGhostPatch","outDir","merged","import_node_fs","import_node_path","import_minimatch","existingPatches","newPatches","allPatches","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","committer","commitSha"]}
|