@fern-api/replay 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +16642 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/index.cjs +2014 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +463 -0
- package/dist/index.d.ts +463 -12
- package/dist/index.js +1968 -10
- package/dist/index.js.map +1 -1
- package/package.json +16 -6
- package/dist/FernignoreMigrator.d.ts +0 -38
- package/dist/FernignoreMigrator.d.ts.map +0 -1
- package/dist/FernignoreMigrator.js +0 -210
- package/dist/FernignoreMigrator.js.map +0 -1
- package/dist/LockfileManager.d.ts +0 -31
- package/dist/LockfileManager.d.ts.map +0 -1
- package/dist/LockfileManager.js +0 -124
- package/dist/LockfileManager.js.map +0 -1
- package/dist/ReplayApplicator.d.ts +0 -30
- package/dist/ReplayApplicator.d.ts.map +0 -1
- package/dist/ReplayApplicator.js +0 -544
- package/dist/ReplayApplicator.js.map +0 -1
- package/dist/ReplayCommitter.d.ts +0 -19
- package/dist/ReplayCommitter.d.ts.map +0 -1
- package/dist/ReplayCommitter.js +0 -64
- package/dist/ReplayCommitter.js.map +0 -1
- package/dist/ReplayDetector.d.ts +0 -22
- package/dist/ReplayDetector.d.ts.map +0 -1
- package/dist/ReplayDetector.js +0 -147
- package/dist/ReplayDetector.js.map +0 -1
- package/dist/ReplayService.d.ts +0 -100
- package/dist/ReplayService.d.ts.map +0 -1
- package/dist/ReplayService.js +0 -596
- package/dist/ReplayService.js.map +0 -1
- package/dist/ThreeWayMerge.d.ts +0 -11
- package/dist/ThreeWayMerge.d.ts.map +0 -1
- package/dist/ThreeWayMerge.js +0 -48
- package/dist/ThreeWayMerge.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -462
- package/dist/cli.js.map +0 -1
- package/dist/commands/bootstrap.d.ts +0 -46
- package/dist/commands/bootstrap.d.ts.map +0 -1
- package/dist/commands/bootstrap.js +0 -237
- package/dist/commands/bootstrap.js.map +0 -1
- package/dist/commands/forget.d.ts +0 -16
- package/dist/commands/forget.d.ts.map +0 -1
- package/dist/commands/forget.js +0 -27
- package/dist/commands/forget.js.map +0 -1
- package/dist/commands/index.d.ts +0 -6
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -6
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/reset.d.ts +0 -16
- package/dist/commands/reset.d.ts.map +0 -1
- package/dist/commands/reset.js +0 -25
- package/dist/commands/reset.js.map +0 -1
- package/dist/commands/resolve.d.ts +0 -16
- package/dist/commands/resolve.d.ts.map +0 -1
- package/dist/commands/resolve.js +0 -28
- package/dist/commands/resolve.js.map +0 -1
- package/dist/commands/status.d.ts +0 -26
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -24
- package/dist/commands/status.js.map +0 -1
- package/dist/git/CommitDetection.d.ts +0 -7
- package/dist/git/CommitDetection.d.ts.map +0 -1
- package/dist/git/CommitDetection.js +0 -26
- package/dist/git/CommitDetection.js.map +0 -1
- package/dist/git/GitClient.d.ts +0 -22
- package/dist/git/GitClient.d.ts.map +0 -1
- package/dist/git/GitClient.js +0 -109
- package/dist/git/GitClient.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -80
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
interface GenerationLock {
|
|
2
|
+
version: "1.0";
|
|
3
|
+
generations: GenerationRecord[];
|
|
4
|
+
current_generation: string;
|
|
5
|
+
patches: StoredPatch[];
|
|
6
|
+
replay_skipped_at?: string;
|
|
7
|
+
}
|
|
8
|
+
interface GenerationRecord {
|
|
9
|
+
commit_sha: string;
|
|
10
|
+
tree_hash: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
cli_version: string;
|
|
13
|
+
generator_versions: Record<string, string>;
|
|
14
|
+
/** SHA of the base branch HEAD before replay ran. Always on main's lineage. */
|
|
15
|
+
base_branch_head?: string;
|
|
16
|
+
}
|
|
17
|
+
interface StoredPatch {
|
|
18
|
+
id: string;
|
|
19
|
+
content_hash: string;
|
|
20
|
+
original_commit: string;
|
|
21
|
+
original_message: string;
|
|
22
|
+
original_author: string;
|
|
23
|
+
base_generation: string;
|
|
24
|
+
files: string[];
|
|
25
|
+
patch_content: string;
|
|
26
|
+
}
|
|
27
|
+
interface CustomizationsConfig {
|
|
28
|
+
exclude?: string[];
|
|
29
|
+
moves?: MoveDeclaration[];
|
|
30
|
+
}
|
|
31
|
+
interface MoveDeclaration {
|
|
32
|
+
from: string;
|
|
33
|
+
to: string;
|
|
34
|
+
}
|
|
35
|
+
type ConflictReason = "same-line-edit" | "new-file-both" | "base-generation-mismatch" | "patch-apply-failed";
|
|
36
|
+
interface ReplayResult {
|
|
37
|
+
patch: StoredPatch;
|
|
38
|
+
status: "applied" | "conflict" | "skipped";
|
|
39
|
+
method: "git-am" | "3way-merge";
|
|
40
|
+
fileResults?: FileResult[];
|
|
41
|
+
conflictReason?: ConflictReason;
|
|
42
|
+
/** Maps original file path → resolved path for files that were renamed between generations. */
|
|
43
|
+
resolvedFiles?: Record<string, string>;
|
|
44
|
+
}
|
|
45
|
+
interface ConflictMetadata {
|
|
46
|
+
patchId: string;
|
|
47
|
+
patchMessage: string;
|
|
48
|
+
baseGeneration: string;
|
|
49
|
+
currentGeneration: string;
|
|
50
|
+
}
|
|
51
|
+
interface FileResult {
|
|
52
|
+
file: string;
|
|
53
|
+
status: "merged" | "conflict" | "skipped";
|
|
54
|
+
reason?: string;
|
|
55
|
+
conflicts?: ConflictRegion[];
|
|
56
|
+
conflictReason?: ConflictReason;
|
|
57
|
+
conflictMetadata?: ConflictMetadata;
|
|
58
|
+
}
|
|
59
|
+
interface ConflictRegion {
|
|
60
|
+
startLine: number;
|
|
61
|
+
endLine: number;
|
|
62
|
+
ours: string[];
|
|
63
|
+
theirs: string[];
|
|
64
|
+
}
|
|
65
|
+
interface MergeResult {
|
|
66
|
+
content: string;
|
|
67
|
+
hasConflicts: boolean;
|
|
68
|
+
conflicts: ConflictRegion[];
|
|
69
|
+
}
|
|
70
|
+
interface CommitInfo {
|
|
71
|
+
sha: string;
|
|
72
|
+
authorName: string;
|
|
73
|
+
authorEmail: string;
|
|
74
|
+
authorLogin?: string;
|
|
75
|
+
message: string;
|
|
76
|
+
}
|
|
77
|
+
interface ReplayConfig {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
declare class GitClient {
|
|
82
|
+
private git;
|
|
83
|
+
private repoPath;
|
|
84
|
+
constructor(repoPath: string);
|
|
85
|
+
exec(args: string[]): Promise<string>;
|
|
86
|
+
execWithInput(args: string[], input: string): Promise<string>;
|
|
87
|
+
formatPatch(commitSha: string): Promise<string>;
|
|
88
|
+
applyPatch(patchContent: string): Promise<void>;
|
|
89
|
+
getTreeHash(commitSha: string): Promise<string>;
|
|
90
|
+
showFile(treeish: string, filePath: string): Promise<string | null>;
|
|
91
|
+
getCommitInfo(commitSha: string): Promise<CommitInfo>;
|
|
92
|
+
getCommitParents(commitSha: string): Promise<string[]>;
|
|
93
|
+
detectRenames(fromTree: string, toTree: string): Promise<Array<{
|
|
94
|
+
from: string;
|
|
95
|
+
to: string;
|
|
96
|
+
}>>;
|
|
97
|
+
isAncestor(commit: string, descendant: string): Promise<boolean>;
|
|
98
|
+
commitExists(sha: string): Promise<boolean>;
|
|
99
|
+
getRepoPath(): string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare const FERN_BOT_NAME = "fern-api";
|
|
103
|
+
declare const FERN_BOT_EMAIL = "115122769+fern-api[bot]@users.noreply.github.com";
|
|
104
|
+
declare const FERN_BOT_LOGIN = "fern-api[bot]";
|
|
105
|
+
declare function isGenerationCommit(commit: CommitInfo): boolean;
|
|
106
|
+
declare function isReplayCommit(commit: CommitInfo): boolean;
|
|
107
|
+
|
|
108
|
+
declare class LockfileManager {
|
|
109
|
+
private outputDir;
|
|
110
|
+
private lock;
|
|
111
|
+
constructor(outputDir: string);
|
|
112
|
+
get lockfilePath(): string;
|
|
113
|
+
get customizationsPath(): string;
|
|
114
|
+
exists(): boolean;
|
|
115
|
+
read(): GenerationLock;
|
|
116
|
+
initialize(firstGeneration: GenerationRecord): void;
|
|
117
|
+
/**
|
|
118
|
+
* Set up in-memory lock state without writing to disk.
|
|
119
|
+
* Useful for bootstrap dry-run where we need state for detection
|
|
120
|
+
* but don't want to persist anything.
|
|
121
|
+
*/
|
|
122
|
+
initializeInMemory(firstGeneration: GenerationRecord): void;
|
|
123
|
+
save(): void;
|
|
124
|
+
addGeneration(record: GenerationRecord): void;
|
|
125
|
+
addPatch(patch: StoredPatch): void;
|
|
126
|
+
updatePatch(patchId: string, updates: Partial<Pick<StoredPatch, "base_generation" | "patch_content" | "content_hash" | "files">>): void;
|
|
127
|
+
removePatch(patchId: string): void;
|
|
128
|
+
clearPatches(): void;
|
|
129
|
+
getPatches(): StoredPatch[];
|
|
130
|
+
setReplaySkippedAt(timestamp: string): void;
|
|
131
|
+
clearReplaySkippedAt(): void;
|
|
132
|
+
isReplaySkipped(): boolean;
|
|
133
|
+
getGeneration(commitSha: string): GenerationRecord | undefined;
|
|
134
|
+
getCustomizationsConfig(): CustomizationsConfig;
|
|
135
|
+
private ensureLoaded;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare class ReplayDetector {
|
|
139
|
+
private git;
|
|
140
|
+
private lockManager;
|
|
141
|
+
private sdkOutputDir;
|
|
142
|
+
readonly warnings: string[];
|
|
143
|
+
constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string);
|
|
144
|
+
detectNewPatches(): Promise<StoredPatch[]>;
|
|
145
|
+
/**
|
|
146
|
+
* Compute content hash for deduplication.
|
|
147
|
+
* Removes commit SHA line and index lines before hashing,
|
|
148
|
+
* so rebased commits with same content produce the same hash.
|
|
149
|
+
*/
|
|
150
|
+
computeContentHash(patchContent: string): string;
|
|
151
|
+
/** Detect patches via tree diff for non-linear history. Returns a composite patch. */
|
|
152
|
+
private detectPatchesViaTreeDiff;
|
|
153
|
+
private parseGitLog;
|
|
154
|
+
private getLastGeneration;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Performs a 3-way merge using the diff3 algorithm.
|
|
159
|
+
*
|
|
160
|
+
* @param base - The common ancestor (pristine generated state user edited against)
|
|
161
|
+
* @param ours - The new generated version
|
|
162
|
+
* @param theirs - The user's customized version
|
|
163
|
+
* @returns MergeResult with content, conflict flag, and conflict regions
|
|
164
|
+
*/
|
|
165
|
+
declare function threeWayMerge(base: string, ours: string, theirs: string): MergeResult;
|
|
166
|
+
|
|
167
|
+
declare class ReplayApplicator {
|
|
168
|
+
private git;
|
|
169
|
+
private lockManager;
|
|
170
|
+
private outputDir;
|
|
171
|
+
private renameCache;
|
|
172
|
+
private fileTheirsAccumulator;
|
|
173
|
+
constructor(git: GitClient, lockManager: LockfileManager, outputDir: string);
|
|
174
|
+
/** Reset inter-patch accumulator for a new cycle. */
|
|
175
|
+
private resetAccumulator;
|
|
176
|
+
/**
|
|
177
|
+
* Apply all patches, returning results for each.
|
|
178
|
+
* Skips patches that match exclude patterns in replay.yml
|
|
179
|
+
*/
|
|
180
|
+
applyPatches(patches: StoredPatch[]): Promise<ReplayResult[]>;
|
|
181
|
+
/** Populate accumulator after git apply succeeds. */
|
|
182
|
+
private populateAccumulatorForPatch;
|
|
183
|
+
private applyPatchWithFallback;
|
|
184
|
+
private applyWithThreeWayMerge;
|
|
185
|
+
private mergeFile;
|
|
186
|
+
private isExcluded;
|
|
187
|
+
private resolveFilePath;
|
|
188
|
+
private applyPatchToContent;
|
|
189
|
+
private extractFileDiff;
|
|
190
|
+
private extractRenameSource;
|
|
191
|
+
private extractNewFileFromPatch;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface CommitOptions {
|
|
195
|
+
cliVersion: string;
|
|
196
|
+
generatorVersions: Record<string, string>;
|
|
197
|
+
baseBranchHead?: string;
|
|
198
|
+
}
|
|
199
|
+
declare class ReplayCommitter {
|
|
200
|
+
private git;
|
|
201
|
+
private outputDir;
|
|
202
|
+
constructor(git: GitClient, outputDir: string);
|
|
203
|
+
commitGeneration(message: string, options?: CommitOptions): Promise<string>;
|
|
204
|
+
commitReplay(_patchCount: number, patches?: StoredPatch[]): Promise<string>;
|
|
205
|
+
createGenerationRecord(options?: CommitOptions): Promise<GenerationRecord>;
|
|
206
|
+
stageAll(): Promise<void>;
|
|
207
|
+
hasStagedChanges(): Promise<boolean>;
|
|
208
|
+
getTreeHash(commitSha: string): Promise<string>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface ConflictDetail {
|
|
212
|
+
patchId: string;
|
|
213
|
+
patchMessage: string;
|
|
214
|
+
reason?: string;
|
|
215
|
+
files: FileResult[];
|
|
216
|
+
/** Files that applied cleanly in a patch that also had conflicts. */
|
|
217
|
+
cleanFiles?: string[];
|
|
218
|
+
}
|
|
219
|
+
interface ReplayReport {
|
|
220
|
+
flow: "first-generation" | "no-patches" | "normal-regeneration" | "skip-application";
|
|
221
|
+
patchesDetected: number;
|
|
222
|
+
patchesApplied: number;
|
|
223
|
+
patchesWithConflicts: number;
|
|
224
|
+
patchesSkipped: number;
|
|
225
|
+
patchesAbsorbed?: number;
|
|
226
|
+
patchesRepointed?: number;
|
|
227
|
+
patchesContentRebased?: number;
|
|
228
|
+
patchesKeptAsUserOwned?: number;
|
|
229
|
+
patchesPartiallyApplied?: number;
|
|
230
|
+
patchesConflictResolved?: number;
|
|
231
|
+
patchesRefreshed?: number;
|
|
232
|
+
conflicts: FileResult[];
|
|
233
|
+
conflictDetails?: ConflictDetail[];
|
|
234
|
+
wouldApply?: StoredPatch[];
|
|
235
|
+
warnings?: string[];
|
|
236
|
+
}
|
|
237
|
+
interface ReplayOptions {
|
|
238
|
+
/** Log what would happen but don't modify anything */
|
|
239
|
+
dryRun?: boolean;
|
|
240
|
+
/** Write files and stage changes, but don't commit */
|
|
241
|
+
stageOnly?: boolean;
|
|
242
|
+
/** CLI version for commit metadata */
|
|
243
|
+
cliVersion?: string;
|
|
244
|
+
/** Generator versions for commit metadata */
|
|
245
|
+
generatorVersions?: Record<string, string>;
|
|
246
|
+
/** Commit generation + update lockfile, skip detection/application */
|
|
247
|
+
skipApplication?: boolean;
|
|
248
|
+
/** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */
|
|
249
|
+
baseBranchHead?: string;
|
|
250
|
+
}
|
|
251
|
+
declare class ReplayService {
|
|
252
|
+
private git;
|
|
253
|
+
private detector;
|
|
254
|
+
private applicator;
|
|
255
|
+
private committer;
|
|
256
|
+
private lockManager;
|
|
257
|
+
private outputDir;
|
|
258
|
+
constructor(outputDir: string, _config: ReplayConfig);
|
|
259
|
+
runReplay(options?: ReplayOptions): Promise<ReplayReport>;
|
|
260
|
+
/**
|
|
261
|
+
* Sync the lockfile after a divergent PR was squash-merged.
|
|
262
|
+
* Call this BEFORE runReplay() when the CLI detects a merged divergent PR.
|
|
263
|
+
*
|
|
264
|
+
* After updating the generation record, re-detects customer patches via
|
|
265
|
+
* tree diff between the generation tag (pure generation tree) and HEAD
|
|
266
|
+
* (which includes customer customizations after squash merge). This ensures
|
|
267
|
+
* patches survive the squash merge → regenerate cycle even when the lockfile
|
|
268
|
+
* was restored from the base branch during conflict PR creation.
|
|
269
|
+
*/
|
|
270
|
+
syncFromDivergentMerge(generationCommitSha: string, options?: {
|
|
271
|
+
cliVersion?: string;
|
|
272
|
+
generatorVersions?: Record<string, string>;
|
|
273
|
+
baseBranchHead?: string;
|
|
274
|
+
}): Promise<void>;
|
|
275
|
+
private determineFlow;
|
|
276
|
+
private handleFirstGeneration;
|
|
277
|
+
/**
|
|
278
|
+
* Skip-application mode: commit the generation and update the lockfile
|
|
279
|
+
* but don't detect or apply patches. Sets a marker so the next normal
|
|
280
|
+
* run skips revert detection in preGenerationRebase().
|
|
281
|
+
*/
|
|
282
|
+
private handleSkipApplication;
|
|
283
|
+
private handleNoPatchesRegeneration;
|
|
284
|
+
private handleNormalRegeneration;
|
|
285
|
+
/**
|
|
286
|
+
* Rebase cleanly applied patches so they are relative to the current generation.
|
|
287
|
+
* This prevents recurring conflicts on subsequent regenerations.
|
|
288
|
+
* Returns the number of patches rebased.
|
|
289
|
+
*/
|
|
290
|
+
private rebasePatches;
|
|
291
|
+
/**
|
|
292
|
+
* For conflict patches with mixed results (some files merged, some conflicted),
|
|
293
|
+
* check if the cleanly merged files were absorbed by the generator (empty diff).
|
|
294
|
+
* If so, remove them from patch.files so they don't pollute the pre-generation
|
|
295
|
+
* rebase conflict marker check (`git grep <<<<<<< -- ...patch.files`).
|
|
296
|
+
*
|
|
297
|
+
* Non-absorbed clean files stay in patch.files — removing them would lose
|
|
298
|
+
* the customization on the next generation.
|
|
299
|
+
*/
|
|
300
|
+
private trimAbsorbedFiles;
|
|
301
|
+
/**
|
|
302
|
+
* Pre-generation rebase: update patches using the customer's current state.
|
|
303
|
+
* Called BEFORE commitGeneration() while HEAD has customer code.
|
|
304
|
+
*/
|
|
305
|
+
private preGenerationRebase;
|
|
306
|
+
private readFernignorePatterns;
|
|
307
|
+
private buildReport;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface MigrationAnalysis {
|
|
311
|
+
/** Files in .fernignore that have git commit history (can be tracked by Replay) */
|
|
312
|
+
trackedByBoth: Array<{
|
|
313
|
+
file: string;
|
|
314
|
+
commit: string;
|
|
315
|
+
}>;
|
|
316
|
+
/** Files in .fernignore but NO recent commit history found after last generation */
|
|
317
|
+
fernignoreOnly: string[];
|
|
318
|
+
/** Commits found that AREN'T in .fernignore (inline edits to generated files) */
|
|
319
|
+
commitsOnly: StoredPatch[];
|
|
320
|
+
/** Synthetic patches created for .fernignore files that differ from pristine generation */
|
|
321
|
+
syntheticPatches: StoredPatch[];
|
|
322
|
+
}
|
|
323
|
+
interface MigrationResult {
|
|
324
|
+
patchesCreated: number;
|
|
325
|
+
filesSkipped: string[];
|
|
326
|
+
warnings: string[];
|
|
327
|
+
}
|
|
328
|
+
declare class FernignoreMigrator {
|
|
329
|
+
private git;
|
|
330
|
+
private lockManager;
|
|
331
|
+
private outputDir;
|
|
332
|
+
constructor(git: GitClient, lockManager: LockfileManager, outputDir: string);
|
|
333
|
+
fernignoreExists(): boolean;
|
|
334
|
+
readFernignorePatterns(): string[];
|
|
335
|
+
/** Analyze .fernignore patterns vs git history. Creates synthetic patches for files differing from pristine generation. */
|
|
336
|
+
analyzeMigration(): Promise<MigrationAnalysis>;
|
|
337
|
+
private resolvePatterns;
|
|
338
|
+
private readFileContent;
|
|
339
|
+
private createNewFileDiff;
|
|
340
|
+
private createFileDiff;
|
|
341
|
+
migrate(): Promise<MigrationResult>;
|
|
342
|
+
movePatternsToReplayYml(patterns: string[]): void;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
interface BootstrapOptions {
|
|
346
|
+
/** Log what would happen but don't modify anything */
|
|
347
|
+
dryRun?: boolean;
|
|
348
|
+
/** How to handle .fernignore: "migrate" moves patterns to replay.yml, "delete" removes it, "skip" leaves it */
|
|
349
|
+
fernignoreAction?: "migrate" | "delete" | "skip";
|
|
350
|
+
/** Maximum number of commits to scan for generation history (default: 500) */
|
|
351
|
+
maxCommitsToScan?: number;
|
|
352
|
+
/** Allow overwriting an existing lockfile */
|
|
353
|
+
force?: boolean;
|
|
354
|
+
/** When true, scan git history for existing patches. Default: false (clean start with 0 patches). */
|
|
355
|
+
importHistory?: boolean;
|
|
356
|
+
}
|
|
357
|
+
interface BootstrapResult {
|
|
358
|
+
/** The generation commit used as baseline, or null if none found */
|
|
359
|
+
generationCommit: CommitInfo | null;
|
|
360
|
+
/** Number of customization patches detected */
|
|
361
|
+
patchesDetected: number;
|
|
362
|
+
/** Number of patches written to lockfile */
|
|
363
|
+
patchesCreated: number;
|
|
364
|
+
/** The detected patches (for dry-run inspection) */
|
|
365
|
+
patches: StoredPatch[];
|
|
366
|
+
/** .fernignore patterns found, if any */
|
|
367
|
+
fernignorePatterns: string[];
|
|
368
|
+
/** .fernignore migration analysis, if .fernignore exists */
|
|
369
|
+
fernignoreAnalysis?: MigrationAnalysis;
|
|
370
|
+
/** Whether .fernignore was updated to protect replay files */
|
|
371
|
+
fernignoreUpdated: boolean;
|
|
372
|
+
/** Warnings about edge cases */
|
|
373
|
+
warnings: string[];
|
|
374
|
+
/** Number of older generation commits that were skipped (stale commits ignored) */
|
|
375
|
+
staleGenerationsSkipped: number;
|
|
376
|
+
/** The generation commit SHA used as cutoff for patch detection */
|
|
377
|
+
scannedSinceGeneration: string;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Bootstrap Replay for an existing SDK repository.
|
|
381
|
+
*
|
|
382
|
+
* Scans git history to find all generation commits, identifies
|
|
383
|
+
* user customization patches between them, and creates the initial replay.lock.
|
|
384
|
+
*
|
|
385
|
+
* This is a one-time migration step for SDKs that existed before Replay.
|
|
386
|
+
*/
|
|
387
|
+
declare function bootstrap(outputDir: string, options?: BootstrapOptions): Promise<BootstrapResult>;
|
|
388
|
+
|
|
389
|
+
interface ForgetOptions {
|
|
390
|
+
/** Don't actually remove, just show what would be removed */
|
|
391
|
+
dryRun?: boolean;
|
|
392
|
+
}
|
|
393
|
+
interface ForgetResult {
|
|
394
|
+
/** Patches that were (or would be) removed */
|
|
395
|
+
removed: Array<{
|
|
396
|
+
id: string;
|
|
397
|
+
message: string;
|
|
398
|
+
files: string[];
|
|
399
|
+
}>;
|
|
400
|
+
/** True if no patches matched the pattern */
|
|
401
|
+
notFound: boolean;
|
|
402
|
+
}
|
|
403
|
+
declare function forget(outputDir: string, filePattern: string, options?: ForgetOptions): ForgetResult;
|
|
404
|
+
|
|
405
|
+
interface ResetOptions {
|
|
406
|
+
/** Don't actually delete, just show what would happen */
|
|
407
|
+
dryRun?: boolean;
|
|
408
|
+
}
|
|
409
|
+
interface ResetResult {
|
|
410
|
+
/** Whether reset was successful (or would be) */
|
|
411
|
+
success: boolean;
|
|
412
|
+
/** Number of patches that were (or would be) removed */
|
|
413
|
+
patchesRemoved: number;
|
|
414
|
+
/** Whether the lockfile was (or would be) deleted */
|
|
415
|
+
lockfileDeleted: boolean;
|
|
416
|
+
/** True if there was nothing to reset */
|
|
417
|
+
nothingToReset: boolean;
|
|
418
|
+
}
|
|
419
|
+
declare function reset(outputDir: string, options?: ResetOptions): ResetResult;
|
|
420
|
+
|
|
421
|
+
interface ResolveOptions {
|
|
422
|
+
/** Check for remaining conflict markers before committing. Default: true */
|
|
423
|
+
checkMarkers?: boolean;
|
|
424
|
+
}
|
|
425
|
+
interface ResolveResult {
|
|
426
|
+
/** Whether the resolve succeeded */
|
|
427
|
+
success: boolean;
|
|
428
|
+
/** Commit SHA of the [fern-replay] commit, if created */
|
|
429
|
+
commitSha?: string;
|
|
430
|
+
/** Reason for failure */
|
|
431
|
+
reason?: string;
|
|
432
|
+
/** Files that still have conflict markers */
|
|
433
|
+
unresolvedFiles?: string[];
|
|
434
|
+
}
|
|
435
|
+
declare function resolve(outputDir: string, options?: ResolveOptions): Promise<ResolveResult>;
|
|
436
|
+
|
|
437
|
+
interface StatusResult {
|
|
438
|
+
/** Whether replay is initialized (lockfile exists) */
|
|
439
|
+
initialized: boolean;
|
|
440
|
+
/** Tracked customization patches */
|
|
441
|
+
patches: StatusPatch[];
|
|
442
|
+
/** Last generation info, if available */
|
|
443
|
+
lastGeneration: StatusGeneration | undefined;
|
|
444
|
+
}
|
|
445
|
+
interface StatusPatch {
|
|
446
|
+
/** Short SHA of the original commit */
|
|
447
|
+
sha: string;
|
|
448
|
+
/** Author name (without email) */
|
|
449
|
+
author: string;
|
|
450
|
+
/** Original commit message */
|
|
451
|
+
message: string;
|
|
452
|
+
/** Files touched by this patch */
|
|
453
|
+
files: string[];
|
|
454
|
+
}
|
|
455
|
+
interface StatusGeneration {
|
|
456
|
+
/** Full commit SHA */
|
|
457
|
+
sha: string;
|
|
458
|
+
/** Generation timestamp */
|
|
459
|
+
timestamp: string;
|
|
460
|
+
}
|
|
461
|
+
declare function status(outputDir: string): StatusResult;
|
|
462
|
+
|
|
463
|
+
export { type BootstrapOptions, type BootstrapResult, type CommitInfo, type CommitOptions, type ConflictDetail, type ConflictMetadata, type ConflictReason, type ConflictRegion, type CustomizationsConfig, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_BOT_NAME, FernignoreMigrator, type FileResult, type ForgetOptions, type ForgetResult, type GenerationLock, type GenerationRecord, GitClient, LockfileManager, type MergeResult, type MigrationAnalysis, type MigrationResult, type MoveDeclaration, ReplayApplicator, ReplayCommitter, type ReplayConfig, ReplayDetector, type ReplayOptions, type ReplayReport, type ReplayResult, ReplayService, type ResetOptions, type ResetResult, type ResolveOptions, type ResolveResult, type StatusGeneration, type StatusPatch, type StatusResult, type StoredPatch, bootstrap, forget, isGenerationCommit, isReplayCommit, reset, resolve, status, threeWayMerge };
|