@fern-api/replay 0.10.4 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +928 -100
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +820 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +277 -11
- package/dist/index.d.ts +277 -11
- package/dist/index.js +814 -99
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,15 @@ interface StoredPatch {
|
|
|
28
28
|
* When "resolving", the resolve command has applied patches to the working tree
|
|
29
29
|
* and is waiting for the customer to resolve conflicts and run resolve again. */
|
|
30
30
|
status?: "unresolved" | "resolving";
|
|
31
|
+
/**
|
|
32
|
+
* True when the patch introduces files that the generator has never produced
|
|
33
|
+
* (new-file creations). User-owned patches are immune to absorption checks in
|
|
34
|
+
* `rebasePatches`, `trimAbsorbedFiles`, and `preGenerationRebase`. Set at
|
|
35
|
+
* detection time by observing `--- /dev/null` headers in patch_content, or at
|
|
36
|
+
* rebase time by the reachability-aware helper. Once true, never cleared —
|
|
37
|
+
* the generator will not start producing a file it never produced before.
|
|
38
|
+
*/
|
|
39
|
+
user_owned?: boolean;
|
|
31
40
|
}
|
|
32
41
|
interface CustomizationsConfig {
|
|
33
42
|
exclude?: string[];
|
|
@@ -83,6 +92,29 @@ interface ReplayConfig {
|
|
|
83
92
|
enabled: boolean;
|
|
84
93
|
}
|
|
85
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Credential detection patterns for the replay pipeline.
|
|
97
|
+
*
|
|
98
|
+
* Two-layer defense against credential leaks in .fern/replay.lock:
|
|
99
|
+
* Layer 1 — file-level: SENSITIVE_FILE_PATTERNS blocks entire files (.env, .pem, etc.)
|
|
100
|
+
* Layer 2 — content-level: CREDENTIAL_PATTERNS catches inline secrets in any file
|
|
101
|
+
*
|
|
102
|
+
* These patterns mirror the invariant assertions in __tests__/invariants/i4-credential-containment.ts.
|
|
103
|
+
* If they diverge, the invariant tests independently catch real leaks.
|
|
104
|
+
*
|
|
105
|
+
* @security FER-9807
|
|
106
|
+
*/
|
|
107
|
+
interface CredentialPattern {
|
|
108
|
+
name: string;
|
|
109
|
+
re: RegExp;
|
|
110
|
+
}
|
|
111
|
+
declare const CREDENTIAL_PATTERNS: ReadonlyArray<CredentialPattern>;
|
|
112
|
+
declare const SENSITIVE_FILE_PATTERNS: ReadonlyArray<RegExp>;
|
|
113
|
+
/** Check if a file path matches any sensitive file pattern. */
|
|
114
|
+
declare function isSensitiveFile(filePath: string): boolean;
|
|
115
|
+
/** Scan content for credential patterns. Returns matched pattern names. */
|
|
116
|
+
declare function scanForCredentials(content: string): string[];
|
|
117
|
+
|
|
86
118
|
declare class GitClient {
|
|
87
119
|
private git;
|
|
88
120
|
private repoPath;
|
|
@@ -95,6 +127,16 @@ declare class GitClient {
|
|
|
95
127
|
showFile(treeish: string, filePath: string): Promise<string | null>;
|
|
96
128
|
getCommitInfo(commitSha: string): Promise<CommitInfo>;
|
|
97
129
|
getCommitParents(commitSha: string): Promise<string[]>;
|
|
130
|
+
/**
|
|
131
|
+
* Detects renames and copies between two trees.
|
|
132
|
+
*
|
|
133
|
+
* Both `R` (rename) and `C` (copy) entries are returned as `{from, to}` pairs.
|
|
134
|
+
* Copies are treated as rename-equivalent because the generator may produce the
|
|
135
|
+
* new path while the old path remains in the tree (e.g., imperfect cleanup,
|
|
136
|
+
* customer edits at the old path, or test helpers that only write new files).
|
|
137
|
+
* Callers that care about "is the source still present" should verify via
|
|
138
|
+
* `showFile(toTree, from)`.
|
|
139
|
+
*/
|
|
98
140
|
detectRenames(fromTree: string, toTree: string): Promise<Array<{
|
|
99
141
|
from: string;
|
|
100
142
|
to: string;
|
|
@@ -124,6 +166,7 @@ declare class LockfileNotFoundError extends Error {
|
|
|
124
166
|
declare class LockfileManager {
|
|
125
167
|
private outputDir;
|
|
126
168
|
private lock;
|
|
169
|
+
readonly warnings: string[];
|
|
127
170
|
constructor(outputDir: string);
|
|
128
171
|
get lockfilePath(): string;
|
|
129
172
|
get customizationsPath(): string;
|
|
@@ -139,7 +182,7 @@ declare class LockfileManager {
|
|
|
139
182
|
save(): void;
|
|
140
183
|
addGeneration(record: GenerationRecord): void;
|
|
141
184
|
addPatch(patch: StoredPatch): void;
|
|
142
|
-
updatePatch(patchId: string, updates: Partial<Pick<StoredPatch, "base_generation" | "patch_content" | "content_hash" | "files" | "status">>): void;
|
|
185
|
+
updatePatch(patchId: string, updates: Partial<Pick<StoredPatch, "base_generation" | "patch_content" | "content_hash" | "files" | "status" | "user_owned">>): void;
|
|
143
186
|
removePatch(patchId: string): void;
|
|
144
187
|
clearPatches(): void;
|
|
145
188
|
addForgottenHash(hash: string): void;
|
|
@@ -169,10 +212,60 @@ declare class ReplayDetector {
|
|
|
169
212
|
detectNewPatches(): Promise<DetectionResult>;
|
|
170
213
|
/**
|
|
171
214
|
* Compute content hash for deduplication.
|
|
172
|
-
*
|
|
173
|
-
*
|
|
215
|
+
*
|
|
216
|
+
* Produces a format-agnostic hash so both `git format-patch` output
|
|
217
|
+
* (email-wrapped) and plain `git diff` output hash to the same value
|
|
218
|
+
* when the underlying diff hunks are identical.
|
|
219
|
+
*
|
|
220
|
+
* Normalization:
|
|
221
|
+
* 1. Strip email wrapper: everything before the first `diff --git` line
|
|
222
|
+
* (From:, Subject:, Date:, diffstat, blank separators).
|
|
223
|
+
* 2. Strip `index` lines (blob SHA pairs change across rebases).
|
|
224
|
+
* 3. Strip trailing git version marker (`-- \n<version>`).
|
|
225
|
+
*
|
|
226
|
+
* This ensures content hashes match across the no-patches and normal-
|
|
227
|
+
* regeneration flows, which store formatPatch and git-diff formats
|
|
228
|
+
* respectively (FER-9850, D5-D9).
|
|
174
229
|
*/
|
|
175
230
|
computeContentHash(patchContent: string): string;
|
|
231
|
+
/**
|
|
232
|
+
* FER-9805 — Drop patches whose files were transiently created and then
|
|
233
|
+
* deleted within the current linear detection window, and are absent from
|
|
234
|
+
* HEAD at the end of the window.
|
|
235
|
+
*
|
|
236
|
+
* Rationale: on a merge commit, createMergeCompositePatch already diffs
|
|
237
|
+
* firstParent..mergeCommit so net-zero files never enter the composite. On
|
|
238
|
+
* linear history each commit becomes its own patch, so a file that was
|
|
239
|
+
* briefly added and later removed survives as a create+delete pair whose
|
|
240
|
+
* cumulative diff is empty. We drop such patches before they reach the
|
|
241
|
+
* lockfile.
|
|
242
|
+
*
|
|
243
|
+
* A file is "transient" when:
|
|
244
|
+
* 1. some patch in the window sets `new file mode` for it (a creation), AND
|
|
245
|
+
* 2. some patch in the window sets `deleted file mode` for it (a deletion), AND
|
|
246
|
+
* 3. it is absent from HEAD's tree.
|
|
247
|
+
*
|
|
248
|
+
* The HEAD guard (#3) prevents false positives when a file is deleted
|
|
249
|
+
* and then recreated with different content — the cumulative diff of
|
|
250
|
+
* such a pair is non-empty and must be preserved.
|
|
251
|
+
*
|
|
252
|
+
* This only drops patches whose `files` are a subset of the transient
|
|
253
|
+
* set. A partial-transient patch (one that touches a transient file
|
|
254
|
+
* alongside a persistent one) is left unmodified; surgical stripping of
|
|
255
|
+
* single files from a multi-file patch would require a follow-up that
|
|
256
|
+
* regenerates the patch content via `git format-patch -- <files>`. No
|
|
257
|
+
* current failing test exercises this, and leaving the patch intact
|
|
258
|
+
* preserves today's behaviour. TODO(FER-9805): revisit if a future
|
|
259
|
+
* adversarial test demands per-file stripping.
|
|
260
|
+
*/
|
|
261
|
+
private collapseNetZeroFiles;
|
|
262
|
+
/**
|
|
263
|
+
* List every tracked path at HEAD (one `git ls-tree -r` invocation).
|
|
264
|
+
* Returns an empty Set if HEAD is unborn or the invocation fails — the
|
|
265
|
+
* caller then treats every candidate as "not in HEAD" and may collapse
|
|
266
|
+
* more aggressively. On typical SDK repos this is a single sub-10ms call.
|
|
267
|
+
*/
|
|
268
|
+
private listHeadFiles;
|
|
176
269
|
/**
|
|
177
270
|
* Create a single composite patch for a merge commit by diffing the merge
|
|
178
271
|
* commit against its first parent. This captures the net change of the
|
|
@@ -237,6 +330,17 @@ declare class ReplayApplicator {
|
|
|
237
330
|
private resolveBaseGeneration;
|
|
238
331
|
/** Reset inter-patch accumulator for a new cycle. */
|
|
239
332
|
private resetAccumulator;
|
|
333
|
+
/**
|
|
334
|
+
* @internal Test-only.
|
|
335
|
+
* Returns a defensive copy of the inter-patch accumulator. Used by the
|
|
336
|
+
* adversarial test suite (FER-9791) to assert invariant I2: after every
|
|
337
|
+
* applied patch, the accumulator has an entry for each file the patch
|
|
338
|
+
* touched, and the entry's content matches on-disk.
|
|
339
|
+
*/
|
|
340
|
+
getAccumulatorSnapshot(): ReadonlyMap<string, {
|
|
341
|
+
content: string;
|
|
342
|
+
baseGeneration: string;
|
|
343
|
+
}>;
|
|
240
344
|
/**
|
|
241
345
|
* Apply all patches, returning results for each.
|
|
242
346
|
* Skips patches that match exclude patterns in replay.yml
|
|
@@ -251,6 +355,14 @@ declare class ReplayApplicator {
|
|
|
251
355
|
private isExcluded;
|
|
252
356
|
private resolveFilePath;
|
|
253
357
|
private applyPatchToContent;
|
|
358
|
+
/**
|
|
359
|
+
* Detects whether a patch's additions are already present in `content`.
|
|
360
|
+
* Uses `git apply --reverse --check` — if the reverse patch applies cleanly,
|
|
361
|
+
* the forward patch is effectively a no-op (its +lines are already there and
|
|
362
|
+
* its -lines are already gone). Used to distinguish "patch already applied"
|
|
363
|
+
* from "patch base mismatch" after a forward-apply fails.
|
|
364
|
+
*/
|
|
365
|
+
private isPatchAlreadyApplied;
|
|
254
366
|
private extractFileDiff;
|
|
255
367
|
private extractRenameSource;
|
|
256
368
|
private extractNewFileFromPatch;
|
|
@@ -322,6 +434,72 @@ interface ReplayOptions {
|
|
|
322
434
|
/** SHA of the base branch HEAD before replay runs. Stored in lockfile for squash merge recovery. */
|
|
323
435
|
baseBranchHead?: string;
|
|
324
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Options honored by `applyPreparedReplay()`. `cliVersion`, `generatorVersions`,
|
|
439
|
+
* `baseBranchHead`, `dryRun`, and `skipApplication` were all captured in phase 1
|
|
440
|
+
* and re-supplying them here is meaningless.
|
|
441
|
+
*/
|
|
442
|
+
interface ApplyOptions {
|
|
443
|
+
/** Write files and stage changes, but don't commit */
|
|
444
|
+
stageOnly?: boolean;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Opaque handle returned by `prepareReplay()`. Consumed by `applyPreparedReplay()`
|
|
448
|
+
* to complete the run.
|
|
449
|
+
*
|
|
450
|
+
* Contract for consumers (e.g., generator-cli pipeline inserting AutoVersionStep):
|
|
451
|
+
*
|
|
452
|
+
* - Between `prepareReplay` and `applyPreparedReplay`, HEAD is at the new
|
|
453
|
+
* `[fern-generated]` commit (unless `_prepared.terminal === true`, e.g. dry-run).
|
|
454
|
+
* - Consumers MAY land additional commits on HEAD between phases. `applyPatches`
|
|
455
|
+
* runs against current HEAD at phase-2 call time, so mid-phase commits are
|
|
456
|
+
* respected. `rebasePatches` uses `currentGenerationSha` (the pure `[fern-generated]`
|
|
457
|
+
* SHA), NOT HEAD — mid-phase commits do not retarget patches' `base_generation`.
|
|
458
|
+
* - The service instance is single-use across the phase boundary: do not call
|
|
459
|
+
* other service methods (`syncFromDivergentMerge`, another `prepareReplay`, etc.)
|
|
460
|
+
* between phases. In-memory lockfile and warning state would be corrupted.
|
|
461
|
+
* - If the caller's mid-phase work throws or `applyPreparedReplay` is never called,
|
|
462
|
+
* the repo is left with the new `[fern-generated]` commit but a stale lockfile.
|
|
463
|
+
* Consumers MUST either (a) still call `applyPreparedReplay` so the lockfile
|
|
464
|
+
* advances, or (b) reset HEAD to `previousGenerationSha` and surface the failure.
|
|
465
|
+
*
|
|
466
|
+
* To decide whether to run autoversion between phases, use:
|
|
467
|
+
* prep.previousGenerationSha != null && prep.flow !== "skip-application"
|
|
468
|
+
*/
|
|
469
|
+
interface ReplayPreparation {
|
|
470
|
+
flow: "first-generation" | "no-patches" | "normal-regeneration" | "skip-application";
|
|
471
|
+
/** lockfile.current_generation from BEFORE this run; null iff no prior generation exists */
|
|
472
|
+
previousGenerationSha: string | null;
|
|
473
|
+
/** SHA of the new [fern-generated] commit created by prepareReplay (or HEAD for dry-run terminals) */
|
|
474
|
+
currentGenerationSha: string;
|
|
475
|
+
/** options.baseBranchHead passed through */
|
|
476
|
+
baseBranchHead: string | null;
|
|
477
|
+
/** @internal Opaque state consumed by applyPreparedReplay */
|
|
478
|
+
readonly _prepared: InternalPreparationState;
|
|
479
|
+
}
|
|
480
|
+
/** @internal */
|
|
481
|
+
interface InternalPreparationState {
|
|
482
|
+
flow: "first-generation" | "no-patches" | "normal-regeneration" | "skip-application";
|
|
483
|
+
/** true → applyPreparedReplay returns preparedReport without disk/git work (dry-run path) */
|
|
484
|
+
terminal: boolean;
|
|
485
|
+
preparedReport?: ReplayReport;
|
|
486
|
+
/** post-preGenRebase, post-detection, post-absorption (references, not copies) */
|
|
487
|
+
patchesToApply: StoredPatch[];
|
|
488
|
+
/** subset of patchesToApply that were freshly detected this cycle (vs already in the lockfile) */
|
|
489
|
+
newPatchIds: Set<string>;
|
|
490
|
+
preRebaseCounts?: {
|
|
491
|
+
conflictResolved: number;
|
|
492
|
+
conflictAbsorbed: number;
|
|
493
|
+
contentRefreshed: number;
|
|
494
|
+
};
|
|
495
|
+
/** detector warnings snapshotted at end of phase 1 */
|
|
496
|
+
detectorWarnings: string[];
|
|
497
|
+
revertedCount: number;
|
|
498
|
+
/** [fern-generated] SHA; passed to rebasePatches as currentGenSha */
|
|
499
|
+
genSha: string;
|
|
500
|
+
/** cached phase-1 options for constructing the final ReplayReport in phase 2 */
|
|
501
|
+
optionsSnapshot?: ReplayOptions;
|
|
502
|
+
}
|
|
325
503
|
declare class ReplayService {
|
|
326
504
|
private git;
|
|
327
505
|
private detector;
|
|
@@ -329,7 +507,57 @@ declare class ReplayService {
|
|
|
329
507
|
private committer;
|
|
330
508
|
private lockManager;
|
|
331
509
|
private outputDir;
|
|
510
|
+
/** @internal Test-only. Captures the last ReplayResult[] returned from applicator.applyPatches(). */
|
|
511
|
+
private _lastApplyResults;
|
|
512
|
+
/**
|
|
513
|
+
* Service-level warnings accumulated during a single runReplay() call.
|
|
514
|
+
* Merged with `detector.warnings` into `ReplayReport.warnings` by each flow handler.
|
|
515
|
+
* Populated by `isFileUserOwned` when a patch's base generation tree is unreachable
|
|
516
|
+
* (shallow clone / aggressive `git gc --prune`) and we fall back to a conservative
|
|
517
|
+
* heuristic. Cleared at the top of `runReplay()`.
|
|
518
|
+
*/
|
|
519
|
+
private warnings;
|
|
520
|
+
/**
|
|
521
|
+
* @internal Test-only accessor.
|
|
522
|
+
* Returns the ReplayApplicator instance used for the last run. Tests use this
|
|
523
|
+
* to inspect the inter-patch accumulator after runReplay() completes (FER-9791, I2).
|
|
524
|
+
*/
|
|
525
|
+
get applicatorRef(): ReplayApplicator;
|
|
526
|
+
/**
|
|
527
|
+
* @internal Test-only accessor.
|
|
528
|
+
* Returns the ReplayResult[] from the most recent applyPatches() call. Tests use
|
|
529
|
+
* this to filter applied-vs-conflicted-vs-absorbed patches for invariant assertions
|
|
530
|
+
* (FER-9791). Returns an empty array if no patches have been applied yet.
|
|
531
|
+
*/
|
|
532
|
+
getLastResults(): ReadonlyArray<ReplayResult>;
|
|
332
533
|
constructor(outputDir: string, _config: ReplayConfig);
|
|
534
|
+
/**
|
|
535
|
+
* Phase 1 of the two-phase replay flow. Runs preGenerationRebase (when applicable),
|
|
536
|
+
* detects new patches, and creates the `[fern-generated]` commit. Leaves HEAD at
|
|
537
|
+
* the generation commit (or unchanged for dry-run).
|
|
538
|
+
*
|
|
539
|
+
* Does NOT apply patches — the returned handle must be passed to
|
|
540
|
+
* `applyPreparedReplay()` to complete the run. No disk writes to the lockfile
|
|
541
|
+
* happen here; lockfile persistence is deferred to phase 2.
|
|
542
|
+
*
|
|
543
|
+
* Callers may land additional commits on HEAD between `prepareReplay` and
|
|
544
|
+
* `applyPreparedReplay` (e.g., `[fern-autoversion]`).
|
|
545
|
+
*/
|
|
546
|
+
prepareReplay(options?: ReplayOptions): Promise<ReplayPreparation>;
|
|
547
|
+
/**
|
|
548
|
+
* Phase 2 of the two-phase replay flow. Applies patches, rebases them against
|
|
549
|
+
* the generation, saves the lockfile, and commits `[fern-replay]` (or stages
|
|
550
|
+
* under `stageOnly`). Operates on HEAD at call time — mid-phase commits are
|
|
551
|
+
* respected.
|
|
552
|
+
*
|
|
553
|
+
* For terminal handles (dry-run, first-gen has no patch work, skip-app does
|
|
554
|
+
* its own post-commit logic), this returns the precomputed report.
|
|
555
|
+
*/
|
|
556
|
+
applyPreparedReplay(prep: ReplayPreparation, options?: ApplyOptions): Promise<ReplayReport>;
|
|
557
|
+
/**
|
|
558
|
+
* Backwards-compatible atomic entry point. Composes `prepareReplay` + `applyPreparedReplay`.
|
|
559
|
+
* Behavior is byte-identical to the pre-split implementation for all existing callers.
|
|
560
|
+
*/
|
|
333
561
|
runReplay(options?: ReplayOptions): Promise<ReplayReport>;
|
|
334
562
|
/**
|
|
335
563
|
* Sync the lockfile after a divergent PR was squash-merged.
|
|
@@ -347,21 +575,59 @@ declare class ReplayService {
|
|
|
347
575
|
baseBranchHead?: string;
|
|
348
576
|
}): Promise<void>;
|
|
349
577
|
private determineFlow;
|
|
350
|
-
private
|
|
578
|
+
private firstGenerationReport;
|
|
579
|
+
private _prepareFirstGeneration;
|
|
580
|
+
private _applyFirstGeneration;
|
|
351
581
|
/**
|
|
352
|
-
* Skip-application mode: commit the generation and update the
|
|
353
|
-
* but don't detect or apply patches. Sets a marker
|
|
354
|
-
* run skips revert detection in preGenerationRebase().
|
|
582
|
+
* Skip-application mode phase 1: commit the generation and update the
|
|
583
|
+
* in-memory lockfile, but don't detect or apply patches. Sets a marker
|
|
584
|
+
* so the next normal run skips revert detection in preGenerationRebase().
|
|
585
|
+
*
|
|
586
|
+
* Disk save is deferred to `_applySkipApplication`.
|
|
355
587
|
*/
|
|
356
|
-
private
|
|
357
|
-
private
|
|
358
|
-
private
|
|
588
|
+
private _prepareSkipApplication;
|
|
589
|
+
private _applySkipApplication;
|
|
590
|
+
private _prepareNoPatchesRegeneration;
|
|
591
|
+
private _applyNoPatchesRegeneration;
|
|
592
|
+
private _prepareNormalRegeneration;
|
|
593
|
+
private _applyNormalRegeneration;
|
|
359
594
|
/**
|
|
360
595
|
* Rebase cleanly applied patches so they are relative to the current generation.
|
|
361
596
|
* This prevents recurring conflicts on subsequent regenerations.
|
|
362
597
|
* Returns the number of patches rebased.
|
|
363
598
|
*/
|
|
364
599
|
private rebasePatches;
|
|
600
|
+
/**
|
|
601
|
+
* Determine whether `file` is user-owned (never produced by the generator).
|
|
602
|
+
*
|
|
603
|
+
* Resolution order (first match wins):
|
|
604
|
+
* 1. `patch.user_owned === true` — authoritative, persisted across cycles.
|
|
605
|
+
* 2. `.fernignore` itself, or file matches a .fernignore pattern.
|
|
606
|
+
* 3. Legacy-safe signal: `patch_content` shows this file as a `--- /dev/null`
|
|
607
|
+
* creation. Works for patches that predate the `user_owned` field or
|
|
608
|
+
* whose flag was lost. Immune to rename tricks — relies on raw patch text.
|
|
609
|
+
* 4. Tree-based check against `patch.base_generation` when it is reachable
|
|
610
|
+
* AND distinct from `currentGenSha`. If the base tree is unreachable
|
|
611
|
+
* (shallow clone / aggressive `git gc --prune`), emit a one-time
|
|
612
|
+
* customer-actionable warning (deduplicated via warnedGens) and
|
|
613
|
+
* conservatively treat as user-owned — strictly safer than silent
|
|
614
|
+
* absorption (FER-9809).
|
|
615
|
+
* 5. Final fallback — check `currentGenSha` when there is no usable base
|
|
616
|
+
* (legacy one-gen lockfile). Preserves pre-fix behavior for that edge.
|
|
617
|
+
*
|
|
618
|
+
* `originalFileName` is the pre-rename path when the generator moved the
|
|
619
|
+
* file between the patch's base and the current generation. Tree lookups
|
|
620
|
+
* at ancestor generations use the original path — that's where the
|
|
621
|
+
* generator produced the content.
|
|
622
|
+
*/
|
|
623
|
+
private isFileUserOwned;
|
|
624
|
+
/**
|
|
625
|
+
* Returns true if `file`'s diff section in `patchContent` starts with
|
|
626
|
+
* `--- /dev/null`, meaning this file was introduced by the patch (user
|
|
627
|
+
* creation). Used as a legacy-safe fallback when `patch.user_owned` is
|
|
628
|
+
* absent or cleared.
|
|
629
|
+
*/
|
|
630
|
+
private fileIsCreationInPatchContent;
|
|
365
631
|
/**
|
|
366
632
|
* For conflict patches with mixed results (some files merged, some conflicted),
|
|
367
633
|
* check if the cleanly merged files were absorbed by the generator (empty diff).
|
|
@@ -595,4 +861,4 @@ interface StatusGeneration {
|
|
|
595
861
|
}
|
|
596
862
|
declare function status(outputDir: string): StatusResult;
|
|
597
863
|
|
|
598
|
-
export { type BootstrapOptions, type BootstrapResult, type CommitInfo, type CommitOptions, type ConflictDetail, type ConflictMetadata, type ConflictReason, type ConflictRegion, type CustomizationsConfig, type DetectionResult, type DiffStat, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_BOT_NAME, FernignoreMigrator, type FileResult, type ForgetOptions, type ForgetResult, type GenerationLock, type GenerationRecord, GitClient, LockfileManager, LockfileNotFoundError, type MatchedPatch, 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, type UnresolvedPatchInfo, bootstrap, forget, isGenerationCommit, isReplayCommit, isRevertCommit, parseRevertedMessage, parseRevertedSha, reset, resolve, status, threeWayMerge };
|
|
864
|
+
export { type ApplyOptions, type BootstrapOptions, type BootstrapResult, CREDENTIAL_PATTERNS, type CommitInfo, type CommitOptions, type ConflictDetail, type ConflictMetadata, type ConflictReason, type ConflictRegion, type CredentialPattern, type CustomizationsConfig, type DetectionResult, type DiffStat, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_BOT_NAME, FernignoreMigrator, type FileResult, type ForgetOptions, type ForgetResult, type GenerationLock, type GenerationRecord, GitClient, LockfileManager, LockfileNotFoundError, type MatchedPatch, type MergeResult, type MigrationAnalysis, type MigrationResult, type MoveDeclaration, ReplayApplicator, ReplayCommitter, type ReplayConfig, ReplayDetector, type ReplayOptions, type ReplayPreparation, type ReplayReport, type ReplayResult, ReplayService, type ResetOptions, type ResetResult, type ResolveOptions, type ResolveResult, SENSITIVE_FILE_PATTERNS, type StatusGeneration, type StatusPatch, type StatusResult, type StoredPatch, type UnresolvedPatchInfo, bootstrap, forget, isGenerationCommit, isReplayCommit, isRevertCommit, isSensitiveFile, parseRevertedMessage, parseRevertedSha, reset, resolve, scanForCredentials, status, threeWayMerge };
|