@fern-api/generator-cli 0.8.1 → 0.9.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/api.d.ts +17 -3
- package/dist/api.js +42 -26
- package/dist/cli.js +639 -54
- package/package.json +2 -2
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BootstrapResult, ResolveResult, ReplayReport } from '@fern-api/replay';
|
|
2
|
-
export { ConflictDetail, ReplayReport, ResolveResult } from '@fern-api/replay';
|
|
1
|
+
import { ForgetOptions, ForgetResult, BootstrapResult, ResolveResult, ReplayReport, StatusResult } from '@fern-api/replay';
|
|
2
|
+
export { ConflictDetail, DiffStat, ForgetOptions, ForgetResult, MatchedPatch, ReplayReport, ResolveResult, StatusGeneration, StatusPatch, StatusResult } from '@fern-api/replay';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -614,6 +614,14 @@ declare function formatReplayPrBody(result: ReplayStepResult | undefined, option
|
|
|
614
614
|
repoUri?: string;
|
|
615
615
|
}): string | undefined;
|
|
616
616
|
|
|
617
|
+
interface ReplayForgetParams {
|
|
618
|
+
/** Directory containing the SDK (where .fern/replay.lock lives) */
|
|
619
|
+
outputDir: string;
|
|
620
|
+
/** Options controlling which patches to forget */
|
|
621
|
+
options?: ForgetOptions;
|
|
622
|
+
}
|
|
623
|
+
declare function replayForget(params: ReplayForgetParams): ForgetResult;
|
|
624
|
+
|
|
617
625
|
interface ReplayInitParams {
|
|
618
626
|
/** GitHub repo URI (e.g., "fern-demo/fern-replay-testbed-java-sdk") */
|
|
619
627
|
githubRepo: string;
|
|
@@ -699,4 +707,10 @@ interface ReplayRunResult {
|
|
|
699
707
|
}
|
|
700
708
|
declare function replayRun(params: ReplayRunParams): Promise<ReplayRunResult>;
|
|
701
709
|
|
|
702
|
-
|
|
710
|
+
interface ReplayStatusParams {
|
|
711
|
+
/** Directory containing the SDK (where .fern/replay.lock lives) */
|
|
712
|
+
outputDir: string;
|
|
713
|
+
}
|
|
714
|
+
declare function replayStatus(params: ReplayStatusParams): StatusResult;
|
|
715
|
+
|
|
716
|
+
export { type BootstrapLogEntry, type GenerateReadmeParams, type GenerateReadmeToStreamParams, type GenerateReferenceParams, type GenerateReferenceToStreamParams, type GithubPrParams, type GithubPushParams, type GithubReleaseParams, type GithubStepConfig, type GithubStepResult, type PipelineConfig, type PipelineContext, type PipelineLogger, type PipelineResult, PostGenerationPipeline, type ReplayForgetParams, type ReplayInitParams, type ReplayInitResult, type ReplayResolveParams, type ReplayRunParams, type ReplayRunResult, type ReplayStatusParams, type ReplayStepResult, consolePipelineLogger, formatBootstrapSummary, formatReplayPrBody, generateReadme, generateReadmeToStream, generateReference, generateReferenceToStream, githubPr, githubPush, githubRelease, logReplaySummary, replayForget, replayInit, replayResolve, replayRun, replayStatus };
|
package/dist/api.js
CHANGED
|
@@ -844,7 +844,7 @@ var require_dist2 = __commonJS({
|
|
|
844
844
|
function deferred2() {
|
|
845
845
|
let done;
|
|
846
846
|
let fail;
|
|
847
|
-
let
|
|
847
|
+
let status2 = "pending";
|
|
848
848
|
const promise = new Promise((_done, _fail) => {
|
|
849
849
|
done = _done;
|
|
850
850
|
fail = _fail;
|
|
@@ -852,22 +852,22 @@ var require_dist2 = __commonJS({
|
|
|
852
852
|
return {
|
|
853
853
|
promise,
|
|
854
854
|
done(result) {
|
|
855
|
-
if (
|
|
856
|
-
|
|
855
|
+
if (status2 === "pending") {
|
|
856
|
+
status2 = "resolved";
|
|
857
857
|
done(result);
|
|
858
858
|
}
|
|
859
859
|
},
|
|
860
860
|
fail(error) {
|
|
861
|
-
if (
|
|
862
|
-
|
|
861
|
+
if (status2 === "pending") {
|
|
862
|
+
status2 = "rejected";
|
|
863
863
|
fail(error);
|
|
864
864
|
}
|
|
865
865
|
},
|
|
866
866
|
get fulfilled() {
|
|
867
|
-
return
|
|
867
|
+
return status2 !== "pending";
|
|
868
868
|
},
|
|
869
869
|
get status() {
|
|
870
|
-
return
|
|
870
|
+
return status2;
|
|
871
871
|
}
|
|
872
872
|
};
|
|
873
873
|
}
|
|
@@ -892,9 +892,11 @@ __export(api_exports2, {
|
|
|
892
892
|
githubPush: () => githubPush,
|
|
893
893
|
githubRelease: () => githubRelease,
|
|
894
894
|
logReplaySummary: () => logReplaySummary,
|
|
895
|
+
replayForget: () => replayForget,
|
|
895
896
|
replayInit: () => replayInit,
|
|
896
897
|
replayResolve: () => replayResolve,
|
|
897
|
-
replayRun: () => replayRun
|
|
898
|
+
replayRun: () => replayRun,
|
|
899
|
+
replayStatus: () => replayStatus
|
|
898
900
|
});
|
|
899
901
|
module.exports = __toCommonJS(api_exports2);
|
|
900
902
|
|
|
@@ -2827,7 +2829,7 @@ var init_parse_diff_summary = __esm({
|
|
|
2827
2829
|
nameStatusParser = [
|
|
2828
2830
|
new LineParser(
|
|
2829
2831
|
/([ACDMRTUXB])([0-9]{0,3})\t(.[^\t]*)(\t(.[^\t]*))?$/,
|
|
2830
|
-
(result, [
|
|
2832
|
+
(result, [status2, similarity, from, _to, to]) => {
|
|
2831
2833
|
result.changed++;
|
|
2832
2834
|
result.files.push({
|
|
2833
2835
|
file: to ?? from,
|
|
@@ -2835,7 +2837,7 @@ var init_parse_diff_summary = __esm({
|
|
|
2835
2837
|
insertions: 0,
|
|
2836
2838
|
deletions: 0,
|
|
2837
2839
|
binary: false,
|
|
2838
|
-
status: orVoid(isDiffNameStatus(
|
|
2840
|
+
status: orVoid(isDiffNameStatus(status2) && status2),
|
|
2839
2841
|
from: orVoid(!!to && from !== to && from),
|
|
2840
2842
|
similarity: asNumber(similarity)
|
|
2841
2843
|
});
|
|
@@ -3361,10 +3363,10 @@ var init_merge = __esm({
|
|
|
3361
3363
|
init_task();
|
|
3362
3364
|
}
|
|
3363
3365
|
});
|
|
3364
|
-
function pushResultPushedItem(local, remote,
|
|
3365
|
-
const deleted =
|
|
3366
|
-
const tag =
|
|
3367
|
-
const alreadyUpdated = !
|
|
3366
|
+
function pushResultPushedItem(local, remote, status2) {
|
|
3367
|
+
const deleted = status2.includes("deleted");
|
|
3368
|
+
const tag = status2.includes("tag") || /^refs\/tags/.test(local);
|
|
3369
|
+
const alreadyUpdated = !status2.includes("new");
|
|
3368
3370
|
return {
|
|
3369
3371
|
deleted,
|
|
3370
3372
|
tag,
|
|
@@ -3678,7 +3680,7 @@ var init_StatusSummary = __esm({
|
|
|
3678
3680
|
]);
|
|
3679
3681
|
parseStatusSummary = function(text) {
|
|
3680
3682
|
const lines = text.split(NULL);
|
|
3681
|
-
const
|
|
3683
|
+
const status2 = new StatusSummary();
|
|
3682
3684
|
for (let i = 0, l = lines.length; i < l; ) {
|
|
3683
3685
|
let line = lines[i++].trim();
|
|
3684
3686
|
if (!line) {
|
|
@@ -3687,9 +3689,9 @@ var init_StatusSummary = __esm({
|
|
|
3687
3689
|
if (line.charAt(0) === "R") {
|
|
3688
3690
|
line += NULL + (lines[i++] || "");
|
|
3689
3691
|
}
|
|
3690
|
-
splitLine(
|
|
3692
|
+
splitLine(status2, line);
|
|
3691
3693
|
}
|
|
3692
|
-
return
|
|
3694
|
+
return status2;
|
|
3693
3695
|
};
|
|
3694
3696
|
}
|
|
3695
3697
|
});
|
|
@@ -4116,15 +4118,15 @@ var init_BranchSummary = __esm({
|
|
|
4116
4118
|
this.current = "";
|
|
4117
4119
|
this.detached = false;
|
|
4118
4120
|
}
|
|
4119
|
-
push(
|
|
4120
|
-
if (
|
|
4121
|
+
push(status2, detached, name, commit, label) {
|
|
4122
|
+
if (status2 === "*") {
|
|
4121
4123
|
this.detached = detached;
|
|
4122
4124
|
this.current = name;
|
|
4123
4125
|
}
|
|
4124
4126
|
this.all.push(name);
|
|
4125
4127
|
this.branches[name] = {
|
|
4126
|
-
current:
|
|
4127
|
-
linkedWorkTree:
|
|
4128
|
+
current: status2 === "*",
|
|
4129
|
+
linkedWorkTree: status2 === "+",
|
|
4128
4130
|
name,
|
|
4129
4131
|
commit,
|
|
4130
4132
|
label
|
|
@@ -10488,8 +10490,14 @@ var PostGenerationPipeline = class {
|
|
|
10488
10490
|
}
|
|
10489
10491
|
};
|
|
10490
10492
|
|
|
10491
|
-
// src/replay/replay-
|
|
10493
|
+
// src/replay/replay-forget.ts
|
|
10492
10494
|
var import_replay2 = require("@fern-api/replay");
|
|
10495
|
+
function replayForget(params) {
|
|
10496
|
+
return (0, import_replay2.forget)(params.outputDir, params.options);
|
|
10497
|
+
}
|
|
10498
|
+
|
|
10499
|
+
// src/replay/replay-init.ts
|
|
10500
|
+
var import_replay3 = require("@fern-api/replay");
|
|
10493
10501
|
var import_fs4 = require("fs");
|
|
10494
10502
|
var import_path6 = require("path");
|
|
10495
10503
|
var import_tmp_promise2 = __toESM(require("tmp-promise"));
|
|
@@ -10502,7 +10510,7 @@ async function replayInit(params) {
|
|
|
10502
10510
|
installationToken: token,
|
|
10503
10511
|
targetDirectory: repoPath
|
|
10504
10512
|
});
|
|
10505
|
-
const bootstrapResult = await (0,
|
|
10513
|
+
const bootstrapResult = await (0, import_replay3.bootstrap)(repoPath, {
|
|
10506
10514
|
dryRun,
|
|
10507
10515
|
fernignoreAction: "skip",
|
|
10508
10516
|
maxCommitsToScan: params.maxCommitsToScan,
|
|
@@ -10635,12 +10643,18 @@ function buildPrBody(result) {
|
|
|
10635
10643
|
}
|
|
10636
10644
|
|
|
10637
10645
|
// src/replay/replay-resolve.ts
|
|
10638
|
-
var
|
|
10646
|
+
var import_replay4 = require("@fern-api/replay");
|
|
10639
10647
|
async function replayResolve(params) {
|
|
10640
|
-
return (0,
|
|
10648
|
+
return (0, import_replay4.resolve)(params.outputDir, {
|
|
10641
10649
|
checkMarkers: params.checkMarkers
|
|
10642
10650
|
});
|
|
10643
10651
|
}
|
|
10652
|
+
|
|
10653
|
+
// src/replay/replay-status.ts
|
|
10654
|
+
var import_replay5 = require("@fern-api/replay");
|
|
10655
|
+
function replayStatus(params) {
|
|
10656
|
+
return (0, import_replay5.status)(params.outputDir);
|
|
10657
|
+
}
|
|
10644
10658
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10645
10659
|
0 && (module.exports = {
|
|
10646
10660
|
PostGenerationPipeline,
|
|
@@ -10655,7 +10669,9 @@ async function replayResolve(params) {
|
|
|
10655
10669
|
githubPush,
|
|
10656
10670
|
githubRelease,
|
|
10657
10671
|
logReplaySummary,
|
|
10672
|
+
replayForget,
|
|
10658
10673
|
replayInit,
|
|
10659
10674
|
replayResolve,
|
|
10660
|
-
replayRun
|
|
10675
|
+
replayRun,
|
|
10676
|
+
replayStatus
|
|
10661
10677
|
});
|
package/dist/cli.js
CHANGED
|
@@ -19759,7 +19759,7 @@ var init_diff3 = __esm({
|
|
|
19759
19759
|
}
|
|
19760
19760
|
});
|
|
19761
19761
|
|
|
19762
|
-
// ../../node_modules/.pnpm/@fern-api+replay@0.
|
|
19762
|
+
// ../../node_modules/.pnpm/@fern-api+replay@0.9.1/node_modules/@fern-api/replay/dist/index.js
|
|
19763
19763
|
var dist_exports = {};
|
|
19764
19764
|
__export(dist_exports, {
|
|
19765
19765
|
FERN_BOT_EMAIL: () => FERN_BOT_EMAIL2,
|
|
@@ -19784,6 +19784,241 @@ __export(dist_exports, {
|
|
|
19784
19784
|
status: () => status,
|
|
19785
19785
|
threeWayMerge: () => threeWayMerge
|
|
19786
19786
|
});
|
|
19787
|
+
function parseHunks(fileDiff) {
|
|
19788
|
+
const lines = fileDiff.split("\n");
|
|
19789
|
+
const hunks = [];
|
|
19790
|
+
let currentHunk = null;
|
|
19791
|
+
for (const line of lines) {
|
|
19792
|
+
const headerMatch = line.match(
|
|
19793
|
+
/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/
|
|
19794
|
+
);
|
|
19795
|
+
if (headerMatch) {
|
|
19796
|
+
if (currentHunk) {
|
|
19797
|
+
hunks.push(currentHunk);
|
|
19798
|
+
}
|
|
19799
|
+
currentHunk = {
|
|
19800
|
+
oldStart: parseInt(headerMatch[1], 10),
|
|
19801
|
+
oldCount: headerMatch[2] != null ? parseInt(headerMatch[2], 10) : 1,
|
|
19802
|
+
newStart: parseInt(headerMatch[3], 10),
|
|
19803
|
+
newCount: headerMatch[4] != null ? parseInt(headerMatch[4], 10) : 1,
|
|
19804
|
+
lines: []
|
|
19805
|
+
};
|
|
19806
|
+
continue;
|
|
19807
|
+
}
|
|
19808
|
+
if (!currentHunk) continue;
|
|
19809
|
+
if (line.startsWith("diff --git") || line.startsWith("index ") || line.startsWith("---") || line.startsWith("+++") || line.startsWith("old mode") || line.startsWith("new mode") || line.startsWith("similarity index") || line.startsWith("rename from") || line.startsWith("rename to") || line.startsWith("new file mode") || line.startsWith("deleted file mode")) {
|
|
19810
|
+
continue;
|
|
19811
|
+
}
|
|
19812
|
+
if (line === "\") {
|
|
19813
|
+
continue;
|
|
19814
|
+
}
|
|
19815
|
+
if (line.startsWith("-")) {
|
|
19816
|
+
currentHunk.lines.push({ type: "remove", content: line.slice(1) });
|
|
19817
|
+
} else if (line.startsWith("+")) {
|
|
19818
|
+
currentHunk.lines.push({ type: "add", content: line.slice(1) });
|
|
19819
|
+
} else if (line.startsWith(" ") || line === "") {
|
|
19820
|
+
currentHunk.lines.push({
|
|
19821
|
+
type: "context",
|
|
19822
|
+
content: line.startsWith(" ") ? line.slice(1) : line
|
|
19823
|
+
});
|
|
19824
|
+
}
|
|
19825
|
+
}
|
|
19826
|
+
if (currentHunk) {
|
|
19827
|
+
hunks.push(currentHunk);
|
|
19828
|
+
}
|
|
19829
|
+
return hunks;
|
|
19830
|
+
}
|
|
19831
|
+
function extractLeadingContext(hunk) {
|
|
19832
|
+
const result = [];
|
|
19833
|
+
for (const line of hunk.lines) {
|
|
19834
|
+
if (line.type !== "context") break;
|
|
19835
|
+
result.push(line.content);
|
|
19836
|
+
}
|
|
19837
|
+
return result;
|
|
19838
|
+
}
|
|
19839
|
+
function extractTrailingContext(hunk) {
|
|
19840
|
+
const result = [];
|
|
19841
|
+
for (let i = hunk.lines.length - 1; i >= 0; i--) {
|
|
19842
|
+
if (hunk.lines[i].type !== "context") break;
|
|
19843
|
+
result.unshift(hunk.lines[i].content);
|
|
19844
|
+
}
|
|
19845
|
+
return result;
|
|
19846
|
+
}
|
|
19847
|
+
function countOursLinesBeforeTrailing(hunk) {
|
|
19848
|
+
let count = 0;
|
|
19849
|
+
const trailingStart = findTrailingContextStart(hunk);
|
|
19850
|
+
for (let i = 0; i < trailingStart; i++) {
|
|
19851
|
+
if (hunk.lines[i].type === "context") count++;
|
|
19852
|
+
}
|
|
19853
|
+
return count;
|
|
19854
|
+
}
|
|
19855
|
+
function findTrailingContextStart(hunk) {
|
|
19856
|
+
let i = hunk.lines.length - 1;
|
|
19857
|
+
while (i >= 0 && hunk.lines[i].type === "context") {
|
|
19858
|
+
i--;
|
|
19859
|
+
}
|
|
19860
|
+
return i + 1;
|
|
19861
|
+
}
|
|
19862
|
+
function matchesAt(needle, haystack, offset) {
|
|
19863
|
+
for (let i = 0; i < needle.length; i++) {
|
|
19864
|
+
if (haystack[offset + i] !== needle[i]) return false;
|
|
19865
|
+
}
|
|
19866
|
+
return true;
|
|
19867
|
+
}
|
|
19868
|
+
function findContextInOurs(contextLines, oursLines, minIndex, hint) {
|
|
19869
|
+
const SEARCH_WINDOW = 200;
|
|
19870
|
+
const maxStart = oursLines.length - contextLines.length;
|
|
19871
|
+
const clampedHint = Math.max(minIndex, Math.min(hint, maxStart));
|
|
19872
|
+
if (clampedHint >= minIndex && clampedHint <= maxStart) {
|
|
19873
|
+
if (matchesAt(contextLines, oursLines, clampedHint)) {
|
|
19874
|
+
return clampedHint;
|
|
19875
|
+
}
|
|
19876
|
+
}
|
|
19877
|
+
for (let delta = 1; delta <= SEARCH_WINDOW; delta++) {
|
|
19878
|
+
for (const sign of [1, -1]) {
|
|
19879
|
+
const idx = clampedHint + delta * sign;
|
|
19880
|
+
if (idx < minIndex || idx > maxStart) continue;
|
|
19881
|
+
if (matchesAt(contextLines, oursLines, idx)) {
|
|
19882
|
+
return idx;
|
|
19883
|
+
}
|
|
19884
|
+
}
|
|
19885
|
+
}
|
|
19886
|
+
return -1;
|
|
19887
|
+
}
|
|
19888
|
+
function computeOursSpan(hunk, oursLines, oursOffset) {
|
|
19889
|
+
const leading = extractLeadingContext(hunk);
|
|
19890
|
+
const trailing = extractTrailingContext(hunk);
|
|
19891
|
+
if (trailing.length === 0) {
|
|
19892
|
+
const contextCount2 = hunk.lines.filter(
|
|
19893
|
+
(l) => l.type === "context"
|
|
19894
|
+
).length;
|
|
19895
|
+
return Math.min(contextCount2, oursLines.length - oursOffset);
|
|
19896
|
+
}
|
|
19897
|
+
const searchStart = oursOffset + leading.length;
|
|
19898
|
+
for (let i = searchStart; i <= oursLines.length - trailing.length; i++) {
|
|
19899
|
+
if (matchesAt(trailing, oursLines, i)) {
|
|
19900
|
+
return i + trailing.length - oursOffset;
|
|
19901
|
+
}
|
|
19902
|
+
}
|
|
19903
|
+
const contextCount = hunk.lines.filter(
|
|
19904
|
+
(l) => l.type === "context"
|
|
19905
|
+
).length;
|
|
19906
|
+
return Math.min(contextCount, oursLines.length - oursOffset);
|
|
19907
|
+
}
|
|
19908
|
+
function locateHunksInOurs(hunks, oursLines) {
|
|
19909
|
+
const located = [];
|
|
19910
|
+
let minOursIndex = 0;
|
|
19911
|
+
for (const hunk of hunks) {
|
|
19912
|
+
const contextLines = extractLeadingContext(hunk);
|
|
19913
|
+
let oursOffset;
|
|
19914
|
+
if (contextLines.length > 0) {
|
|
19915
|
+
const found = findContextInOurs(
|
|
19916
|
+
contextLines,
|
|
19917
|
+
oursLines,
|
|
19918
|
+
minOursIndex,
|
|
19919
|
+
hunk.newStart - 1
|
|
19920
|
+
);
|
|
19921
|
+
if (found === -1) {
|
|
19922
|
+
const trailingContext = extractTrailingContext(hunk);
|
|
19923
|
+
if (trailingContext.length > 0) {
|
|
19924
|
+
const trailingFound = findContextInOurs(
|
|
19925
|
+
trailingContext,
|
|
19926
|
+
oursLines,
|
|
19927
|
+
minOursIndex,
|
|
19928
|
+
hunk.newStart - 1
|
|
19929
|
+
);
|
|
19930
|
+
if (trailingFound === -1) return null;
|
|
19931
|
+
const nonTrailingCount = countOursLinesBeforeTrailing(hunk);
|
|
19932
|
+
oursOffset = trailingFound - nonTrailingCount;
|
|
19933
|
+
if (oursOffset < minOursIndex) return null;
|
|
19934
|
+
} else {
|
|
19935
|
+
return null;
|
|
19936
|
+
}
|
|
19937
|
+
} else {
|
|
19938
|
+
oursOffset = found;
|
|
19939
|
+
}
|
|
19940
|
+
} else if (hunk.oldStart === 1 && hunk.oldCount === 0) {
|
|
19941
|
+
oursOffset = 0;
|
|
19942
|
+
} else {
|
|
19943
|
+
oursOffset = Math.max(hunk.newStart - 1, minOursIndex);
|
|
19944
|
+
}
|
|
19945
|
+
const oursSpan = computeOursSpan(hunk, oursLines, oursOffset);
|
|
19946
|
+
located.push({ hunk, oursOffset, oursSpan });
|
|
19947
|
+
minOursIndex = oursOffset + oursSpan;
|
|
19948
|
+
}
|
|
19949
|
+
return located;
|
|
19950
|
+
}
|
|
19951
|
+
function assembleHybrid(locatedHunks, oursLines) {
|
|
19952
|
+
const baseLines = [];
|
|
19953
|
+
const theirsLines = [];
|
|
19954
|
+
let oursCursor = 0;
|
|
19955
|
+
for (const { hunk, oursOffset, oursSpan } of locatedHunks) {
|
|
19956
|
+
if (oursOffset > oursCursor) {
|
|
19957
|
+
const gapLines = oursLines.slice(oursCursor, oursOffset);
|
|
19958
|
+
baseLines.push(...gapLines);
|
|
19959
|
+
theirsLines.push(...gapLines);
|
|
19960
|
+
}
|
|
19961
|
+
for (const line of hunk.lines) {
|
|
19962
|
+
switch (line.type) {
|
|
19963
|
+
case "context":
|
|
19964
|
+
baseLines.push(line.content);
|
|
19965
|
+
theirsLines.push(line.content);
|
|
19966
|
+
break;
|
|
19967
|
+
case "remove":
|
|
19968
|
+
baseLines.push(line.content);
|
|
19969
|
+
break;
|
|
19970
|
+
case "add":
|
|
19971
|
+
theirsLines.push(line.content);
|
|
19972
|
+
break;
|
|
19973
|
+
}
|
|
19974
|
+
}
|
|
19975
|
+
oursCursor = oursOffset + oursSpan;
|
|
19976
|
+
}
|
|
19977
|
+
if (oursCursor < oursLines.length) {
|
|
19978
|
+
const gapLines = oursLines.slice(oursCursor);
|
|
19979
|
+
baseLines.push(...gapLines);
|
|
19980
|
+
theirsLines.push(...gapLines);
|
|
19981
|
+
}
|
|
19982
|
+
return {
|
|
19983
|
+
base: baseLines.join("\n"),
|
|
19984
|
+
theirs: theirsLines.join("\n")
|
|
19985
|
+
};
|
|
19986
|
+
}
|
|
19987
|
+
function reconstructFromGhostPatch(fileDiff, ours) {
|
|
19988
|
+
const hunks = parseHunks(fileDiff);
|
|
19989
|
+
if (hunks.length === 0) {
|
|
19990
|
+
return null;
|
|
19991
|
+
}
|
|
19992
|
+
const isPureAddition = hunks.every(
|
|
19993
|
+
(h) => h.oldCount === 0 && h.lines.every((l) => l.type !== "remove")
|
|
19994
|
+
);
|
|
19995
|
+
if (isPureAddition) {
|
|
19996
|
+
return null;
|
|
19997
|
+
}
|
|
19998
|
+
const isPureDeletion = hunks.every(
|
|
19999
|
+
(h) => h.newCount === 0 && h.lines.every((l) => l.type !== "add")
|
|
20000
|
+
);
|
|
20001
|
+
if (isPureDeletion) {
|
|
20002
|
+
const baseLines = [];
|
|
20003
|
+
for (const hunk of hunks) {
|
|
20004
|
+
for (const line of hunk.lines) {
|
|
20005
|
+
if (line.type === "context" || line.type === "remove") {
|
|
20006
|
+
baseLines.push(line.content);
|
|
20007
|
+
}
|
|
20008
|
+
}
|
|
20009
|
+
}
|
|
20010
|
+
return {
|
|
20011
|
+
base: baseLines.join("\n"),
|
|
20012
|
+
theirs: ""
|
|
20013
|
+
};
|
|
20014
|
+
}
|
|
20015
|
+
const oursLines = ours.split("\n");
|
|
20016
|
+
const located = locateHunksInOurs(hunks, oursLines);
|
|
20017
|
+
if (!located) {
|
|
20018
|
+
return null;
|
|
20019
|
+
}
|
|
20020
|
+
return assembleHybrid(located, oursLines);
|
|
20021
|
+
}
|
|
19787
20022
|
function isGenerationCommit(commit) {
|
|
19788
20023
|
const isFernSupport = FERN_SUPPORT_NAMES.includes(commit.authorName);
|
|
19789
20024
|
const isBotAuthor = !isFernSupport && (commit.authorLogin === FERN_BOT_LOGIN2 || commit.authorEmail === FERN_BOT_EMAIL2 || commit.authorName === FERN_BOT_NAME2);
|
|
@@ -19797,7 +20032,7 @@ function isReplayCommit(commit) {
|
|
|
19797
20032
|
return commit.message.startsWith("[fern-replay]");
|
|
19798
20033
|
}
|
|
19799
20034
|
function isRevertCommit(message) {
|
|
19800
|
-
return
|
|
20035
|
+
return /^Revert ".+"$/.test(message);
|
|
19801
20036
|
}
|
|
19802
20037
|
function parseRevertedSha(fullBody) {
|
|
19803
20038
|
const match2 = fullBody.match(/This reverts commit ([0-9a-f]{40})\./);
|
|
@@ -19842,14 +20077,6 @@ function threeWayMerge(base, ours, theirs) {
|
|
|
19842
20077
|
conflicts: conflicts2
|
|
19843
20078
|
};
|
|
19844
20079
|
}
|
|
19845
|
-
function isBinaryFile(filePath) {
|
|
19846
|
-
const ext2 = (0, import_path9.extname)(filePath).toLowerCase();
|
|
19847
|
-
return BINARY_EXTENSIONS.has(ext2);
|
|
19848
|
-
}
|
|
19849
|
-
function isDiffLineForFile(diffLine, filePath) {
|
|
19850
|
-
const match2 = diffLine.match(/^diff --git a\/.+ b\/(.+)$/);
|
|
19851
|
-
return match2 !== null && match2[1] === filePath;
|
|
19852
|
-
}
|
|
19853
20080
|
function stripConflictMarkers(content) {
|
|
19854
20081
|
const lines = content.split("\n");
|
|
19855
20082
|
const result = [];
|
|
@@ -19876,6 +20103,14 @@ function stripConflictMarkers(content) {
|
|
|
19876
20103
|
}
|
|
19877
20104
|
return result.join("\n");
|
|
19878
20105
|
}
|
|
20106
|
+
function isBinaryFile(filePath) {
|
|
20107
|
+
const ext2 = (0, import_path9.extname)(filePath).toLowerCase();
|
|
20108
|
+
return BINARY_EXTENSIONS.has(ext2);
|
|
20109
|
+
}
|
|
20110
|
+
function isDiffLineForFile(diffLine, filePath) {
|
|
20111
|
+
const match2 = diffLine.match(/^diff --git a\/.+ b\/(.+)$/);
|
|
20112
|
+
return match2 !== null && match2[1] === filePath;
|
|
20113
|
+
}
|
|
19879
20114
|
async function bootstrap(outputDir, options) {
|
|
19880
20115
|
const git = new GitClient(outputDir);
|
|
19881
20116
|
const lockManager = new LockfileManager(outputDir);
|
|
@@ -19957,6 +20192,7 @@ async function bootstrap(outputDir, options) {
|
|
|
19957
20192
|
}
|
|
19958
20193
|
lockManager.save();
|
|
19959
20194
|
const fernignoreUpdated = ensureFernignoreEntries(outputDir);
|
|
20195
|
+
ensureGitattributesEntries(outputDir);
|
|
19960
20196
|
if (migrator.fernignoreExists() && fernignorePatterns.length > 0) {
|
|
19961
20197
|
const action = options?.fernignoreAction ?? "skip";
|
|
19962
20198
|
if (action === "migrate") {
|
|
@@ -20061,34 +20297,162 @@ function ensureFernignoreEntries(outputDir) {
|
|
|
20061
20297
|
(0, import_fs9.writeFileSync)(fernignorePath, content, "utf-8");
|
|
20062
20298
|
return true;
|
|
20063
20299
|
}
|
|
20300
|
+
function ensureGitattributesEntries(outputDir) {
|
|
20301
|
+
const gitattributesPath = (0, import_path12.join)(outputDir, ".gitattributes");
|
|
20302
|
+
let content = "";
|
|
20303
|
+
if ((0, import_fs9.existsSync)(gitattributesPath)) {
|
|
20304
|
+
content = (0, import_fs9.readFileSync)(gitattributesPath, "utf-8");
|
|
20305
|
+
}
|
|
20306
|
+
const lines = content.split("\n");
|
|
20307
|
+
const toAdd = [];
|
|
20308
|
+
for (const entry of GITATTRIBUTES_ENTRIES) {
|
|
20309
|
+
if (!lines.some((line) => line.trim() === entry)) {
|
|
20310
|
+
toAdd.push(entry);
|
|
20311
|
+
}
|
|
20312
|
+
}
|
|
20313
|
+
if (toAdd.length === 0) {
|
|
20314
|
+
return;
|
|
20315
|
+
}
|
|
20316
|
+
if (content && !content.endsWith("\n")) {
|
|
20317
|
+
content += "\n";
|
|
20318
|
+
}
|
|
20319
|
+
content += toAdd.join("\n") + "\n";
|
|
20320
|
+
(0, import_fs9.writeFileSync)(gitattributesPath, content, "utf-8");
|
|
20321
|
+
}
|
|
20064
20322
|
function computeContentHash(patchContent) {
|
|
20065
20323
|
const normalized = patchContent.split("\n").filter((line) => !line.startsWith("From ") && !line.startsWith("index ") && !line.startsWith("Date: ")).join("\n");
|
|
20066
20324
|
return `sha256:${(0, import_crypto3.createHash)("sha256").update(normalized).digest("hex")}`;
|
|
20067
20325
|
}
|
|
20068
|
-
function
|
|
20326
|
+
function parseDiffStat(patchContent) {
|
|
20327
|
+
let additions = 0;
|
|
20328
|
+
let deletions = 0;
|
|
20329
|
+
let inDiffHunk = false;
|
|
20330
|
+
for (const line of patchContent.split("\n")) {
|
|
20331
|
+
if (line.startsWith("diff --git ")) {
|
|
20332
|
+
inDiffHunk = true;
|
|
20333
|
+
continue;
|
|
20334
|
+
}
|
|
20335
|
+
if (!inDiffHunk) continue;
|
|
20336
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
20337
|
+
additions++;
|
|
20338
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
20339
|
+
deletions++;
|
|
20340
|
+
}
|
|
20341
|
+
}
|
|
20342
|
+
return { additions, deletions };
|
|
20343
|
+
}
|
|
20344
|
+
function toMatchedPatch(patch) {
|
|
20345
|
+
return {
|
|
20346
|
+
id: patch.id,
|
|
20347
|
+
message: patch.original_message,
|
|
20348
|
+
files: patch.files,
|
|
20349
|
+
diffstat: parseDiffStat(patch.patch_content),
|
|
20350
|
+
...patch.status ? { status: patch.status } : {}
|
|
20351
|
+
};
|
|
20352
|
+
}
|
|
20353
|
+
function matchesPatch(patch, pattern) {
|
|
20354
|
+
const fileMatch = patch.files.some(
|
|
20355
|
+
(file) => file === pattern || minimatch(file, pattern)
|
|
20356
|
+
);
|
|
20357
|
+
if (fileMatch) return true;
|
|
20358
|
+
return patch.original_message.toLowerCase().includes(pattern.toLowerCase());
|
|
20359
|
+
}
|
|
20360
|
+
function buildWarnings(patches) {
|
|
20361
|
+
const warnings = [];
|
|
20362
|
+
for (const patch of patches) {
|
|
20363
|
+
if (patch.status === "resolving") {
|
|
20364
|
+
warnings.push(
|
|
20365
|
+
`patch ${patch.id} has conflict markers in these files: ${patch.files.join(", ")}. Run \`git checkout -- <files>\` to restore the generated versions.`
|
|
20366
|
+
);
|
|
20367
|
+
} else if (patch.status === "unresolved") {
|
|
20368
|
+
warnings.push(
|
|
20369
|
+
`patch ${patch.id} had unresolved conflicts (files: ${patch.files.join(", ")}).`
|
|
20370
|
+
);
|
|
20371
|
+
}
|
|
20372
|
+
}
|
|
20373
|
+
return warnings;
|
|
20374
|
+
}
|
|
20375
|
+
function forget(outputDir, options) {
|
|
20069
20376
|
const lockManager = new LockfileManager(outputDir);
|
|
20070
20377
|
if (!lockManager.exists()) {
|
|
20071
|
-
return {
|
|
20378
|
+
return { ...EMPTY_RESULT };
|
|
20072
20379
|
}
|
|
20073
20380
|
const lock = lockManager.read();
|
|
20074
|
-
const
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
|
|
20381
|
+
const totalPatches = lock.patches.length;
|
|
20382
|
+
if (options?.all) {
|
|
20383
|
+
const removed = lock.patches.map(toMatchedPatch);
|
|
20384
|
+
const warnings = buildWarnings(lock.patches);
|
|
20385
|
+
if (!options.dryRun) {
|
|
20386
|
+
for (const patch of lock.patches) {
|
|
20387
|
+
lockManager.addForgottenHash(patch.content_hash);
|
|
20388
|
+
}
|
|
20389
|
+
lockManager.clearPatches();
|
|
20390
|
+
lockManager.save();
|
|
20391
|
+
}
|
|
20392
|
+
return {
|
|
20393
|
+
initialized: true,
|
|
20394
|
+
removed,
|
|
20395
|
+
remaining: 0,
|
|
20396
|
+
notFound: false,
|
|
20397
|
+
alreadyForgotten: [],
|
|
20398
|
+
totalPatches,
|
|
20399
|
+
warnings
|
|
20400
|
+
};
|
|
20079
20401
|
}
|
|
20080
|
-
|
|
20081
|
-
|
|
20082
|
-
|
|
20083
|
-
|
|
20084
|
-
|
|
20085
|
-
|
|
20086
|
-
|
|
20087
|
-
|
|
20402
|
+
if (options?.patchIds && options.patchIds.length > 0) {
|
|
20403
|
+
const removed = [];
|
|
20404
|
+
const alreadyForgotten = [];
|
|
20405
|
+
const patchesToRemove = [];
|
|
20406
|
+
for (const id of options.patchIds) {
|
|
20407
|
+
const patch = lock.patches.find((p) => p.id === id);
|
|
20408
|
+
if (patch) {
|
|
20409
|
+
removed.push(toMatchedPatch(patch));
|
|
20410
|
+
patchesToRemove.push(patch);
|
|
20411
|
+
} else {
|
|
20412
|
+
alreadyForgotten.push(id);
|
|
20413
|
+
}
|
|
20088
20414
|
}
|
|
20089
|
-
|
|
20415
|
+
const warnings = buildWarnings(patchesToRemove);
|
|
20416
|
+
if (!options.dryRun) {
|
|
20417
|
+
for (const patch of patchesToRemove) {
|
|
20418
|
+
lockManager.addForgottenHash(patch.content_hash);
|
|
20419
|
+
lockManager.removePatch(patch.id);
|
|
20420
|
+
}
|
|
20421
|
+
lockManager.save();
|
|
20422
|
+
}
|
|
20423
|
+
return {
|
|
20424
|
+
initialized: true,
|
|
20425
|
+
removed,
|
|
20426
|
+
remaining: totalPatches - removed.length,
|
|
20427
|
+
notFound: removed.length === 0 && alreadyForgotten.length > 0,
|
|
20428
|
+
alreadyForgotten,
|
|
20429
|
+
totalPatches,
|
|
20430
|
+
warnings
|
|
20431
|
+
};
|
|
20090
20432
|
}
|
|
20091
|
-
|
|
20433
|
+
if (options?.pattern) {
|
|
20434
|
+
const matched = lock.patches.filter((p) => matchesPatch(p, options.pattern)).map(toMatchedPatch);
|
|
20435
|
+
return {
|
|
20436
|
+
initialized: true,
|
|
20437
|
+
removed: [],
|
|
20438
|
+
remaining: totalPatches,
|
|
20439
|
+
notFound: matched.length === 0,
|
|
20440
|
+
alreadyForgotten: [],
|
|
20441
|
+
totalPatches,
|
|
20442
|
+
warnings: [],
|
|
20443
|
+
matched
|
|
20444
|
+
};
|
|
20445
|
+
}
|
|
20446
|
+
return {
|
|
20447
|
+
initialized: true,
|
|
20448
|
+
removed: [],
|
|
20449
|
+
remaining: totalPatches,
|
|
20450
|
+
notFound: totalPatches === 0,
|
|
20451
|
+
alreadyForgotten: [],
|
|
20452
|
+
totalPatches,
|
|
20453
|
+
warnings: [],
|
|
20454
|
+
matched: lock.patches.map(toMatchedPatch)
|
|
20455
|
+
};
|
|
20092
20456
|
}
|
|
20093
20457
|
function reset(outputDir, options) {
|
|
20094
20458
|
const lockManager = new LockfileManager(outputDir);
|
|
@@ -20202,28 +20566,53 @@ async function getChangedFiles(git, currentGen, files) {
|
|
|
20202
20566
|
function status(outputDir) {
|
|
20203
20567
|
const lockManager = new LockfileManager(outputDir);
|
|
20204
20568
|
if (!lockManager.exists()) {
|
|
20205
|
-
return {
|
|
20569
|
+
return {
|
|
20570
|
+
initialized: false,
|
|
20571
|
+
generationCount: 0,
|
|
20572
|
+
lastGeneration: void 0,
|
|
20573
|
+
patches: [],
|
|
20574
|
+
unresolvedCount: 0,
|
|
20575
|
+
excludePatterns: []
|
|
20576
|
+
};
|
|
20206
20577
|
}
|
|
20207
20578
|
const lock = lockManager.read();
|
|
20208
20579
|
const patches = lock.patches.map((patch) => ({
|
|
20209
|
-
|
|
20210
|
-
|
|
20580
|
+
id: patch.id,
|
|
20581
|
+
type: patch.patch_content.includes("new file mode") ? "added" : "modified",
|
|
20211
20582
|
message: patch.original_message,
|
|
20212
|
-
|
|
20583
|
+
author: patch.original_author.split("<")[0]?.trim() || "unknown",
|
|
20584
|
+
sha: patch.original_commit.slice(0, 7),
|
|
20585
|
+
files: patch.files,
|
|
20586
|
+
fileCount: patch.files.length,
|
|
20587
|
+
...patch.status ? { status: patch.status } : {}
|
|
20213
20588
|
}));
|
|
20589
|
+
const unresolvedCount = lock.patches.filter(
|
|
20590
|
+
(p) => p.status === "unresolved" || p.status === "resolving"
|
|
20591
|
+
).length;
|
|
20214
20592
|
let lastGeneration;
|
|
20215
20593
|
const lastGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);
|
|
20216
20594
|
if (lastGen) {
|
|
20217
20595
|
lastGeneration = {
|
|
20218
|
-
sha: lastGen.commit_sha,
|
|
20219
|
-
timestamp: lastGen.timestamp
|
|
20596
|
+
sha: lastGen.commit_sha.slice(0, 7),
|
|
20597
|
+
timestamp: lastGen.timestamp,
|
|
20598
|
+
cliVersion: lastGen.cli_version,
|
|
20599
|
+
generatorVersions: lastGen.generator_versions
|
|
20220
20600
|
};
|
|
20221
20601
|
}
|
|
20222
|
-
|
|
20602
|
+
const config = lockManager.getCustomizationsConfig();
|
|
20603
|
+
const excludePatterns = config.exclude ?? [];
|
|
20604
|
+
return {
|
|
20605
|
+
initialized: true,
|
|
20606
|
+
generationCount: lock.generations.length,
|
|
20607
|
+
lastGeneration,
|
|
20608
|
+
patches,
|
|
20609
|
+
unresolvedCount,
|
|
20610
|
+
excludePatterns
|
|
20611
|
+
};
|
|
20223
20612
|
}
|
|
20224
|
-
var import_fs6, import_path8, import_yaml, import_crypto, import_promises4, import_os, import_path9, import_fs7, import_path10, import_crypto2, import_fs8, import_path11, import_yaml2, import_crypto3, import_fs9, import_path12, import_fs10, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, FERN_BOT_NAME2, FERN_BOT_EMAIL2, FERN_BOT_LOGIN2, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileManager, INFRASTRUCTURE_FILES, ReplayDetector, BINARY_EXTENSIONS, ReplayApplicator, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES;
|
|
20613
|
+
var import_fs6, import_path8, import_yaml, import_crypto, import_promises4, import_os, import_path9, import_fs7, import_path10, import_crypto2, import_fs8, import_path11, import_yaml2, import_crypto3, import_fs9, import_path12, import_fs10, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, FERN_BOT_NAME2, FERN_BOT_EMAIL2, FERN_BOT_LOGIN2, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileManager, INFRASTRUCTURE_FILES, ReplayDetector, BINARY_EXTENSIONS, ReplayApplicator, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
|
|
20225
20614
|
var init_dist = __esm({
|
|
20226
|
-
"../../node_modules/.pnpm/@fern-api+replay@0.
|
|
20615
|
+
"../../node_modules/.pnpm/@fern-api+replay@0.9.1/node_modules/@fern-api/replay/dist/index.js"() {
|
|
20227
20616
|
"use strict";
|
|
20228
20617
|
init_esm4();
|
|
20229
20618
|
import_fs6 = require("fs");
|
|
@@ -20357,6 +20746,14 @@ var init_dist = __esm({
|
|
|
20357
20746
|
return false;
|
|
20358
20747
|
}
|
|
20359
20748
|
}
|
|
20749
|
+
async treeExists(treeHash) {
|
|
20750
|
+
try {
|
|
20751
|
+
const type = await this.exec(["cat-file", "-t", treeHash]);
|
|
20752
|
+
return type.trim() === "tree";
|
|
20753
|
+
} catch {
|
|
20754
|
+
return false;
|
|
20755
|
+
}
|
|
20756
|
+
}
|
|
20360
20757
|
async getCommitBody(commitSha) {
|
|
20361
20758
|
return this.exec(["log", "-1", "--format=%B", commitSha]);
|
|
20362
20759
|
}
|
|
@@ -20366,6 +20763,18 @@ var init_dist = __esm({
|
|
|
20366
20763
|
};
|
|
20367
20764
|
}
|
|
20368
20765
|
});
|
|
20766
|
+
HybridReconstruction_exports = {};
|
|
20767
|
+
__export3(HybridReconstruction_exports, {
|
|
20768
|
+
assembleHybrid: () => assembleHybrid,
|
|
20769
|
+
locateHunksInOurs: () => locateHunksInOurs,
|
|
20770
|
+
parseHunks: () => parseHunks,
|
|
20771
|
+
reconstructFromGhostPatch: () => reconstructFromGhostPatch
|
|
20772
|
+
});
|
|
20773
|
+
init_HybridReconstruction = __esm3({
|
|
20774
|
+
"src/HybridReconstruction.ts"() {
|
|
20775
|
+
"use strict";
|
|
20776
|
+
}
|
|
20777
|
+
});
|
|
20369
20778
|
init_GitClient();
|
|
20370
20779
|
FERN_BOT_NAME2 = "fern-api";
|
|
20371
20780
|
FERN_BOT_EMAIL2 = "115122769+fern-api[bot]@users.noreply.github.com";
|
|
@@ -20457,6 +20866,15 @@ var init_dist = __esm({
|
|
|
20457
20866
|
this.ensureLoaded();
|
|
20458
20867
|
this.lock.patches = [];
|
|
20459
20868
|
}
|
|
20869
|
+
addForgottenHash(hash) {
|
|
20870
|
+
this.ensureLoaded();
|
|
20871
|
+
if (!this.lock.forgotten_hashes) {
|
|
20872
|
+
this.lock.forgotten_hashes = [];
|
|
20873
|
+
}
|
|
20874
|
+
if (!this.lock.forgotten_hashes.includes(hash)) {
|
|
20875
|
+
this.lock.forgotten_hashes.push(hash);
|
|
20876
|
+
}
|
|
20877
|
+
}
|
|
20460
20878
|
getUnresolvedPatches() {
|
|
20461
20879
|
this.ensureLoaded();
|
|
20462
20880
|
return this.lock.patches.filter((p) => p.status === "unresolved");
|
|
@@ -20550,6 +20968,7 @@ var init_dist = __esm({
|
|
|
20550
20968
|
}
|
|
20551
20969
|
const commits = this.parseGitLog(log);
|
|
20552
20970
|
const newPatches = [];
|
|
20971
|
+
const forgottenHashes = new Set(lock.forgotten_hashes ?? []);
|
|
20553
20972
|
for (const commit of commits) {
|
|
20554
20973
|
if (isGenerationCommit(commit)) {
|
|
20555
20974
|
continue;
|
|
@@ -20563,7 +20982,7 @@ var init_dist = __esm({
|
|
|
20563
20982
|
}
|
|
20564
20983
|
const patchContent = await this.git.formatPatch(commit.sha);
|
|
20565
20984
|
const contentHash = this.computeContentHash(patchContent);
|
|
20566
|
-
if (lock.patches.find((p) => p.content_hash === contentHash)) {
|
|
20985
|
+
if (lock.patches.find((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {
|
|
20567
20986
|
continue;
|
|
20568
20987
|
}
|
|
20569
20988
|
const filesOutput = await this.git.exec(["diff-tree", "--no-commit-id", "--name-only", "-r", commit.sha]);
|
|
@@ -20633,6 +21052,9 @@ var init_dist = __esm({
|
|
|
20633
21052
|
revertIndicesToRemove.add(idx);
|
|
20634
21053
|
}
|
|
20635
21054
|
}
|
|
21055
|
+
if (!matchedExisting && !matchedNew) {
|
|
21056
|
+
revertIndicesToRemove.add(i);
|
|
21057
|
+
}
|
|
20636
21058
|
}
|
|
20637
21059
|
const filteredPatches = newPatches.filter((_, i) => !revertIndicesToRemove.has(i));
|
|
20638
21060
|
return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };
|
|
@@ -20659,7 +21081,7 @@ var init_dist = __esm({
|
|
|
20659
21081
|
if (!diff.trim()) return { patches: [], revertedPatchIds: [] };
|
|
20660
21082
|
const contentHash = this.computeContentHash(diff);
|
|
20661
21083
|
const lock = this.lockManager.read();
|
|
20662
|
-
if (lock.patches.some((p) => p.content_hash === contentHash)) {
|
|
21084
|
+
if (lock.patches.some((p) => p.content_hash === contentHash) || (lock.forgotten_hashes ?? []).includes(contentHash)) {
|
|
20663
21085
|
return { patches: [], revertedPatchIds: [] };
|
|
20664
21086
|
}
|
|
20665
21087
|
const headSha = (await this.git.exec(["rev-parse", "HEAD"])).trim();
|
|
@@ -20739,6 +21161,7 @@ var init_dist = __esm({
|
|
|
20739
21161
|
lockManager;
|
|
20740
21162
|
outputDir;
|
|
20741
21163
|
renameCache = /* @__PURE__ */ new Map();
|
|
21164
|
+
treeExistsCache = /* @__PURE__ */ new Map();
|
|
20742
21165
|
fileTheirsAccumulator = /* @__PURE__ */ new Map();
|
|
20743
21166
|
constructor(git, lockManager, outputDir) {
|
|
20744
21167
|
this.git = git;
|
|
@@ -20756,7 +21179,8 @@ var init_dist = __esm({
|
|
|
20756
21179
|
async applyPatches(patches) {
|
|
20757
21180
|
this.resetAccumulator();
|
|
20758
21181
|
const results = [];
|
|
20759
|
-
for (
|
|
21182
|
+
for (let i = 0; i < patches.length; i++) {
|
|
21183
|
+
const patch = patches[i];
|
|
20760
21184
|
if (this.isExcluded(patch)) {
|
|
20761
21185
|
results.push({
|
|
20762
21186
|
patch,
|
|
@@ -20767,6 +21191,33 @@ var init_dist = __esm({
|
|
|
20767
21191
|
}
|
|
20768
21192
|
const result = await this.applyPatchWithFallback(patch);
|
|
20769
21193
|
results.push(result);
|
|
21194
|
+
if (result.status === "conflict" && result.fileResults) {
|
|
21195
|
+
const laterFiles = /* @__PURE__ */ new Set();
|
|
21196
|
+
for (let j = i + 1; j < patches.length; j++) {
|
|
21197
|
+
for (const f of patches[j].files) {
|
|
21198
|
+
laterFiles.add(f);
|
|
21199
|
+
}
|
|
21200
|
+
}
|
|
21201
|
+
const resolvedToOriginal = /* @__PURE__ */ new Map();
|
|
21202
|
+
if (result.resolvedFiles) {
|
|
21203
|
+
for (const [orig, resolved] of Object.entries(result.resolvedFiles)) {
|
|
21204
|
+
resolvedToOriginal.set(resolved, orig);
|
|
21205
|
+
}
|
|
21206
|
+
}
|
|
21207
|
+
for (const fileResult of result.fileResults) {
|
|
21208
|
+
if (fileResult.status !== "conflict") continue;
|
|
21209
|
+
const originalPath = resolvedToOriginal.get(fileResult.file) ?? fileResult.file;
|
|
21210
|
+
if (laterFiles.has(fileResult.file) || laterFiles.has(originalPath)) {
|
|
21211
|
+
const filePath = (0, import_path9.join)(this.outputDir, fileResult.file);
|
|
21212
|
+
try {
|
|
21213
|
+
const content = await (0, import_promises4.readFile)(filePath, "utf-8");
|
|
21214
|
+
const stripped = stripConflictMarkers(content);
|
|
21215
|
+
await (0, import_promises4.writeFile)(filePath, stripped);
|
|
21216
|
+
} catch {
|
|
21217
|
+
}
|
|
21218
|
+
}
|
|
21219
|
+
}
|
|
21220
|
+
}
|
|
20770
21221
|
}
|
|
20771
21222
|
return results;
|
|
20772
21223
|
}
|
|
@@ -20785,7 +21236,7 @@ var init_dist = __esm({
|
|
|
20785
21236
|
const resolvedPath = await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);
|
|
20786
21237
|
const base = await this.git.showFile(baseGen.tree_hash, filePath);
|
|
20787
21238
|
const theirs = await this.applyPatchToContent(base, patch.patch_content, filePath, tempGit, tempDir);
|
|
20788
|
-
if (theirs
|
|
21239
|
+
if (theirs) {
|
|
20789
21240
|
this.fileTheirsAccumulator.set(resolvedPath, {
|
|
20790
21241
|
content: theirs,
|
|
20791
21242
|
baseGeneration: patch.base_generation
|
|
@@ -20907,17 +21358,36 @@ var init_dist = __esm({
|
|
|
20907
21358
|
}
|
|
20908
21359
|
const oursPath = (0, import_path9.join)(this.outputDir, resolvedPath);
|
|
20909
21360
|
const ours = await (0, import_promises4.readFile)(oursPath, "utf-8").catch(() => null);
|
|
20910
|
-
let
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
|
|
21361
|
+
let ghostReconstructed = false;
|
|
21362
|
+
let theirs = null;
|
|
21363
|
+
if (!base && ours && !renameSourcePath) {
|
|
21364
|
+
const treeReachable = await this.isTreeReachable(baseGen.tree_hash);
|
|
21365
|
+
if (!treeReachable) {
|
|
21366
|
+
const fileDiff = this.extractFileDiff(patch.patch_content, filePath);
|
|
21367
|
+
if (fileDiff) {
|
|
21368
|
+
const { reconstructFromGhostPatch: reconstructFromGhostPatch2 } = await Promise.resolve().then(() => (init_HybridReconstruction(), HybridReconstruction_exports));
|
|
21369
|
+
const result = reconstructFromGhostPatch2(fileDiff, ours);
|
|
21370
|
+
if (result) {
|
|
21371
|
+
base = result.base;
|
|
21372
|
+
theirs = result.theirs;
|
|
21373
|
+
ghostReconstructed = true;
|
|
21374
|
+
}
|
|
21375
|
+
}
|
|
21376
|
+
}
|
|
21377
|
+
}
|
|
21378
|
+
if (!ghostReconstructed) {
|
|
21379
|
+
theirs = await this.applyPatchToContent(
|
|
21380
|
+
base,
|
|
21381
|
+
patch.patch_content,
|
|
21382
|
+
filePath,
|
|
21383
|
+
tempGit,
|
|
21384
|
+
tempDir,
|
|
21385
|
+
renameSourcePath
|
|
21386
|
+
);
|
|
21387
|
+
}
|
|
20918
21388
|
let useAccumulatorAsMergeBase = false;
|
|
20919
21389
|
const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);
|
|
20920
|
-
if (!theirs &&
|
|
21390
|
+
if (!theirs && accumulatorEntry) {
|
|
20921
21391
|
theirs = await this.applyPatchToContent(
|
|
20922
21392
|
accumulatorEntry.content,
|
|
20923
21393
|
patch.patch_content,
|
|
@@ -20947,13 +21417,13 @@ var init_dist = __esm({
|
|
|
20947
21417
|
baseMismatchSkipped = true;
|
|
20948
21418
|
}
|
|
20949
21419
|
}
|
|
20950
|
-
if (
|
|
21420
|
+
if (base == null && !ours && effective_theirs) {
|
|
20951
21421
|
const outDir2 = (0, import_path9.dirname)(oursPath);
|
|
20952
21422
|
await (0, import_promises4.mkdir)(outDir2, { recursive: true });
|
|
20953
21423
|
await (0, import_promises4.writeFile)(oursPath, effective_theirs);
|
|
20954
21424
|
return { file: resolvedPath, status: "merged", reason: "new-file" };
|
|
20955
21425
|
}
|
|
20956
|
-
if (
|
|
21426
|
+
if (base == null && ours && effective_theirs) {
|
|
20957
21427
|
const merged2 = threeWayMerge("", ours, effective_theirs);
|
|
20958
21428
|
const outDir2 = (0, import_path9.dirname)(oursPath);
|
|
20959
21429
|
await (0, import_promises4.mkdir)(outDir2, { recursive: true });
|
|
@@ -20976,7 +21446,7 @@ var init_dist = __esm({
|
|
|
20976
21446
|
reason: "missing-content"
|
|
20977
21447
|
};
|
|
20978
21448
|
}
|
|
20979
|
-
if (
|
|
21449
|
+
if (base == null && !useAccumulatorAsMergeBase || !ours) {
|
|
20980
21450
|
return {
|
|
20981
21451
|
file: resolvedPath,
|
|
20982
21452
|
status: "skipped",
|
|
@@ -20984,11 +21454,18 @@ var init_dist = __esm({
|
|
|
20984
21454
|
};
|
|
20985
21455
|
}
|
|
20986
21456
|
const mergeBase = useAccumulatorAsMergeBase && accumulatorEntry ? accumulatorEntry.content : base;
|
|
21457
|
+
if (mergeBase == null) {
|
|
21458
|
+
return {
|
|
21459
|
+
file: resolvedPath,
|
|
21460
|
+
status: "skipped",
|
|
21461
|
+
reason: "missing-content"
|
|
21462
|
+
};
|
|
21463
|
+
}
|
|
20987
21464
|
const merged = threeWayMerge(mergeBase, ours, effective_theirs);
|
|
20988
21465
|
const outDir = (0, import_path9.dirname)(oursPath);
|
|
20989
21466
|
await (0, import_promises4.mkdir)(outDir, { recursive: true });
|
|
20990
21467
|
await (0, import_promises4.writeFile)(oursPath, merged.content);
|
|
20991
|
-
if (effective_theirs
|
|
21468
|
+
if (effective_theirs) {
|
|
20992
21469
|
this.fileTheirsAccumulator.set(resolvedPath, {
|
|
20993
21470
|
content: effective_theirs,
|
|
20994
21471
|
baseGeneration: patch.base_generation
|
|
@@ -21012,6 +21489,14 @@ var init_dist = __esm({
|
|
|
21012
21489
|
};
|
|
21013
21490
|
}
|
|
21014
21491
|
}
|
|
21492
|
+
async isTreeReachable(treeHash) {
|
|
21493
|
+
let result = this.treeExistsCache.get(treeHash);
|
|
21494
|
+
if (result === void 0) {
|
|
21495
|
+
result = await this.git.treeExists(treeHash);
|
|
21496
|
+
this.treeExistsCache.set(treeHash, result);
|
|
21497
|
+
}
|
|
21498
|
+
return result;
|
|
21499
|
+
}
|
|
21015
21500
|
isExcluded(patch) {
|
|
21016
21501
|
const config = this.lockManager.getCustomizationsConfig();
|
|
21017
21502
|
if (!config.exclude) return false;
|
|
@@ -21978,7 +22463,17 @@ CLI Version: ${options.cliVersion}`;
|
|
|
21978
22463
|
}
|
|
21979
22464
|
};
|
|
21980
22465
|
init_GitClient();
|
|
21981
|
-
REPLAY_FERNIGNORE_ENTRIES = [".fern/replay.lock", ".fern/replay.yml"];
|
|
22466
|
+
REPLAY_FERNIGNORE_ENTRIES = [".fern/replay.lock", ".fern/replay.yml", ".gitattributes"];
|
|
22467
|
+
GITATTRIBUTES_ENTRIES = [".fern/replay.lock linguist-generated=true"];
|
|
22468
|
+
EMPTY_RESULT = {
|
|
22469
|
+
initialized: false,
|
|
22470
|
+
removed: [],
|
|
22471
|
+
remaining: 0,
|
|
22472
|
+
notFound: false,
|
|
22473
|
+
alreadyForgotten: [],
|
|
22474
|
+
totalPatches: 0,
|
|
22475
|
+
warnings: []
|
|
22476
|
+
};
|
|
21982
22477
|
init_GitClient();
|
|
21983
22478
|
}
|
|
21984
22479
|
});
|
|
@@ -32328,6 +32823,12 @@ var PostGenerationPipeline = class {
|
|
|
32328
32823
|
}
|
|
32329
32824
|
};
|
|
32330
32825
|
|
|
32826
|
+
// src/replay/replay-forget.ts
|
|
32827
|
+
init_dist();
|
|
32828
|
+
function replayForget(params) {
|
|
32829
|
+
return forget(params.outputDir, params.options);
|
|
32830
|
+
}
|
|
32831
|
+
|
|
32331
32832
|
// src/replay/replay-init.ts
|
|
32332
32833
|
init_dist();
|
|
32333
32834
|
var import_fs13 = require("fs");
|
|
@@ -32477,6 +32978,12 @@ function buildPrBody(result) {
|
|
|
32477
32978
|
// src/replay/replay-resolve.ts
|
|
32478
32979
|
init_dist();
|
|
32479
32980
|
|
|
32981
|
+
// src/replay/replay-status.ts
|
|
32982
|
+
init_dist();
|
|
32983
|
+
function replayStatus(params) {
|
|
32984
|
+
return status(params.outputDir);
|
|
32985
|
+
}
|
|
32986
|
+
|
|
32480
32987
|
// src/configuration/loadGitHubConfig.ts
|
|
32481
32988
|
var import_promises6 = require("fs/promises");
|
|
32482
32989
|
async function loadGitHubConfig({
|
|
@@ -32853,6 +33360,84 @@ Bootstrap complete! Lockfile saved to ${outputDir}/.fern/replay.lock
|
|
|
32853
33360
|
} catch (error) {
|
|
32854
33361
|
const errorMessage = extractErrorMessage(error);
|
|
32855
33362
|
process.stderr.write(`Bootstrap failed: ${errorMessage}
|
|
33363
|
+
`);
|
|
33364
|
+
process.exit(1);
|
|
33365
|
+
}
|
|
33366
|
+
}
|
|
33367
|
+
).command(
|
|
33368
|
+
"status [directory]",
|
|
33369
|
+
false,
|
|
33370
|
+
// hidden from --help
|
|
33371
|
+
(subYargs) => {
|
|
33372
|
+
return subYargs.positional("directory", {
|
|
33373
|
+
type: "string",
|
|
33374
|
+
default: ".",
|
|
33375
|
+
description: "SDK directory containing .fern/replay.lock"
|
|
33376
|
+
});
|
|
33377
|
+
},
|
|
33378
|
+
(argv) => {
|
|
33379
|
+
try {
|
|
33380
|
+
const outputDir = resolve(cwd(), argv.directory ?? ".");
|
|
33381
|
+
const result = replayStatus({ outputDir });
|
|
33382
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
33383
|
+
process.exit(0);
|
|
33384
|
+
} catch (error) {
|
|
33385
|
+
const errorMessage = extractErrorMessage(error);
|
|
33386
|
+
process.stderr.write(`Replay status failed: ${errorMessage}
|
|
33387
|
+
`);
|
|
33388
|
+
process.exit(1);
|
|
33389
|
+
}
|
|
33390
|
+
}
|
|
33391
|
+
).command(
|
|
33392
|
+
"forget [args..]",
|
|
33393
|
+
false,
|
|
33394
|
+
// hidden from --help
|
|
33395
|
+
(subYargs) => {
|
|
33396
|
+
return subYargs.positional("args", {
|
|
33397
|
+
type: "string",
|
|
33398
|
+
array: true,
|
|
33399
|
+
description: "Patch IDs or search pattern"
|
|
33400
|
+
}).option("dry-run", {
|
|
33401
|
+
type: "boolean",
|
|
33402
|
+
default: false,
|
|
33403
|
+
description: "Show what would be removed without actually removing"
|
|
33404
|
+
}).option("all", {
|
|
33405
|
+
type: "boolean",
|
|
33406
|
+
default: false,
|
|
33407
|
+
description: "Remove all tracked patches"
|
|
33408
|
+
}).option("pattern", {
|
|
33409
|
+
type: "string",
|
|
33410
|
+
description: "Search pattern (file path, glob, or commit message substring)"
|
|
33411
|
+
});
|
|
33412
|
+
},
|
|
33413
|
+
(argv) => {
|
|
33414
|
+
try {
|
|
33415
|
+
const outputDir = resolve(cwd(), ".");
|
|
33416
|
+
const args = argv.args ?? [];
|
|
33417
|
+
const dryRun = argv["dry-run"];
|
|
33418
|
+
let result;
|
|
33419
|
+
if (argv.all) {
|
|
33420
|
+
result = replayForget({ outputDir, options: { all: true, dryRun } });
|
|
33421
|
+
} else if (argv.pattern) {
|
|
33422
|
+
result = replayForget({ outputDir, options: { pattern: argv.pattern, dryRun } });
|
|
33423
|
+
} else if (args.length > 0) {
|
|
33424
|
+
const allPatchIds = args.every((a) => a.startsWith("patch-"));
|
|
33425
|
+
if (allPatchIds) {
|
|
33426
|
+
result = replayForget({ outputDir, options: { patchIds: args, dryRun } });
|
|
33427
|
+
} else {
|
|
33428
|
+
result = replayForget({
|
|
33429
|
+
outputDir,
|
|
33430
|
+
options: { pattern: args[0], dryRun }
|
|
33431
|
+
});
|
|
33432
|
+
}
|
|
33433
|
+
} else {
|
|
33434
|
+
result = replayForget({ outputDir, options: { dryRun } });
|
|
33435
|
+
}
|
|
33436
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
33437
|
+
process.exit(0);
|
|
33438
|
+
} catch (error) {
|
|
33439
|
+
const errorMessage = extractErrorMessage(error);
|
|
33440
|
+
process.stderr.write(`Replay forget failed: ${errorMessage}
|
|
32856
33441
|
`);
|
|
32857
33442
|
process.exit(1);
|
|
32858
33443
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fern-api/generator-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fern-api/fern.git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"**"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@fern-api/replay": "^0.
|
|
25
|
+
"@fern-api/replay": "^0.9.1",
|
|
26
26
|
"@octokit/rest": "^22.0.1",
|
|
27
27
|
"es-toolkit": "^1.45.1",
|
|
28
28
|
"tmp-promise": "^3.0.3"
|