@fern-api/replay 0.10.1 → 0.10.3

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/git/GitClient.ts","../src/HybridReconstruction.ts","../src/index.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 async detectRenames(fromTree: string, toTree: string): Promise<Array<{ from: string; to: string }>> {\n try {\n const output = await this.exec([\"diff\", \"--find-renames\", \"--name-status\", fromTree, toTree]);\n const renames: Array<{ from: string; to: string }> = [];\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Rename lines look like: R095\\told/path.ts\\tnew/path.ts\n if (line.startsWith(\"R\")) {\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 { 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","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 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\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 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\">>,\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 { 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\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\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 \"--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 const parents = await this.git.getCommitParents(commit.sha);\n if (parents.length > 1) {\n continue;\n }\n\n if (lock.patches.find((p) => p.original_commit === commit.sha)) {\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 const 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 files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f));\n\n // Skip patches that only touch infrastructure 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 });\n }\n\n // Reverse so patches apply in chronological order (oldest first)\n newPatches.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 < newPatches.length; i++) {\n const patch = newPatches[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 = newPatches.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 = newPatches.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 = newPatches.filter((_, i) => !revertIndicesToRemove.has(i));\n return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };\n }\n\n /**\n * Compute content hash for deduplication.\n * Removes commit SHA line and index lines before hashing,\n * so rebased commits with same content produce the same hash.\n */\n computeContentHash(patchContent: string): string {\n const normalized = patchContent\n .split(\"\\n\")\n .filter((line) => !line.startsWith(\"From \") && !line.startsWith(\"index \") && !line.startsWith(\"Date: \"))\n .join(\"\\n\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\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 files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n .filter((f) => !f.startsWith(\".fern/\"));\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 };\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 const contentHash = this.computeContentHash(patchContent);\n if (existingHashes.has(contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n // Skip creation-only commits (all diffs are new-file additions).\n // After force push, squashed commits create all files from scratch — these\n // aren't user customizations, they're history-rewriting artifacts.\n if (this.isCreationOnlyPatch(patchContent)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n const files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f));\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 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, 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 * 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 if (theirs) {\n this.fileTheirsAccumulator.set(resolvedPath, {\n content: theirs,\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 // Strategy 1: Try git apply --3way (skip if accumulation needed)\n if (!needsAccumulation) {\n // Snapshot files before git apply (may leave conflict markers on failure)\n const snapshots = new Map<string, string | null>();\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 const fullPath = join(this.outputDir, resolvedPath);\n snapshots.set(resolvedPath, 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 [resolvedPath, content] of snapshots) {\n if (content != null) {\n await writeFile(join(this.outputDir, resolvedPath), content);\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 || base == null)) {\n theirs = await this.applyPatchToContent(\n accumulatorEntry.content,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir\n );\n if (theirs) {\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 && base && !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 && effective_theirs) {\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 && effective_theirs && !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 return { file: resolvedPath, status: \"merged\" };\n }\n\n if (!effective_theirs) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"missing-content\"\n };\n }\n\n if ((base == null && !useAccumulatorAsMergeBase) || !ours) {\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 && !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 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\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 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 }\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\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 };\n }\n\n private async handleNoPatchesRegeneration(options?: ReplayOptions): Promise<ReplayReport> {\n const { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();\n const warnings = [...this.detector.warnings];\n\n if (options?.dryRun) {\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: warnings.length > 0 ? warnings : undefined\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\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\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 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];\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 const warnings = [...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\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\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 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\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 // Check if any files are user-owned (new, .fernignore-protected, or .fernignore itself).\n const fernignorePatterns = this.readFernignorePatterns();\n const isUserOwned = await Promise.all(\n patch.files.map(async (file) => {\n // .fernignore itself is always user-owned\n if (file === \".fernignore\") {\n return true;\n }\n // Check .fernignore patterns (cheaper than git)\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) {\n return true;\n }\n // Check if file exists in the generation commit tree\n const content = await this.git.showFile(currentGenSha, file);\n return content === null;\n })\n );\n const hasUserOwnedFiles = isUserOwned.some(Boolean);\n\n if (hasUserOwnedFiles) {\n // Patch contains user-owned files — just update base_generation\n // to prevent re-evaluation. Keep patch_content as-is since\n // these files aren't produced by the generator.\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha\n });\n keptAsUserOwned++;\n continue;\n }\n\n // All files exist in generation — safe to use git diff for\n // absorption check and patch rebasing.\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", ...patch.files]).catch(() => null);\n\n if (!diff || !diff.trim()) {\n // Patch is now empty — customization was absorbed by the generator.\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n\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 this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash\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 * 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 const fernignorePatterns = this.readFernignorePatterns();\n\n // Filter to only generator-produced clean files (not user-owned)\n const generatorCleanFiles: string[] = [];\n for (const file of cleanFiles) {\n if (file === \".fernignore\") continue;\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) continue;\n const content = await this.git.showFile(currentGenSha, file);\n if (content === null) continue; // user-owned new file\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\n for (const patch of patches) {\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 // 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 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 — 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 normalized = patchContent\n .split(\"\\n\")\n .filter((line) => !line.startsWith(\"From \") && !line.startsWith(\"index \") && !line.startsWith(\"Date: \"))\n .join(\"\\n\");\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","dirname","join","join","GitClient","reconstructFromGhostPatch","outDir","dirname","merged","existsSync","readFileSync","writeFileSync","join","minimatch","existingPatches","newPatches","warnings","allPatches","minimatch","join","readFileSync","writeFileSync","existsSync","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","minimatch","parse","stringify","existsSync","join","readFileSync","minimatch","createHash","parse","dirname","mkdirSync","writeFileSync","stringify","createHash","existsSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","writeFileSync","createHash","minimatch","minimatch","committer","commitSha"]}
1
+ {"version":3,"sources":["../src/git/GitClient.ts","../src/HybridReconstruction.ts","../src/index.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 async detectRenames(fromTree: string, toTree: string): Promise<Array<{ from: string; to: string }>> {\n try {\n const output = await this.exec([\"diff\", \"--find-renames\", \"--name-status\", fromTree, toTree]);\n const renames: Array<{ from: string; to: string }> = [];\n for (const line of output.trim().split(\"\\n\")) {\n if (!line) continue;\n // Rename lines look like: R095\\told/path.ts\\tnew/path.ts\n if (line.startsWith(\"R\")) {\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 { 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","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 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\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 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\">>,\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 { 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\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\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 \"--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 const parents = await this.git.getCommitParents(commit.sha);\n if (parents.length > 1) {\n continue;\n }\n\n if (lock.patches.find((p) => p.original_commit === commit.sha)) {\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 const 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 files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f));\n\n // Skip patches that only touch infrastructure 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 });\n }\n\n // Reverse so patches apply in chronological order (oldest first)\n newPatches.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 < newPatches.length; i++) {\n const patch = newPatches[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 = newPatches.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 = newPatches.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 = newPatches.filter((_, i) => !revertIndicesToRemove.has(i));\n return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };\n }\n\n /**\n * Compute content hash for deduplication.\n * Removes commit SHA line and index lines before hashing,\n * so rebased commits with same content produce the same hash.\n */\n computeContentHash(patchContent: string): string {\n const normalized = patchContent\n .split(\"\\n\")\n .filter((line) => !line.startsWith(\"From \") && !line.startsWith(\"index \") && !line.startsWith(\"Date: \"))\n .join(\"\\n\");\n\n return `sha256:${createHash(\"sha256\").update(normalized).digest(\"hex\")}`;\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 files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f))\n .filter((f) => !f.startsWith(\".fern/\"));\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 };\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 const contentHash = this.computeContentHash(patchContent);\n if (existingHashes.has(contentHash) || forgottenHashes.has(contentHash)) {\n continue;\n }\n\n // Skip creation-only commits (all diffs are new-file additions).\n // After force push, squashed commits create all files from scratch — these\n // aren't user customizations, they're history-rewriting artifacts.\n if (this.isCreationOnlyPatch(patchContent)) {\n continue;\n }\n\n const filesOutput = await this.git.exec([\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", commit.sha]);\n const files = filesOutput\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .filter((f) => !INFRASTRUCTURE_FILES.has(f));\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 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 * 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) {\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 // Strategy 1: Try git apply --3way (skip if accumulation needed)\n if (!needsAccumulation) {\n // Snapshot files before git apply (may leave conflict markers on failure)\n const snapshots = new Map<string, string | null>();\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 const fullPath = join(this.outputDir, resolvedPath);\n snapshots.set(resolvedPath, 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 [resolvedPath, content] of snapshots) {\n const fullPath = join(this.outputDir, resolvedPath);\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 || base == null)) {\n theirs = await this.applyPatchToContent(\n accumulatorEntry.content,\n patch.patch_content,\n filePath,\n tempGit,\n tempDir\n );\n if (theirs) {\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 && base && !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 && effective_theirs) {\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 && effective_theirs && !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 return { file: resolvedPath, status: \"merged\" };\n }\n\n if (!effective_theirs) {\n return {\n file: resolvedPath,\n status: \"skipped\",\n reason: \"missing-content\"\n };\n }\n\n if ((base == null && !useAccumulatorAsMergeBase) || !ours) {\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 && !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 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\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 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 }\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\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 };\n }\n\n private async handleNoPatchesRegeneration(options?: ReplayOptions): Promise<ReplayReport> {\n const { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();\n const warnings = [...this.detector.warnings];\n\n if (options?.dryRun) {\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: warnings.length > 0 ? warnings : undefined\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\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\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 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];\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 const warnings = [...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\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\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 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\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 // Check if any files are user-owned (new, .fernignore-protected, or .fernignore itself).\n const fernignorePatterns = this.readFernignorePatterns();\n const isUserOwned = await Promise.all(\n patch.files.map(async (file) => {\n // .fernignore itself is always user-owned\n if (file === \".fernignore\") {\n return true;\n }\n // Check .fernignore patterns (cheaper than git)\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) {\n return true;\n }\n // Check if file exists in the generation commit tree\n const content = await this.git.showFile(currentGenSha, file);\n return content === null;\n })\n );\n const hasUserOwnedFiles = isUserOwned.some(Boolean);\n\n if (hasUserOwnedFiles) {\n // Patch contains user-owned files — just update base_generation\n // to prevent re-evaluation. Keep patch_content as-is since\n // these files aren't produced by the generator.\n this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha\n });\n keptAsUserOwned++;\n continue;\n }\n\n // All files exist in generation — safe to use git diff for\n // absorption check and patch rebasing.\n const diff = await this.git.exec([\"diff\", currentGenSha, \"--\", ...patch.files]).catch(() => null);\n\n if (!diff || !diff.trim()) {\n // Patch is now empty — customization was absorbed by the generator.\n this.lockManager.removePatch(patch.id);\n absorbedPatchIds.add(patch.id);\n absorbed++;\n continue;\n }\n\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 this.lockManager.updatePatch(patch.id, {\n base_generation: currentGenSha,\n patch_content: diff,\n content_hash: newContentHash\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 * 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 const fernignorePatterns = this.readFernignorePatterns();\n\n // Filter to only generator-produced clean files (not user-owned)\n const generatorCleanFiles: string[] = [];\n for (const file of cleanFiles) {\n if (file === \".fernignore\") continue;\n if (fernignorePatterns.some((p) => file === p || minimatch(file, p))) continue;\n const content = await this.git.showFile(currentGenSha, file);\n if (content === null) continue; // user-owned new file\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\n for (const patch of patches) {\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 // 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 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 — 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 normalized = patchContent\n .split(\"\\n\")\n .filter((line) => !line.startsWith(\"From \") && !line.startsWith(\"index \") && !line.startsWith(\"Date: \"))\n .join(\"\\n\");\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","dirname","join","join","GitClient","reconstructFromGhostPatch","outDir","dirname","merged","existsSync","readFileSync","writeFileSync","join","minimatch","existingPatches","newPatches","warnings","allPatches","minimatch","join","readFileSync","writeFileSync","existsSync","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","minimatch","parse","stringify","existsSync","join","readFileSync","minimatch","createHash","parse","dirname","mkdirSync","writeFileSync","stringify","createHash","existsSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","writeFileSync","createHash","minimatch","minimatch","committer","commitSha"]}