@fern-api/replay 0.15.2 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +2340 -2331
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +163 -153
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -38
- package/dist/index.d.ts +37 -38
- package/dist/index.js +163 -153
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -12,8 +12,6 @@ interface GenerationRecord {
|
|
|
12
12
|
timestamp: string;
|
|
13
13
|
cli_version: string;
|
|
14
14
|
generator_versions: Record<string, string>;
|
|
15
|
-
/** SHA of the base branch HEAD before replay ran. Always on main's lineage. */
|
|
16
|
-
base_branch_head?: string;
|
|
17
15
|
}
|
|
18
16
|
interface StoredPatch {
|
|
19
17
|
id: string;
|
|
@@ -216,8 +214,19 @@ declare class LockfileNotFoundError extends Error {
|
|
|
216
214
|
declare class LockfileManager {
|
|
217
215
|
private outputDir;
|
|
218
216
|
private lock;
|
|
217
|
+
private fernignorePatterns;
|
|
219
218
|
readonly warnings: string[];
|
|
220
219
|
constructor(outputDir: string);
|
|
220
|
+
/**
|
|
221
|
+
* Inform the lockfile of the customer's `.fernignore` patterns so that
|
|
222
|
+
* `save()` can suppress its "Patch X removed from lockfile" warning when
|
|
223
|
+
* every file in the stripped patch is already `.fernignore`-protected.
|
|
224
|
+
* The strip itself still happens (credentials never persist); only the
|
|
225
|
+
* customer-visible warning is suppressed in that case, because the
|
|
226
|
+
* protected files survive the generator wipe regardless of whether the
|
|
227
|
+
* lockfile tracks them, so there's nothing for the customer to action.
|
|
228
|
+
*/
|
|
229
|
+
setFernignorePatterns(patterns: string[]): void;
|
|
221
230
|
get lockfilePath(): string;
|
|
222
231
|
get customizationsPath(): string;
|
|
223
232
|
exists(): boolean;
|
|
@@ -259,22 +268,24 @@ declare class ReplayDetector {
|
|
|
259
268
|
private sdkOutputDir;
|
|
260
269
|
readonly warnings: string[];
|
|
261
270
|
constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string);
|
|
262
|
-
detectNewPatches(): Promise<DetectionResult>;
|
|
263
271
|
/**
|
|
264
|
-
*
|
|
272
|
+
* Derive the previous-generation SHA from git history instead of trusting
|
|
273
|
+
* `lock.current_generation`.
|
|
265
274
|
*
|
|
266
|
-
*
|
|
267
|
-
* `
|
|
268
|
-
*
|
|
269
|
-
* a reachable ancestor of HEAD. Walking that range and classifying each
|
|
270
|
-
* commit via `isGenerationCommit` mirrors the linear path and eliminates
|
|
271
|
-
* the bug class where pipeline-driven changes (autoversion, replay,
|
|
272
|
-
* generation) get bundled as customer customizations.
|
|
275
|
+
* Walks `git log HEAD --first-parent` and returns the SHA of the most recent
|
|
276
|
+
* commit that `isGenerationBoundary` classifies as a customization-baseline
|
|
277
|
+
* boundary, or null if no such commit is reachable from HEAD on the mainline.
|
|
273
278
|
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
279
|
+
* `isGenerationBoundary` is intentionally narrower than `isGenerationCommit`:
|
|
280
|
+
* it excludes `[fern-autoversion]` (lightweight bumps that don't reset the
|
|
281
|
+
* baseline) and the GitHub merge-commit subject for fern-bot regen PRs
|
|
282
|
+
* (which sits on first-parent but where the customer fix-up commits live
|
|
283
|
+
* on second-parent — stopping at the merge would hide them).
|
|
284
|
+
*
|
|
285
|
+
* See docs/adr/0001-derived-scan-boundary.md.
|
|
276
286
|
*/
|
|
277
|
-
|
|
287
|
+
findPreviousGenerationFromHistory(): Promise<string | null>;
|
|
288
|
+
detectNewPatches(): Promise<DetectionResult>;
|
|
278
289
|
/**
|
|
279
290
|
* Walk `${rangeStart}..HEAD`, classify each commit, emit one
|
|
280
291
|
* `StoredPatch` per customer commit. Body shared by the linear path
|
|
@@ -368,6 +379,13 @@ declare class ReplayDetector {
|
|
|
368
379
|
private resolveDiffBase;
|
|
369
380
|
private parseGitLog;
|
|
370
381
|
private getLastGeneration;
|
|
382
|
+
/**
|
|
383
|
+
* Build a transient `GenerationRecord` from a SHA derived by walking git
|
|
384
|
+
* history. Only `commit_sha` (and `tree_hash` when needed downstream) is
|
|
385
|
+
* load-bearing here; the rest are filled with defensible placeholders.
|
|
386
|
+
* This record is consumed by `detectPatchesInRange` and is never persisted.
|
|
387
|
+
*/
|
|
388
|
+
private synthesizeGenerationRecord;
|
|
371
389
|
}
|
|
372
390
|
|
|
373
391
|
/**
|
|
@@ -468,7 +486,6 @@ declare class ReplayApplicator {
|
|
|
468
486
|
interface CommitOptions {
|
|
469
487
|
cliVersion: string;
|
|
470
488
|
generatorVersions: Record<string, string>;
|
|
471
|
-
baseBranchHead?: string;
|
|
472
489
|
}
|
|
473
490
|
declare class ReplayCommitter {
|
|
474
491
|
private git;
|
|
@@ -587,12 +604,10 @@ interface ReplayOptions {
|
|
|
587
604
|
generatorVersions?: Record<string, string>;
|
|
588
605
|
/** Commit generation + update lockfile, skip detection/application */
|
|
589
606
|
skipApplication?: boolean;
|
|
590
|
-
/** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */
|
|
591
|
-
baseBranchHead?: string;
|
|
592
607
|
}
|
|
593
608
|
/**
|
|
594
609
|
* Options honored by `applyPreparedReplay()`. `cliVersion`, `generatorVersions`,
|
|
595
|
-
* `
|
|
610
|
+
* `dryRun`, and `skipApplication` were all captured in phase 1
|
|
596
611
|
* and re-supplying them here is meaningless.
|
|
597
612
|
*/
|
|
598
613
|
interface ApplyOptions {
|
|
@@ -612,8 +627,8 @@ interface ApplyOptions {
|
|
|
612
627
|
* respected. `rebasePatches` uses `currentGenerationSha` (the pure `[fern-generated]`
|
|
613
628
|
* SHA), NOT HEAD — mid-phase commits do not retarget patches' `base_generation`.
|
|
614
629
|
* - The service instance is single-use across the phase boundary: do not call
|
|
615
|
-
*
|
|
616
|
-
*
|
|
630
|
+
* another `prepareReplay()` between phases. In-memory lockfile and warning
|
|
631
|
+
* state would be corrupted.
|
|
617
632
|
* - If the caller's mid-phase work throws or `applyPreparedReplay` is never called,
|
|
618
633
|
* the repo is left with the new `[fern-generated]` commit but a stale lockfile.
|
|
619
634
|
* Consumers MUST either (a) still call `applyPreparedReplay` so the lockfile
|
|
@@ -628,8 +643,6 @@ interface ReplayPreparation {
|
|
|
628
643
|
previousGenerationSha: string | null;
|
|
629
644
|
/** SHA of the new [fern-generated] commit created by prepareReplay (or HEAD for dry-run terminals) */
|
|
630
645
|
currentGenerationSha: string;
|
|
631
|
-
/** options.baseBranchHead passed through */
|
|
632
|
-
baseBranchHead: string | null;
|
|
633
646
|
/** @internal Opaque state consumed by applyPreparedReplay */
|
|
634
647
|
readonly _prepared: InternalPreparationState;
|
|
635
648
|
}
|
|
@@ -749,21 +762,6 @@ declare class ReplayService {
|
|
|
749
762
|
* Behavior is byte-identical to the pre-split implementation for all existing callers.
|
|
750
763
|
*/
|
|
751
764
|
runReplay(options?: ReplayOptions): Promise<ReplayReport>;
|
|
752
|
-
/**
|
|
753
|
-
* Sync the lockfile after a divergent PR was squash-merged.
|
|
754
|
-
* Call this BEFORE runReplay() when the CLI detects a merged divergent PR.
|
|
755
|
-
*
|
|
756
|
-
* After updating the generation record, re-detects customer patches via
|
|
757
|
-
* tree diff between the generation tag (pure generation tree) and HEAD
|
|
758
|
-
* (which includes customer customizations after squash merge). This ensures
|
|
759
|
-
* patches survive the squash merge → regenerate cycle even when the lockfile
|
|
760
|
-
* was restored from the base branch during conflict PR creation.
|
|
761
|
-
*/
|
|
762
|
-
syncFromDivergentMerge(generationCommitSha: string, options?: {
|
|
763
|
-
cliVersion?: string;
|
|
764
|
-
generatorVersions?: Record<string, string>;
|
|
765
|
-
baseBranchHead?: string;
|
|
766
|
-
}): Promise<void>;
|
|
767
765
|
private determineFlow;
|
|
768
766
|
/**
|
|
769
767
|
* Rebase cleanly applied patches so they are relative to the current generation.
|
|
@@ -887,7 +885,8 @@ declare class ReplayService {
|
|
|
887
885
|
*/
|
|
888
886
|
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
889
887
|
cleanupStaleConflictMarkers(): Promise<void>;
|
|
890
|
-
|
|
888
|
+
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
889
|
+
readFernignorePatterns(): string[];
|
|
891
890
|
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
892
891
|
buildReport(flow: "first-generation" | "no-patches" | "normal-regeneration" | "skip-application", patches: StoredPatch[], results: ReplayResult[], options?: ReplayOptions, warnings?: string[], rebaseCounts?: {
|
|
893
892
|
absorbed: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,8 +12,6 @@ interface GenerationRecord {
|
|
|
12
12
|
timestamp: string;
|
|
13
13
|
cli_version: string;
|
|
14
14
|
generator_versions: Record<string, string>;
|
|
15
|
-
/** SHA of the base branch HEAD before replay ran. Always on main's lineage. */
|
|
16
|
-
base_branch_head?: string;
|
|
17
15
|
}
|
|
18
16
|
interface StoredPatch {
|
|
19
17
|
id: string;
|
|
@@ -216,8 +214,19 @@ declare class LockfileNotFoundError extends Error {
|
|
|
216
214
|
declare class LockfileManager {
|
|
217
215
|
private outputDir;
|
|
218
216
|
private lock;
|
|
217
|
+
private fernignorePatterns;
|
|
219
218
|
readonly warnings: string[];
|
|
220
219
|
constructor(outputDir: string);
|
|
220
|
+
/**
|
|
221
|
+
* Inform the lockfile of the customer's `.fernignore` patterns so that
|
|
222
|
+
* `save()` can suppress its "Patch X removed from lockfile" warning when
|
|
223
|
+
* every file in the stripped patch is already `.fernignore`-protected.
|
|
224
|
+
* The strip itself still happens (credentials never persist); only the
|
|
225
|
+
* customer-visible warning is suppressed in that case, because the
|
|
226
|
+
* protected files survive the generator wipe regardless of whether the
|
|
227
|
+
* lockfile tracks them, so there's nothing for the customer to action.
|
|
228
|
+
*/
|
|
229
|
+
setFernignorePatterns(patterns: string[]): void;
|
|
221
230
|
get lockfilePath(): string;
|
|
222
231
|
get customizationsPath(): string;
|
|
223
232
|
exists(): boolean;
|
|
@@ -259,22 +268,24 @@ declare class ReplayDetector {
|
|
|
259
268
|
private sdkOutputDir;
|
|
260
269
|
readonly warnings: string[];
|
|
261
270
|
constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string);
|
|
262
|
-
detectNewPatches(): Promise<DetectionResult>;
|
|
263
271
|
/**
|
|
264
|
-
*
|
|
272
|
+
* Derive the previous-generation SHA from git history instead of trusting
|
|
273
|
+
* `lock.current_generation`.
|
|
265
274
|
*
|
|
266
|
-
*
|
|
267
|
-
* `
|
|
268
|
-
*
|
|
269
|
-
* a reachable ancestor of HEAD. Walking that range and classifying each
|
|
270
|
-
* commit via `isGenerationCommit` mirrors the linear path and eliminates
|
|
271
|
-
* the bug class where pipeline-driven changes (autoversion, replay,
|
|
272
|
-
* generation) get bundled as customer customizations.
|
|
275
|
+
* Walks `git log HEAD --first-parent` and returns the SHA of the most recent
|
|
276
|
+
* commit that `isGenerationBoundary` classifies as a customization-baseline
|
|
277
|
+
* boundary, or null if no such commit is reachable from HEAD on the mainline.
|
|
273
278
|
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
279
|
+
* `isGenerationBoundary` is intentionally narrower than `isGenerationCommit`:
|
|
280
|
+
* it excludes `[fern-autoversion]` (lightweight bumps that don't reset the
|
|
281
|
+
* baseline) and the GitHub merge-commit subject for fern-bot regen PRs
|
|
282
|
+
* (which sits on first-parent but where the customer fix-up commits live
|
|
283
|
+
* on second-parent — stopping at the merge would hide them).
|
|
284
|
+
*
|
|
285
|
+
* See docs/adr/0001-derived-scan-boundary.md.
|
|
276
286
|
*/
|
|
277
|
-
|
|
287
|
+
findPreviousGenerationFromHistory(): Promise<string | null>;
|
|
288
|
+
detectNewPatches(): Promise<DetectionResult>;
|
|
278
289
|
/**
|
|
279
290
|
* Walk `${rangeStart}..HEAD`, classify each commit, emit one
|
|
280
291
|
* `StoredPatch` per customer commit. Body shared by the linear path
|
|
@@ -368,6 +379,13 @@ declare class ReplayDetector {
|
|
|
368
379
|
private resolveDiffBase;
|
|
369
380
|
private parseGitLog;
|
|
370
381
|
private getLastGeneration;
|
|
382
|
+
/**
|
|
383
|
+
* Build a transient `GenerationRecord` from a SHA derived by walking git
|
|
384
|
+
* history. Only `commit_sha` (and `tree_hash` when needed downstream) is
|
|
385
|
+
* load-bearing here; the rest are filled with defensible placeholders.
|
|
386
|
+
* This record is consumed by `detectPatchesInRange` and is never persisted.
|
|
387
|
+
*/
|
|
388
|
+
private synthesizeGenerationRecord;
|
|
371
389
|
}
|
|
372
390
|
|
|
373
391
|
/**
|
|
@@ -468,7 +486,6 @@ declare class ReplayApplicator {
|
|
|
468
486
|
interface CommitOptions {
|
|
469
487
|
cliVersion: string;
|
|
470
488
|
generatorVersions: Record<string, string>;
|
|
471
|
-
baseBranchHead?: string;
|
|
472
489
|
}
|
|
473
490
|
declare class ReplayCommitter {
|
|
474
491
|
private git;
|
|
@@ -587,12 +604,10 @@ interface ReplayOptions {
|
|
|
587
604
|
generatorVersions?: Record<string, string>;
|
|
588
605
|
/** Commit generation + update lockfile, skip detection/application */
|
|
589
606
|
skipApplication?: boolean;
|
|
590
|
-
/** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */
|
|
591
|
-
baseBranchHead?: string;
|
|
592
607
|
}
|
|
593
608
|
/**
|
|
594
609
|
* Options honored by `applyPreparedReplay()`. `cliVersion`, `generatorVersions`,
|
|
595
|
-
* `
|
|
610
|
+
* `dryRun`, and `skipApplication` were all captured in phase 1
|
|
596
611
|
* and re-supplying them here is meaningless.
|
|
597
612
|
*/
|
|
598
613
|
interface ApplyOptions {
|
|
@@ -612,8 +627,8 @@ interface ApplyOptions {
|
|
|
612
627
|
* respected. `rebasePatches` uses `currentGenerationSha` (the pure `[fern-generated]`
|
|
613
628
|
* SHA), NOT HEAD — mid-phase commits do not retarget patches' `base_generation`.
|
|
614
629
|
* - The service instance is single-use across the phase boundary: do not call
|
|
615
|
-
*
|
|
616
|
-
*
|
|
630
|
+
* another `prepareReplay()` between phases. In-memory lockfile and warning
|
|
631
|
+
* state would be corrupted.
|
|
617
632
|
* - If the caller's mid-phase work throws or `applyPreparedReplay` is never called,
|
|
618
633
|
* the repo is left with the new `[fern-generated]` commit but a stale lockfile.
|
|
619
634
|
* Consumers MUST either (a) still call `applyPreparedReplay` so the lockfile
|
|
@@ -628,8 +643,6 @@ interface ReplayPreparation {
|
|
|
628
643
|
previousGenerationSha: string | null;
|
|
629
644
|
/** SHA of the new [fern-generated] commit created by prepareReplay (or HEAD for dry-run terminals) */
|
|
630
645
|
currentGenerationSha: string;
|
|
631
|
-
/** options.baseBranchHead passed through */
|
|
632
|
-
baseBranchHead: string | null;
|
|
633
646
|
/** @internal Opaque state consumed by applyPreparedReplay */
|
|
634
647
|
readonly _prepared: InternalPreparationState;
|
|
635
648
|
}
|
|
@@ -749,21 +762,6 @@ declare class ReplayService {
|
|
|
749
762
|
* Behavior is byte-identical to the pre-split implementation for all existing callers.
|
|
750
763
|
*/
|
|
751
764
|
runReplay(options?: ReplayOptions): Promise<ReplayReport>;
|
|
752
|
-
/**
|
|
753
|
-
* Sync the lockfile after a divergent PR was squash-merged.
|
|
754
|
-
* Call this BEFORE runReplay() when the CLI detects a merged divergent PR.
|
|
755
|
-
*
|
|
756
|
-
* After updating the generation record, re-detects customer patches via
|
|
757
|
-
* tree diff between the generation tag (pure generation tree) and HEAD
|
|
758
|
-
* (which includes customer customizations after squash merge). This ensures
|
|
759
|
-
* patches survive the squash merge → regenerate cycle even when the lockfile
|
|
760
|
-
* was restored from the base branch during conflict PR creation.
|
|
761
|
-
*/
|
|
762
|
-
syncFromDivergentMerge(generationCommitSha: string, options?: {
|
|
763
|
-
cliVersion?: string;
|
|
764
|
-
generatorVersions?: Record<string, string>;
|
|
765
|
-
baseBranchHead?: string;
|
|
766
|
-
}): Promise<void>;
|
|
767
765
|
private determineFlow;
|
|
768
766
|
/**
|
|
769
767
|
* Rebase cleanly applied patches so they are relative to the current generation.
|
|
@@ -887,7 +885,8 @@ declare class ReplayService {
|
|
|
887
885
|
*/
|
|
888
886
|
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
889
887
|
cleanupStaleConflictMarkers(): Promise<void>;
|
|
890
|
-
|
|
888
|
+
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
889
|
+
readFernignorePatterns(): string[];
|
|
891
890
|
/** @internal Used by Flow implementations in `src/flows/`. */
|
|
892
891
|
buildReport(flow: "first-generation" | "no-patches" | "normal-regeneration" | "skip-application", patches: StoredPatch[], results: ReplayResult[], options?: ReplayOptions, warnings?: string[], rebaseCounts?: {
|
|
893
892
|
absorbed: number;
|