@fern-api/generator-cli 0.9.48 → 0.9.50

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.
Files changed (2) hide show
  1. package/dist/cli.js +107 -11
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -22214,7 +22214,7 @@ var init_diff3 = __esm({
22214
22214
  }
22215
22215
  });
22216
22216
 
22217
- // ../../node_modules/.pnpm/@fern-api+replay@0.19.0/node_modules/@fern-api/replay/dist/index.js
22217
+ // ../../node_modules/.pnpm/@fern-api+replay@0.19.1/node_modules/@fern-api/replay/dist/index.js
22218
22218
  var dist_exports = {};
22219
22219
  __export(dist_exports, {
22220
22220
  CREDENTIAL_PATTERNS: () => CREDENTIAL_PATTERNS,
@@ -23059,6 +23059,37 @@ async function buildMergePlan(args) {
23059
23059
  conflictReasonHint
23060
23060
  };
23061
23061
  }
23062
+ function maskVersions(line) {
23063
+ return line.replace(VERSION_TOKEN, VERSION_MASK);
23064
+ }
23065
+ function containsPlaceholder(content) {
23066
+ if (!content) return false;
23067
+ return AUTOVERSION_PLACEHOLDERS.some((p2) => content.includes(p2));
23068
+ }
23069
+ function remapManagedLines(genBase, target, theirs) {
23070
+ if (!containsPlaceholder(genBase)) return theirs;
23071
+ const managedMasks = /* @__PURE__ */ new Set();
23072
+ for (const line of genBase.split("\n")) {
23073
+ if (AUTOVERSION_PLACEHOLDERS.some((p2) => line.includes(p2))) managedMasks.add(maskVersions(line));
23074
+ }
23075
+ if (managedMasks.size === 0) return theirs;
23076
+ const targetByMask = /* @__PURE__ */ new Map();
23077
+ for (const line of target.split("\n")) {
23078
+ const mask = maskVersions(line);
23079
+ if (managedMasks.has(mask) && !targetByMask.has(mask)) targetByMask.set(mask, line);
23080
+ }
23081
+ return theirs.split("\n").map((line) => {
23082
+ const mask = maskVersions(line);
23083
+ const replacement = managedMasks.has(mask) ? targetByMask.get(mask) : void 0;
23084
+ return replacement !== void 0 && replacement !== line ? replacement : line;
23085
+ }).join("\n");
23086
+ }
23087
+ function neutralizeAutoversionTheirs(genBase, theirs) {
23088
+ return remapManagedLines(genBase, genBase, theirs);
23089
+ }
23090
+ function alignAutoversionToOurs(genBase, ours, theirs) {
23091
+ return remapManagedLines(genBase, ours, theirs);
23092
+ }
23062
23093
  async function runMergeAndRecord(args) {
23063
23094
  const { plan, inputs, patch, accumulator } = args;
23064
23095
  const { resolvedPath, metadata, oursPath, ours } = inputs;
@@ -23089,11 +23120,13 @@ async function runMergeAndRecord(args) {
23089
23120
  accumulator.recordMerge(resolvedPath, merged2.content, patch.base_generation);
23090
23121
  return { file: resolvedPath, status: "merged", ...unreachableFlag };
23091
23122
  }
23092
- const merged = threeWayMerge(plan.mergeBase, ours, plan.theirs);
23123
+ const mergeBase = inputs.base != null ? alignAutoversionToOurs(inputs.base, ours, plan.mergeBase) : plan.mergeBase;
23124
+ const theirs = inputs.base != null ? alignAutoversionToOurs(inputs.base, ours, plan.theirs) : plan.theirs;
23125
+ const merged = threeWayMerge(mergeBase, ours, theirs);
23093
23126
  await (0, import_promises7.mkdir)((0, import_path12.dirname)(oursPath), { recursive: true });
23094
23127
  await (0, import_promises7.writeFile)(oursPath, merged.content);
23095
23128
  if (merged.hasConflicts) {
23096
- accumulator.recordConflict(resolvedPath, plan.theirs, patch.base_generation);
23129
+ accumulator.recordConflict(resolvedPath, theirs, patch.base_generation);
23097
23130
  return {
23098
23131
  file: resolvedPath,
23099
23132
  status: "conflict",
@@ -23102,7 +23135,7 @@ async function runMergeAndRecord(args) {
23102
23135
  conflictMetadata: metadata
23103
23136
  };
23104
23137
  }
23105
- accumulator.recordMerge(resolvedPath, plan.theirs, patch.base_generation);
23138
+ accumulator.recordMerge(resolvedPath, theirs, patch.base_generation);
23106
23139
  return {
23107
23140
  file: resolvedPath,
23108
23141
  status: "merged",
@@ -24260,9 +24293,9 @@ function status(outputDir) {
24260
24293
  legacyDismissedCount
24261
24294
  };
24262
24295
  }
24263
- var import_promises4, import_os, import_path7, import_fs6, import_path8, import_yaml, import_crypto, import_path9, import_promises5, import_os2, import_path10, import_promises6, import_path11, import_promises7, import_path12, import_fs7, import_promises8, import_path13, import_fs8, import_path14, import_promises9, import_os3, import_path15, import_child_process3, import_crypto2, import_fs9, import_path16, import_yaml2, import_crypto3, import_fs10, import_path17, import_fs11, import_promises10, import_path18, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, PatchApplyTheirs_exports, init_PatchApplyTheirs, CREDENTIAL_PATTERNS, SENSITIVE_FILE_PATTERNS, FERN_BOT_NAME, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileNotFoundError, LockfileManager, BINARY_EXTENSIONS, INFRASTRUCTURE_FILES, ReplayDetector, MergeAccumulator, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, ReplayApplicator, ReplayCommitter, FileOwnership, FirstGenerationFlow, SkipApplicationFlow, NoPatchesFlow, NormalRegenerationFlow, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
24296
+ var import_promises4, import_os, import_path7, import_fs6, import_path8, import_yaml, import_crypto, import_path9, import_promises5, import_os2, import_path10, import_promises6, import_path11, import_promises7, import_path12, import_fs7, import_promises8, import_path13, import_fs8, import_path14, import_promises9, import_os3, import_path15, import_child_process3, import_crypto2, import_fs9, import_path16, import_yaml2, import_crypto3, import_fs10, import_path17, import_fs11, import_promises10, import_path18, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, PatchApplyTheirs_exports, init_PatchApplyTheirs, CREDENTIAL_PATTERNS, SENSITIVE_FILE_PATTERNS, FERN_BOT_NAME, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileNotFoundError, LockfileManager, BINARY_EXTENSIONS, INFRASTRUCTURE_FILES, ReplayDetector, MergeAccumulator, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, AUTOVERSION_PLACEHOLDERS, VERSION_TOKEN, VERSION_MASK, ReplayApplicator, ReplayCommitter, FileOwnership, FirstGenerationFlow, SkipApplicationFlow, NoPatchesFlow, NormalRegenerationFlow, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
24264
24297
  var init_dist3 = __esm({
24265
- "../../node_modules/.pnpm/@fern-api+replay@0.19.0/node_modules/@fern-api/replay/dist/index.js"() {
24298
+ "../../node_modules/.pnpm/@fern-api+replay@0.19.1/node_modules/@fern-api/replay/dist/index.js"() {
24266
24299
  "use strict";
24267
24300
  init_esm4();
24268
24301
  import_promises4 = require("fs/promises");
@@ -25466,6 +25499,16 @@ var init_dist3 = __esm({
25466
25499
  CONFLICT_OPENER = "<<<<<<< Generated";
25467
25500
  CONFLICT_SEPARATOR = "=======";
25468
25501
  CONFLICT_CLOSER = ">>>>>>> Your customization";
25502
+ AUTOVERSION_PLACEHOLDERS = [
25503
+ "v0.0.0-fern-placeholder",
25504
+ // Go -- a superstring of the default; check first
25505
+ "0.0.0-fern-placeholder",
25506
+ // TS/Java/C#/Ruby/PHP/Rust/default
25507
+ "0.0.0.dev0"
25508
+ // Python (PEP 440 -- Poetry rejects hyphens)
25509
+ ];
25510
+ VERSION_TOKEN = /(?:v)?\d+\.\d+\.\d+[0-9A-Za-z.+-]*/g;
25511
+ VERSION_MASK = "@@FERN_VERSION@@";
25469
25512
  ReplayApplicator = class {
25470
25513
  git;
25471
25514
  lockManager;
@@ -26852,7 +26895,9 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
26852
26895
  if (baseChanged) repointed++;
26853
26896
  continue;
26854
26897
  }
26855
- const diff = await this.git.exec(["diff", currentGenSha, "--", ...patch.files]).catch(() => null);
26898
+ const rawDiff = await this.git.exec(["diff", currentGenSha, "--", ...patch.files]).catch(() => null);
26899
+ const neutralizedRebase = rawDiff != null && containsPlaceholder(rawDiff) ? await this.computeAutoversionNeutralizedRebase(patch.files, currentGenSha) : null;
26900
+ const diff = neutralizedRebase ? neutralizedRebase.diff : rawDiff;
26856
26901
  if (diff === null) continue;
26857
26902
  if (!diff.trim()) {
26858
26903
  if (hasProtectedFiles) {
@@ -26908,7 +26953,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
26908
26953
  patch.base_generation = currentGenSha;
26909
26954
  patch.patch_content = diff;
26910
26955
  patch.content_hash = newContentHash;
26911
- const snapshot = await this.readSnapshotFromDisk(patch.files);
26956
+ const snapshot = neutralizedRebase ? neutralizedRebase.snapshot : await this.readSnapshotFromDisk(patch.files);
26912
26957
  const snapshotIsNonEmpty = Object.keys(snapshot).length > 0;
26913
26958
  if (snapshotIsNonEmpty) {
26914
26959
  patch.theirs_snapshot = snapshot;
@@ -26948,6 +26993,47 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
26948
26993
  }
26949
26994
  return snapshot;
26950
26995
  }
26996
+ /**
26997
+ * Autoversion-aware replacement for the naive `git diff currentGen -- files`
26998
+ * + on-disk snapshot used when rebasing a cleanly-applied patch.
26999
+ *
27000
+ * The generation tree (BASE) still carries the placeholder on version lines
27001
+ * (autoversion runs after `[fern-generated]`), but the working tree holds
27002
+ * autoversion's resolved semver. A raw diff/snapshot would fold the
27003
+ * placeholder->semver swap into the customer's patch_content/theirs_snapshot,
27004
+ * pinning a stale version. This re-derives both against a version-neutralized
27005
+ * THEIRS so the pipeline-owned version line never enters the patch.
27006
+ *
27007
+ * Returns null when no file is under autoversion (fixed `--version`, i.e. no
27008
+ * placeholder in the generation tree) — callers keep their existing behavior.
27009
+ */
27010
+ async computeAutoversionNeutralizedRebase(files, currentGenSha) {
27011
+ const genByFile = /* @__PURE__ */ new Map();
27012
+ let anyPlaceholder = false;
27013
+ for (const file of files) {
27014
+ const gen = await this.git.showFile(currentGenSha, file).catch(() => null);
27015
+ genByFile.set(file, gen);
27016
+ if (containsPlaceholder(gen)) anyPlaceholder = true;
27017
+ }
27018
+ if (!anyPlaceholder) return null;
27019
+ const snapshot = {};
27020
+ const fragments = [];
27021
+ for (const file of files) {
27022
+ if (isBinaryFile(file)) continue;
27023
+ const disk = await (0, import_promises8.readFile)((0, import_path13.join)(this.outputDir, file), "utf-8").catch(() => null);
27024
+ if (disk == null) continue;
27025
+ const gen = genByFile.get(file) ?? null;
27026
+ const neutralized = gen != null ? neutralizeAutoversionTheirs(gen, disk) : disk;
27027
+ snapshot[file] = neutralized;
27028
+ if (gen == null) {
27029
+ fragments.push(synthesizeNewFileDiff(file, neutralized));
27030
+ } else if (gen !== neutralized) {
27031
+ const fileDiff = await unifiedDiff(gen, neutralized, file);
27032
+ if (fileDiff.trim()) fragments.push(fileDiff);
27033
+ }
27034
+ }
27035
+ return { diff: fragments.join(""), snapshot };
27036
+ }
26951
27037
  /**
26952
27038
  * Detects autoversion contamination — returns true when a
26953
27039
  * `[fern-autoversion]` commit between `fromSha` and `toSha` touched any
@@ -42713,6 +42799,16 @@ ${prBody}`;
42713
42799
  // src/pipeline/github/pushSignedCommit.ts
42714
42800
  var MAX_CONCURRENT_PUSH_RETRIES = 3;
42715
42801
  var MAX_SIGNED_CHAIN_LENGTH = 20;
42802
+ var PAT_TOKEN_PREFIXES = ["ghp_", "github_pat_"];
42803
+ function resolveCommitAuthor(token, author) {
42804
+ if (author != null) {
42805
+ return author;
42806
+ }
42807
+ if (PAT_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix))) {
42808
+ return { name: FERN_BOT_NAME2, email: FERN_BOT_EMAIL2 };
42809
+ }
42810
+ return void 0;
42811
+ }
42716
42812
  async function pushSignedCommit({
42717
42813
  repository,
42718
42814
  octokit,
@@ -43108,7 +43204,7 @@ var GithubStep = class extends BaseStep {
43108
43204
  repo,
43109
43205
  branch: prBranch,
43110
43206
  force: isUpdatingExistingPR,
43111
- author: this.config.author,
43207
+ author: resolveCommitAuthor(this.config.token, this.config.author),
43112
43208
  logger: this.logger
43113
43209
  });
43114
43210
  const pushedBranch = await repository.getCurrentBranch();
@@ -43245,7 +43341,7 @@ var GithubStep = class extends BaseStep {
43245
43341
  branch: baseBranch,
43246
43342
  force: false,
43247
43343
  rebaseOnConflict: true,
43248
- author: this.config.author,
43344
+ author: resolveCommitAuthor(this.config.token, this.config.author),
43249
43345
  logger: this.logger
43250
43346
  });
43251
43347
  const pushedBranch = await repository.getCurrentBranch();
@@ -43287,7 +43383,7 @@ var GithubStep = class extends BaseStep {
43287
43383
  branch: baseBranch,
43288
43384
  force: false,
43289
43385
  rebaseOnConflict: true,
43290
- author: this.config.author,
43386
+ author: resolveCommitAuthor(this.config.token, this.config.author),
43291
43387
  logger: this.logger
43292
43388
  });
43293
43389
  const pushedBranch = await repository.getCurrentBranch();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.9.48",
3
+ "version": "0.9.50",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fern-api/fern.git",
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@boundaryml/baml": "^0.219.0",
26
- "@fern-api/replay": "0.19.0",
26
+ "@fern-api/replay": "0.19.1",
27
27
  "@octokit/rest": "^22.0.1",
28
28
  "es-toolkit": "^1.45.1",
29
29
  "semver": "^7.6.3",