@fern-api/generator-cli 0.9.9 → 0.9.11

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 CHANGED
@@ -499,6 +499,7 @@ declare const consolePipelineLogger: PipelineLogger;
499
499
  interface PipelineConfig {
500
500
  outputDir: string;
501
501
  replay?: ReplayStepConfig;
502
+ autoVersion?: AutoVersionStepConfig;
502
503
  fernignore?: FernignoreStepConfig;
503
504
  github?: GithubStepConfig;
504
505
  cliVersion?: string;
@@ -508,6 +509,7 @@ interface PipelineConfig {
508
509
  interface PipelineContext {
509
510
  previousStepResults: {
510
511
  replay?: ReplayStepResult;
512
+ autoVersion?: AutoVersionStepResult;
511
513
  fernignore?: FernignoreStepResult;
512
514
  };
513
515
  }
@@ -516,6 +518,17 @@ interface ReplayStepConfig {
516
518
  stageOnly?: boolean;
517
519
  skipApplication?: boolean;
518
520
  }
521
+ interface AutoVersionStepConfig {
522
+ enabled: boolean;
523
+ /** Generator language: typescript | python | java | go | ruby | csharp | php | swift | rust | kotlin */
524
+ language: string;
525
+ /** Existing changelog content passed to the AI for context. */
526
+ priorChangelog?: string;
527
+ /** Fallback version when no prior generation exists (first run). */
528
+ baseVersion?: string;
529
+ /** Fern token used to authorize the FAI (AnalyzeSdkDiff) call. */
530
+ fernToken: string;
531
+ }
519
532
  interface FernignoreStepConfig {
520
533
  enabled: boolean;
521
534
  customContents?: string;
@@ -555,8 +568,10 @@ interface GithubStepConfig {
555
568
  previousGenerationSha: string;
556
569
  currentGenerationSha: string;
557
570
  };
558
- /** When true: separate PRs per generation, no-diff skip, automerge support, run_id in body */
571
+ /** When true: separate PRs per generation, automerge support, run_id in body */
559
572
  automationMode?: boolean;
573
+ /** When true: skip opening a PR / pushing when the generated output has no diff from the base branch. */
574
+ skipIfNoDiff?: boolean;
560
575
  /** Enable GitHub automerge on the PR (only effective when automationMode && !hasBreakingChanges) */
561
576
  autoMerge?: boolean;
562
577
  /** Pre-computed: version bump is MAJOR (from --version AUTO AI analysis) */
@@ -570,6 +585,7 @@ interface PipelineResult {
570
585
  success: boolean;
571
586
  steps: {
572
587
  replay?: ReplayStepResult;
588
+ autoVersion?: AutoVersionStepResult;
573
589
  fernignore?: FernignoreStepResult;
574
590
  github?: GithubStepResult;
575
591
  };
@@ -602,6 +618,24 @@ interface ReplayStepResult extends StepResult {
602
618
  interface FernignoreStepResult extends StepResult {
603
619
  pathsPreserved?: string[];
604
620
  }
621
+ interface AutoVersionStepResult extends StepResult {
622
+ /** The new version to use (e.g. "1.2.3"). Field name matches fiddle's Java AutoVersionResult DTO. */
623
+ version?: string;
624
+ /** Commit subject for the `[fern-autoversion]` commit. */
625
+ commitMessage?: string;
626
+ /** User-facing changelog entry appended to changelog.md. */
627
+ changelogEntry?: string;
628
+ /** Prior SDK version before this change (e.g. "1.2.2"). */
629
+ previousVersion?: string;
630
+ /** The version bump level determined by FAI. */
631
+ versionBump?: "MAJOR" | "MINOR" | "PATCH" | "NO_CHANGE";
632
+ /** Structured PR description with Before/After code fences for breaking changes. */
633
+ prDescription?: string;
634
+ /** One-sentence justification for WHY the version bump was chosen. */
635
+ versionBumpReason?: string;
636
+ /** SHA of the `[fern-autoversion]` commit once it's been made. TS-only; no fiddle counterpart. */
637
+ commitSha?: string;
638
+ }
605
639
  interface GithubStepResult extends StepResult {
606
640
  commitSha?: string;
607
641
  branchUrl?: string;
@@ -733,4 +767,48 @@ interface ReplayStatusParams {
733
767
  }
734
768
  declare function replayStatus(params: ReplayStatusParams): StatusResult;
735
769
 
736
- 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 };
770
+ interface SubmitReplayInitParams {
771
+ /** Fiddle API origin (e.g. "https://fiddle.buildwithfern.com") */
772
+ fiddleOrigin: string;
773
+ /** Fern auth token */
774
+ fernToken: string;
775
+ /** GitHub repository (e.g. "owner/repo" or full URL) */
776
+ githubRepo: string;
777
+ /** Result from replayInit() */
778
+ initResult: ReplayInitResult;
779
+ }
780
+ interface SubmitReplayInitResult {
781
+ /** URL of the PR created by Fiddle */
782
+ prUrl: string;
783
+ }
784
+ /**
785
+ * Submits a Replay init lockfile to the Fiddle API for server-side PR creation.
786
+ *
787
+ * Extracts owner/repo from the GitHub repository string, posts the lockfile
788
+ * and related metadata to the Fiddle remote-gen endpoint, and returns the
789
+ * resulting PR URL.
790
+ *
791
+ * This function is shared between CLI v1 and CLI v2 to avoid duplicating
792
+ * the Fiddle submission logic.
793
+ */
794
+ declare function submitReplayInit(params: SubmitReplayInitParams): Promise<SubmitReplayInitResult>;
795
+ /**
796
+ * Parses a GitHub repository string into owner and repo components.
797
+ * Accepts formats: "owner/repo", "github.com/owner/repo",
798
+ * "https://github.com/owner/repo", "https://github.com/owner/repo.git"
799
+ */
800
+ declare function parseOwnerRepo(githubRepo: string): {
801
+ owner: string;
802
+ repo: string;
803
+ };
804
+ /**
805
+ * Error thrown when submitting a Replay init to Fiddle fails.
806
+ * Consumers can inspect `statusCode` to distinguish between
807
+ * different failure modes (e.g. 404 = GitHub App not installed).
808
+ */
809
+ declare class ReplaySubmitError extends Error {
810
+ readonly statusCode: number | undefined;
811
+ constructor(message: string, statusCode?: number);
812
+ }
813
+
814
+ 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, ReplaySubmitError, type SubmitReplayInitParams, type SubmitReplayInitResult, consolePipelineLogger, formatBootstrapSummary, formatReplayPrBody, generateReadme, generateReadmeToStream, generateReference, generateReferenceToStream, githubPr, githubPush, githubRelease, logReplaySummary, parseOwnerRepo, replayForget, replayInit, replayResolve, replayRun, replayStatus, submitReplayInit };
package/dist/api.js CHANGED
@@ -881,6 +881,7 @@ var require_dist2 = __commonJS({
881
881
  var api_exports2 = {};
882
882
  __export(api_exports2, {
883
883
  PostGenerationPipeline: () => PostGenerationPipeline,
884
+ ReplaySubmitError: () => ReplaySubmitError,
884
885
  consolePipelineLogger: () => consolePipelineLogger,
885
886
  formatBootstrapSummary: () => formatBootstrapSummary,
886
887
  formatReplayPrBody: () => formatReplayPrBody,
@@ -892,11 +893,13 @@ __export(api_exports2, {
892
893
  githubPush: () => githubPush,
893
894
  githubRelease: () => githubRelease,
894
895
  logReplaySummary: () => logReplaySummary,
896
+ parseOwnerRepo: () => parseOwnerRepo,
895
897
  replayForget: () => replayForget,
896
898
  replayInit: () => replayInit,
897
899
  replayResolve: () => replayResolve,
898
900
  replayRun: () => replayRun,
899
- replayStatus: () => replayStatus
901
+ replayStatus: () => replayStatus,
902
+ submitReplayInit: () => submitReplayInit
900
903
  });
901
904
  module.exports = __toCommonJS(api_exports2);
902
905
 
@@ -6017,6 +6020,46 @@ var ClonedRepository = class _ClonedRepository {
6017
6020
  const result = await this.git.raw(["rev-parse", "HEAD^{tree}"]);
6018
6021
  return result.trim();
6019
6022
  }
6023
+ async getHeadCommitMessage() {
6024
+ await this.git.cwd(this.clonePath);
6025
+ const result = await this.git.raw(["log", "-1", "--format=%B", "HEAD"]);
6026
+ return result.replace(/\n$/, "");
6027
+ }
6028
+ async getHeadParents() {
6029
+ await this.git.cwd(this.clonePath);
6030
+ const result = await this.git.raw(["rev-list", "--parents", "-n", "1", "HEAD"]);
6031
+ const parts = result.trim().split(/\s+/);
6032
+ return parts.slice(1);
6033
+ }
6034
+ /**
6035
+ * Pushes a specific object (commit SHA) to a remote ref.
6036
+ * Used to upload tree and blob objects to the remote without moving a branch.
6037
+ *
6038
+ * Pass `force: true` when overwriting a ref that may already point to an
6039
+ * unrelated commit (e.g. retrying a temp ref after a local rebase rewrites
6040
+ * history so the new SHA is not a descendant of the previous one).
6041
+ */
6042
+ async pushObjectToRef(localSha, remoteRef, { force = false } = {}) {
6043
+ await this.git.cwd(this.clonePath);
6044
+ const spec = force ? `+${localSha}:${remoteRef}` : `${localSha}:${remoteRef}`;
6045
+ await this.git.raw(["push", "origin", spec]);
6046
+ }
6047
+ /**
6048
+ * Resets the current branch HEAD to the given SHA. After fetching a newly-created remote
6049
+ * signed commit, use this to align the local branch so subsequent operations (tag push,
6050
+ * getHeadSha(), etc.) see the signed SHA.
6051
+ */
6052
+ async resetHardToSha(sha) {
6053
+ await this.git.cwd(this.clonePath);
6054
+ await this.git.raw(["reset", "--hard", sha]);
6055
+ }
6056
+ /**
6057
+ * Rebases the current branch onto the given remote branch (`git pull --rebase origin <branch>`).
6058
+ */
6059
+ async pullWithRebase(branch) {
6060
+ await this.git.cwd(this.clonePath);
6061
+ await this.git.raw(["pull", "origin", branch, "--rebase"]);
6062
+ }
6020
6063
  async getCommitTreeHash(commitSha) {
6021
6064
  await this.git.cwd(this.clonePath);
6022
6065
  const result = await this.git.raw(["rev-parse", `${commitSha}^{tree}`]);
@@ -10024,6 +10067,35 @@ var FERN_BOT_NAME = "fern-api";
10024
10067
  var FERN_BOT_EMAIL = "115122769+fern-api[bot]@users.noreply.github.com";
10025
10068
  var FERN_BOT_LOGIN = "fern-api[bot]";
10026
10069
 
10070
+ // src/pipeline/steps/BaseStep.ts
10071
+ var BaseStep = class {
10072
+ constructor(outputDir, logger) {
10073
+ this.outputDir = outputDir;
10074
+ this.logger = logger;
10075
+ }
10076
+ outputDir;
10077
+ logger;
10078
+ };
10079
+
10080
+ // src/pipeline/steps/AutoVersionStep.ts
10081
+ var AutoVersionStep = class extends BaseStep {
10082
+ constructor(outputDir, logger, config) {
10083
+ super(outputDir, logger);
10084
+ this.config = config;
10085
+ }
10086
+ config;
10087
+ name = "autoVersion";
10088
+ async execute(_context) {
10089
+ this.logger.info(
10090
+ `AutoVersionStep: no-op scaffold for language=${this.config.language} (logic lands in FER-9980)`
10091
+ );
10092
+ return {
10093
+ executed: true,
10094
+ success: true
10095
+ };
10096
+ }
10097
+ };
10098
+
10027
10099
  // src/pipeline/steps/GithubStep.ts
10028
10100
  var import_rest2 = require("@octokit/rest");
10029
10101
  var import_promises2 = require("fs/promises");
@@ -10157,6 +10229,128 @@ ${prBody}`;
10157
10229
  return { prTitle, prBody };
10158
10230
  }
10159
10231
 
10232
+ // src/pipeline/github/pushSignedCommit.ts
10233
+ var MAX_CONCURRENT_PUSH_RETRIES = 3;
10234
+ async function pushSignedCommit({
10235
+ repository,
10236
+ octokit,
10237
+ owner,
10238
+ repo,
10239
+ branch,
10240
+ force,
10241
+ rebaseOnConflict = false,
10242
+ logger
10243
+ }) {
10244
+ const tempRef = `refs/temp/fern-${Date.now()}`;
10245
+ let tempRefPushed = false;
10246
+ try {
10247
+ let [localHeadSha, treeSha, message, parents] = await Promise.all([
10248
+ repository.getHeadSha(),
10249
+ repository.getHeadTreeHash(),
10250
+ repository.getHeadCommitMessage(),
10251
+ repository.getHeadParents()
10252
+ ]);
10253
+ await repository.pushObjectToRef(localHeadSha, tempRef);
10254
+ tempRefPushed = true;
10255
+ for (let attempt = 0; attempt < MAX_CONCURRENT_PUSH_RETRIES; attempt++) {
10256
+ const { data: signedCommit } = await octokit.git.createCommit({
10257
+ owner,
10258
+ repo,
10259
+ message,
10260
+ tree: treeSha,
10261
+ parents
10262
+ });
10263
+ const signedSha = signedCommit.sha;
10264
+ try {
10265
+ await upsertBranchRef({ octokit, owner, repo, branch, sha: signedSha, force });
10266
+ logger.debug(`Updated refs/heads/${branch} to signed commit ${signedSha}`);
10267
+ await syncLocalToSignedCommit({ repository, branch, signedSha });
10268
+ return signedSha;
10269
+ } catch (err) {
10270
+ if (!isNonFastForwardError(err) || force || attempt >= MAX_CONCURRENT_PUSH_RETRIES - 1) {
10271
+ throw err;
10272
+ }
10273
+ if (rebaseOnConflict) {
10274
+ logger.warn(
10275
+ `Non-fast-forward on refs/heads/${branch} (attempt ${attempt + 1}/${MAX_CONCURRENT_PUSH_RETRIES}); rebasing locally and retrying.`
10276
+ );
10277
+ await repository.pullWithRebase(branch);
10278
+ [localHeadSha, treeSha, message, parents] = await Promise.all([
10279
+ repository.getHeadSha(),
10280
+ repository.getHeadTreeHash(),
10281
+ repository.getHeadCommitMessage(),
10282
+ repository.getHeadParents()
10283
+ ]);
10284
+ await repository.pushObjectToRef(localHeadSha, tempRef, { force: true });
10285
+ } else {
10286
+ throw err;
10287
+ }
10288
+ }
10289
+ }
10290
+ throw new Error(
10291
+ `Failed to push signed commit to refs/heads/${branch} after ${MAX_CONCURRENT_PUSH_RETRIES} attempts`
10292
+ );
10293
+ } finally {
10294
+ if (tempRefPushed) {
10295
+ try {
10296
+ await octokit.git.deleteRef({ owner, repo, ref: tempRef.replace(/^refs\//, "") });
10297
+ } catch (err) {
10298
+ logger.debug(`Failed to delete temp ref ${tempRef}: ${extractErrorMessage(err)}`);
10299
+ }
10300
+ }
10301
+ }
10302
+ }
10303
+ async function upsertBranchRef({
10304
+ octokit,
10305
+ owner,
10306
+ repo,
10307
+ branch,
10308
+ sha,
10309
+ force
10310
+ }) {
10311
+ try {
10312
+ await octokit.git.updateRef({
10313
+ owner,
10314
+ repo,
10315
+ ref: `heads/${branch}`,
10316
+ sha,
10317
+ force
10318
+ });
10319
+ } catch (err) {
10320
+ if (isNotFoundError(err)) {
10321
+ await octokit.git.createRef({
10322
+ owner,
10323
+ repo,
10324
+ ref: `refs/heads/${branch}`,
10325
+ sha
10326
+ });
10327
+ return;
10328
+ }
10329
+ throw err;
10330
+ }
10331
+ }
10332
+ async function syncLocalToSignedCommit({
10333
+ repository,
10334
+ branch,
10335
+ signedSha
10336
+ }) {
10337
+ await repository.fetch(["origin", branch]);
10338
+ await repository.resetHardToSha(signedSha);
10339
+ }
10340
+ function hasNumericStatus(err) {
10341
+ return typeof err === "object" && err != null && "status" in err && typeof err.status === "number";
10342
+ }
10343
+ function isNotFoundError(err) {
10344
+ return hasNumericStatus(err) && err.status === 404;
10345
+ }
10346
+ function isNonFastForwardError(err) {
10347
+ if (!hasNumericStatus(err) || err.status !== 422) {
10348
+ return false;
10349
+ }
10350
+ const message = extractErrorMessage(err).toLowerCase();
10351
+ return message.includes("not a fast forward") || message.includes("not a fast-forward") || message.includes("update is not a fast forward");
10352
+ }
10353
+
10160
10354
  // src/pipeline/replay-summary.ts
10161
10355
  function plural(n, word) {
10162
10356
  return `${n} ${word}${n === 1 ? "" : "s"}`;
@@ -10288,16 +10482,6 @@ function formatReplayPrBody(result, options) {
10288
10482
  return parts.join("\n");
10289
10483
  }
10290
10484
 
10291
- // src/pipeline/steps/BaseStep.ts
10292
- var BaseStep = class {
10293
- constructor(outputDir, logger) {
10294
- this.outputDir = outputDir;
10295
- this.logger = logger;
10296
- }
10297
- outputDir;
10298
- logger;
10299
- };
10300
-
10301
10485
  // src/pipeline/steps/GithubStep.ts
10302
10486
  var GithubStep = class extends BaseStep {
10303
10487
  constructor(outputDir, logger, config) {
@@ -10377,13 +10561,17 @@ var GithubStep = class extends BaseStep {
10377
10561
  });
10378
10562
  switch (branchAction) {
10379
10563
  case "replay-branch":
10380
- generationBaseSha = await createReplayBranch(
10381
- repository,
10382
- prBranch,
10383
- this.config.commitMessage,
10384
- replayConflictInfo,
10385
- this.logger
10386
- );
10564
+ if (shouldPushGenerationBaseTag(replayResult)) {
10565
+ generationBaseSha = await createReplayBranch(
10566
+ repository,
10567
+ prBranch,
10568
+ this.config.commitMessage,
10569
+ replayConflictInfo,
10570
+ this.logger
10571
+ );
10572
+ } else {
10573
+ await repository.createBranchFromHead(prBranch);
10574
+ }
10387
10575
  break;
10388
10576
  case "create-from-head":
10389
10577
  await repository.createBranchFromHead(prBranch);
@@ -10403,7 +10591,7 @@ var GithubStep = class extends BaseStep {
10403
10591
  await repository.commitAllChanges(finalCommitMessage2);
10404
10592
  this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
10405
10593
  }
10406
- if (this.config.automationMode) {
10594
+ if (shouldCheckNoDiff(this.config)) {
10407
10595
  const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
10408
10596
  if (noDiff) {
10409
10597
  this.logger.info("No changes detected after generation \u2014 skipping PR creation");
@@ -10416,11 +10604,15 @@ var GithubStep = class extends BaseStep {
10416
10604
  updatedExistingPr: isUpdatingExistingPR
10417
10605
  };
10418
10606
  if (!this.config.previewMode) {
10419
- if (isUpdatingExistingPR) {
10420
- await repository.forcePush();
10421
- } else {
10422
- await repository.push();
10423
- }
10607
+ await pushSignedCommit({
10608
+ repository,
10609
+ octokit,
10610
+ owner,
10611
+ repo,
10612
+ branch: prBranch,
10613
+ force: isUpdatingExistingPR,
10614
+ logger: this.logger
10615
+ });
10424
10616
  const pushedBranch = await repository.getCurrentBranch();
10425
10617
  result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
10426
10618
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
@@ -10521,7 +10713,7 @@ var GithubStep = class extends BaseStep {
10521
10713
  const finalCommitMessage = this.config.commitMessage ?? "SDK Generation";
10522
10714
  await repository.commitAllChanges(finalCommitMessage);
10523
10715
  this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
10524
- if (this.config.automationMode) {
10716
+ if (shouldCheckNoDiff(this.config)) {
10525
10717
  const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
10526
10718
  if (noDiff) {
10527
10719
  this.logger.info("No changes detected after generation \u2014 skipping push");
@@ -10533,7 +10725,18 @@ var GithubStep = class extends BaseStep {
10533
10725
  success: true
10534
10726
  };
10535
10727
  if (!this.config.previewMode) {
10536
- await repository.pushWithRebasingRemote();
10728
+ const octokit = new import_rest2.Octokit({ auth: this.config.token });
10729
+ const { owner, repo } = parseRepository(this.config.uri);
10730
+ await pushSignedCommit({
10731
+ repository,
10732
+ octokit,
10733
+ owner,
10734
+ repo,
10735
+ branch: baseBranch,
10736
+ force: false,
10737
+ rebaseOnConflict: true,
10738
+ logger: this.logger
10739
+ });
10537
10740
  const pushedBranch = await repository.getCurrentBranch();
10538
10741
  result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
10539
10742
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
@@ -10592,6 +10795,12 @@ _Fern Run ID: \`${config.runId}\`_`;
10592
10795
  function shouldEnableAutomerge(config) {
10593
10796
  return config.automationMode === true && config.autoMerge === true && config.hasBreakingChanges !== true;
10594
10797
  }
10798
+ function shouldCheckNoDiff(config) {
10799
+ return config.skipIfNoDiff === true;
10800
+ }
10801
+ function shouldPushGenerationBaseTag(replayResult) {
10802
+ return (replayResult?.patchesWithConflicts ?? 0) > 0;
10803
+ }
10595
10804
  function resolveBranchAction({
10596
10805
  automationMode,
10597
10806
  skipCommit,
@@ -10730,18 +10939,24 @@ async function replayRun(params) {
10730
10939
  }
10731
10940
  }
10732
10941
  if (shouldSync && tagSha != null) {
10733
- const syncService = new import_replay.ReplayService(outputDir, { enabled: true });
10734
- await syncService.syncFromDivergentMerge(tagSha, {
10735
- cliVersion,
10736
- generatorVersions,
10737
- baseBranchHead: baseBranchHead ?? void 0
10738
- });
10739
- try {
10740
- const freshLockManager = new import_replay.LockfileManager(outputDir);
10741
- if (freshLockManager.exists()) {
10742
- previousGenerationSha = freshLockManager.read().current_generation;
10942
+ if (!isTagMergedIntoHead(outputDir, tagSha)) {
10943
+ logger?.warn(
10944
+ `fern-generation-base tag ${tagSha} is not reachable from HEAD \u2014 skipping divergent-merge sync. The tag likely points at an unmerged generation (PR closed without merge).`
10945
+ );
10946
+ } else {
10947
+ const syncService = new import_replay.ReplayService(outputDir, { enabled: true });
10948
+ await syncService.syncFromDivergentMerge(tagSha, {
10949
+ cliVersion,
10950
+ generatorVersions,
10951
+ baseBranchHead: baseBranchHead ?? void 0
10952
+ });
10953
+ try {
10954
+ const freshLockManager = new import_replay.LockfileManager(outputDir);
10955
+ if (freshLockManager.exists()) {
10956
+ previousGenerationSha = freshLockManager.read().current_generation;
10957
+ }
10958
+ } catch {
10743
10959
  }
10744
- } catch {
10745
10960
  }
10746
10961
  }
10747
10962
  }
@@ -10791,6 +11006,30 @@ async function replayRun(params) {
10791
11006
  baseBranchHead: resolvedBaseBranchHead
10792
11007
  };
10793
11008
  }
11009
+ function isTagMergedIntoHead(cwd2, tagSha) {
11010
+ try {
11011
+ (0, import_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
11012
+ cwd: cwd2,
11013
+ stdio: "pipe"
11014
+ });
11015
+ return true;
11016
+ } catch {
11017
+ }
11018
+ const tagTree = gitRevParse(cwd2, `${tagSha}^{tree}`);
11019
+ if (tagTree == null) {
11020
+ return false;
11021
+ }
11022
+ try {
11023
+ const trees = (0, import_child_process3.execFileSync)("git", ["log", "HEAD", "--format=%T", "--max-count=500"], {
11024
+ cwd: cwd2,
11025
+ encoding: "utf-8",
11026
+ stdio: "pipe"
11027
+ });
11028
+ return trees.split("\n").some((t2) => t2.trim() === tagTree);
11029
+ } catch {
11030
+ return false;
11031
+ }
11032
+ }
10794
11033
  function gitRevParse(cwd2, rev) {
10795
11034
  try {
10796
11035
  return (0, import_child_process3.execFileSync)("git", ["rev-parse", "--verify", rev], {
@@ -10892,6 +11131,9 @@ var PostGenerationPipeline = class {
10892
11131
  );
10893
11132
  config.replay.enabled = false;
10894
11133
  }
11134
+ if (config.autoVersion?.enabled) {
11135
+ this.steps.push(new AutoVersionStep(config.outputDir, this.logger, config.autoVersion));
11136
+ }
10895
11137
  if (config.replay?.enabled) {
10896
11138
  this.steps.push(
10897
11139
  new ReplayStep(
@@ -10932,6 +11174,9 @@ var PostGenerationPipeline = class {
10932
11174
  if (step.name === "replay") {
10933
11175
  result.steps.replay = stepResult;
10934
11176
  pipelineContext.previousStepResults.replay = stepResult;
11177
+ } else if (step.name === "autoVersion") {
11178
+ result.steps.autoVersion = stepResult;
11179
+ pipelineContext.previousStepResults.autoVersion = stepResult;
10935
11180
  } else if (step.name === "fernignore") {
10936
11181
  result.steps.fernignore = stepResult;
10937
11182
  } else if (step.name === "github") {
@@ -11119,9 +11364,66 @@ var import_replay5 = require("@fern-api/replay");
11119
11364
  function replayStatus(params) {
11120
11365
  return (0, import_replay5.status)(params.outputDir);
11121
11366
  }
11367
+
11368
+ // src/replay/replay-submit-init.ts
11369
+ async function submitReplayInit(params) {
11370
+ const { fiddleOrigin, fernToken, githubRepo, initResult } = params;
11371
+ const { owner, repo } = parseOwnerRepo(githubRepo);
11372
+ const response = await fetch(`${fiddleOrigin}/api/remote-gen/replay/init`, {
11373
+ method: "POST",
11374
+ headers: {
11375
+ "Content-Type": "application/json",
11376
+ Authorization: `Bearer ${fernToken}`
11377
+ },
11378
+ body: JSON.stringify({
11379
+ owner,
11380
+ repo,
11381
+ lockfileContents: initResult.lockfileContent,
11382
+ fernignoreEntries: initResult.fernignoreEntries,
11383
+ prBody: initResult.prBody
11384
+ })
11385
+ });
11386
+ if (!response.ok) {
11387
+ if (response.status === 404) {
11388
+ throw new ReplaySubmitError(
11389
+ "The Fern GitHub App is not installed on this repository. Install it at https://github.com/apps/fern-api to enable server-side PR creation.",
11390
+ response.status
11391
+ );
11392
+ }
11393
+ const body = await response.text();
11394
+ throw new ReplaySubmitError(`Failed to create PR via Fern: ${body}`, response.status);
11395
+ }
11396
+ const data = await response.json();
11397
+ if (!isSubmitResponse(data)) {
11398
+ throw new ReplaySubmitError("Unexpected response from Fern: missing prUrl field.");
11399
+ }
11400
+ return { prUrl: data.prUrl };
11401
+ }
11402
+ function parseOwnerRepo(githubRepo) {
11403
+ const cleaned = githubRepo.replace(/^https?:\/\//, "").replace(/\.git$/, "").replace(/^github\.com\//, "");
11404
+ const parts = cleaned.split("/");
11405
+ const owner = parts[parts.length - 2];
11406
+ const repo = parts[parts.length - 1];
11407
+ if (!owner || !repo) {
11408
+ throw new Error(`Could not parse owner/repo from: ${githubRepo}`);
11409
+ }
11410
+ return { owner, repo };
11411
+ }
11412
+ var ReplaySubmitError = class extends Error {
11413
+ statusCode;
11414
+ constructor(message, statusCode) {
11415
+ super(message);
11416
+ this.name = "ReplaySubmitError";
11417
+ this.statusCode = statusCode;
11418
+ }
11419
+ };
11420
+ function isSubmitResponse(data) {
11421
+ return typeof data === "object" && data != null && "prUrl" in data && typeof data.prUrl === "string";
11422
+ }
11122
11423
  // Annotate the CommonJS export names for ESM import in node:
11123
11424
  0 && (module.exports = {
11124
11425
  PostGenerationPipeline,
11426
+ ReplaySubmitError,
11125
11427
  consolePipelineLogger,
11126
11428
  formatBootstrapSummary,
11127
11429
  formatReplayPrBody,
@@ -11133,9 +11435,11 @@ function replayStatus(params) {
11133
11435
  githubPush,
11134
11436
  githubRelease,
11135
11437
  logReplaySummary,
11438
+ parseOwnerRepo,
11136
11439
  replayForget,
11137
11440
  replayInit,
11138
11441
  replayResolve,
11139
11442
  replayRun,
11140
- replayStatus
11443
+ replayStatus,
11444
+ submitReplayInit
11141
11445
  });
package/dist/cli.js CHANGED
@@ -25629,6 +25629,46 @@ var ClonedRepository = class _ClonedRepository {
25629
25629
  const result = await this.git.raw(["rev-parse", "HEAD^{tree}"]);
25630
25630
  return result.trim();
25631
25631
  }
25632
+ async getHeadCommitMessage() {
25633
+ await this.git.cwd(this.clonePath);
25634
+ const result = await this.git.raw(["log", "-1", "--format=%B", "HEAD"]);
25635
+ return result.replace(/\n$/, "");
25636
+ }
25637
+ async getHeadParents() {
25638
+ await this.git.cwd(this.clonePath);
25639
+ const result = await this.git.raw(["rev-list", "--parents", "-n", "1", "HEAD"]);
25640
+ const parts = result.trim().split(/\s+/);
25641
+ return parts.slice(1);
25642
+ }
25643
+ /**
25644
+ * Pushes a specific object (commit SHA) to a remote ref.
25645
+ * Used to upload tree and blob objects to the remote without moving a branch.
25646
+ *
25647
+ * Pass `force: true` when overwriting a ref that may already point to an
25648
+ * unrelated commit (e.g. retrying a temp ref after a local rebase rewrites
25649
+ * history so the new SHA is not a descendant of the previous one).
25650
+ */
25651
+ async pushObjectToRef(localSha, remoteRef, { force = false } = {}) {
25652
+ await this.git.cwd(this.clonePath);
25653
+ const spec = force ? `+${localSha}:${remoteRef}` : `${localSha}:${remoteRef}`;
25654
+ await this.git.raw(["push", "origin", spec]);
25655
+ }
25656
+ /**
25657
+ * Resets the current branch HEAD to the given SHA. After fetching a newly-created remote
25658
+ * signed commit, use this to align the local branch so subsequent operations (tag push,
25659
+ * getHeadSha(), etc.) see the signed SHA.
25660
+ */
25661
+ async resetHardToSha(sha) {
25662
+ await this.git.cwd(this.clonePath);
25663
+ await this.git.raw(["reset", "--hard", sha]);
25664
+ }
25665
+ /**
25666
+ * Rebases the current branch onto the given remote branch (`git pull --rebase origin <branch>`).
25667
+ */
25668
+ async pullWithRebase(branch) {
25669
+ await this.git.cwd(this.clonePath);
25670
+ await this.git.raw(["pull", "origin", branch, "--rebase"]);
25671
+ }
25632
25672
  async getCommitTreeHash(commitSha) {
25633
25673
  await this.git.cwd(this.clonePath);
25634
25674
  const result = await this.git.raw(["rev-parse", `${commitSha}^{tree}`]);
@@ -33456,6 +33496,35 @@ var FERN_BOT_NAME = "fern-api";
33456
33496
  var FERN_BOT_EMAIL = "115122769+fern-api[bot]@users.noreply.github.com";
33457
33497
  var FERN_BOT_LOGIN = "fern-api[bot]";
33458
33498
 
33499
+ // src/pipeline/steps/BaseStep.ts
33500
+ var BaseStep = class {
33501
+ constructor(outputDir, logger) {
33502
+ this.outputDir = outputDir;
33503
+ this.logger = logger;
33504
+ }
33505
+ outputDir;
33506
+ logger;
33507
+ };
33508
+
33509
+ // src/pipeline/steps/AutoVersionStep.ts
33510
+ var AutoVersionStep = class extends BaseStep {
33511
+ constructor(outputDir, logger, config) {
33512
+ super(outputDir, logger);
33513
+ this.config = config;
33514
+ }
33515
+ config;
33516
+ name = "autoVersion";
33517
+ async execute(_context) {
33518
+ this.logger.info(
33519
+ `AutoVersionStep: no-op scaffold for language=${this.config.language} (logic lands in FER-9980)`
33520
+ );
33521
+ return {
33522
+ executed: true,
33523
+ success: true
33524
+ };
33525
+ }
33526
+ };
33527
+
33459
33528
  // src/pipeline/steps/GithubStep.ts
33460
33529
  var import_promises3 = require("fs/promises");
33461
33530
  var import_path7 = require("path");
@@ -33588,6 +33657,128 @@ ${prBody}`;
33588
33657
  return { prTitle, prBody };
33589
33658
  }
33590
33659
 
33660
+ // src/pipeline/github/pushSignedCommit.ts
33661
+ var MAX_CONCURRENT_PUSH_RETRIES = 3;
33662
+ async function pushSignedCommit({
33663
+ repository,
33664
+ octokit,
33665
+ owner,
33666
+ repo,
33667
+ branch,
33668
+ force,
33669
+ rebaseOnConflict = false,
33670
+ logger
33671
+ }) {
33672
+ const tempRef = `refs/temp/fern-${Date.now()}`;
33673
+ let tempRefPushed = false;
33674
+ try {
33675
+ let [localHeadSha, treeSha, message, parents] = await Promise.all([
33676
+ repository.getHeadSha(),
33677
+ repository.getHeadTreeHash(),
33678
+ repository.getHeadCommitMessage(),
33679
+ repository.getHeadParents()
33680
+ ]);
33681
+ await repository.pushObjectToRef(localHeadSha, tempRef);
33682
+ tempRefPushed = true;
33683
+ for (let attempt2 = 0; attempt2 < MAX_CONCURRENT_PUSH_RETRIES; attempt2++) {
33684
+ const { data: signedCommit } = await octokit.git.createCommit({
33685
+ owner,
33686
+ repo,
33687
+ message,
33688
+ tree: treeSha,
33689
+ parents
33690
+ });
33691
+ const signedSha = signedCommit.sha;
33692
+ try {
33693
+ await upsertBranchRef({ octokit, owner, repo, branch, sha: signedSha, force });
33694
+ logger.debug(`Updated refs/heads/${branch} to signed commit ${signedSha}`);
33695
+ await syncLocalToSignedCommit({ repository, branch, signedSha });
33696
+ return signedSha;
33697
+ } catch (err) {
33698
+ if (!isNonFastForwardError(err) || force || attempt2 >= MAX_CONCURRENT_PUSH_RETRIES - 1) {
33699
+ throw err;
33700
+ }
33701
+ if (rebaseOnConflict) {
33702
+ logger.warn(
33703
+ `Non-fast-forward on refs/heads/${branch} (attempt ${attempt2 + 1}/${MAX_CONCURRENT_PUSH_RETRIES}); rebasing locally and retrying.`
33704
+ );
33705
+ await repository.pullWithRebase(branch);
33706
+ [localHeadSha, treeSha, message, parents] = await Promise.all([
33707
+ repository.getHeadSha(),
33708
+ repository.getHeadTreeHash(),
33709
+ repository.getHeadCommitMessage(),
33710
+ repository.getHeadParents()
33711
+ ]);
33712
+ await repository.pushObjectToRef(localHeadSha, tempRef, { force: true });
33713
+ } else {
33714
+ throw err;
33715
+ }
33716
+ }
33717
+ }
33718
+ throw new Error(
33719
+ `Failed to push signed commit to refs/heads/${branch} after ${MAX_CONCURRENT_PUSH_RETRIES} attempts`
33720
+ );
33721
+ } finally {
33722
+ if (tempRefPushed) {
33723
+ try {
33724
+ await octokit.git.deleteRef({ owner, repo, ref: tempRef.replace(/^refs\//, "") });
33725
+ } catch (err) {
33726
+ logger.debug(`Failed to delete temp ref ${tempRef}: ${extractErrorMessage(err)}`);
33727
+ }
33728
+ }
33729
+ }
33730
+ }
33731
+ async function upsertBranchRef({
33732
+ octokit,
33733
+ owner,
33734
+ repo,
33735
+ branch,
33736
+ sha,
33737
+ force
33738
+ }) {
33739
+ try {
33740
+ await octokit.git.updateRef({
33741
+ owner,
33742
+ repo,
33743
+ ref: `heads/${branch}`,
33744
+ sha,
33745
+ force
33746
+ });
33747
+ } catch (err) {
33748
+ if (isNotFoundError(err)) {
33749
+ await octokit.git.createRef({
33750
+ owner,
33751
+ repo,
33752
+ ref: `refs/heads/${branch}`,
33753
+ sha
33754
+ });
33755
+ return;
33756
+ }
33757
+ throw err;
33758
+ }
33759
+ }
33760
+ async function syncLocalToSignedCommit({
33761
+ repository,
33762
+ branch,
33763
+ signedSha
33764
+ }) {
33765
+ await repository.fetch(["origin", branch]);
33766
+ await repository.resetHardToSha(signedSha);
33767
+ }
33768
+ function hasNumericStatus(err) {
33769
+ return typeof err === "object" && err != null && "status" in err && typeof err.status === "number";
33770
+ }
33771
+ function isNotFoundError(err) {
33772
+ return hasNumericStatus(err) && err.status === 404;
33773
+ }
33774
+ function isNonFastForwardError(err) {
33775
+ if (!hasNumericStatus(err) || err.status !== 422) {
33776
+ return false;
33777
+ }
33778
+ const message = extractErrorMessage(err).toLowerCase();
33779
+ return message.includes("not a fast forward") || message.includes("not a fast-forward") || message.includes("update is not a fast forward");
33780
+ }
33781
+
33591
33782
  // src/pipeline/replay-summary.ts
33592
33783
  function plural(n, word) {
33593
33784
  return `${n} ${word}${n === 1 ? "" : "s"}`;
@@ -33683,16 +33874,6 @@ function formatReplayPrBody(result, options) {
33683
33874
  return parts.join("\n");
33684
33875
  }
33685
33876
 
33686
- // src/pipeline/steps/BaseStep.ts
33687
- var BaseStep = class {
33688
- constructor(outputDir, logger) {
33689
- this.outputDir = outputDir;
33690
- this.logger = logger;
33691
- }
33692
- outputDir;
33693
- logger;
33694
- };
33695
-
33696
33877
  // src/pipeline/steps/GithubStep.ts
33697
33878
  var GithubStep = class extends BaseStep {
33698
33879
  constructor(outputDir, logger, config) {
@@ -33772,13 +33953,17 @@ var GithubStep = class extends BaseStep {
33772
33953
  });
33773
33954
  switch (branchAction) {
33774
33955
  case "replay-branch":
33775
- generationBaseSha = await createReplayBranch(
33776
- repository,
33777
- prBranch,
33778
- this.config.commitMessage,
33779
- replayConflictInfo,
33780
- this.logger
33781
- );
33956
+ if (shouldPushGenerationBaseTag(replayResult)) {
33957
+ generationBaseSha = await createReplayBranch(
33958
+ repository,
33959
+ prBranch,
33960
+ this.config.commitMessage,
33961
+ replayConflictInfo,
33962
+ this.logger
33963
+ );
33964
+ } else {
33965
+ await repository.createBranchFromHead(prBranch);
33966
+ }
33782
33967
  break;
33783
33968
  case "create-from-head":
33784
33969
  await repository.createBranchFromHead(prBranch);
@@ -33798,7 +33983,7 @@ var GithubStep = class extends BaseStep {
33798
33983
  await repository.commitAllChanges(finalCommitMessage2);
33799
33984
  this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
33800
33985
  }
33801
- if (this.config.automationMode) {
33986
+ if (shouldCheckNoDiff(this.config)) {
33802
33987
  const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
33803
33988
  if (noDiff) {
33804
33989
  this.logger.info("No changes detected after generation \u2014 skipping PR creation");
@@ -33811,11 +33996,15 @@ var GithubStep = class extends BaseStep {
33811
33996
  updatedExistingPr: isUpdatingExistingPR
33812
33997
  };
33813
33998
  if (!this.config.previewMode) {
33814
- if (isUpdatingExistingPR) {
33815
- await repository.forcePush();
33816
- } else {
33817
- await repository.push();
33818
- }
33999
+ await pushSignedCommit({
34000
+ repository,
34001
+ octokit,
34002
+ owner,
34003
+ repo,
34004
+ branch: prBranch,
34005
+ force: isUpdatingExistingPR,
34006
+ logger: this.logger
34007
+ });
33819
34008
  const pushedBranch = await repository.getCurrentBranch();
33820
34009
  result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
33821
34010
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
@@ -33916,7 +34105,7 @@ var GithubStep = class extends BaseStep {
33916
34105
  const finalCommitMessage = this.config.commitMessage ?? "SDK Generation";
33917
34106
  await repository.commitAllChanges(finalCommitMessage);
33918
34107
  this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
33919
- if (this.config.automationMode) {
34108
+ if (shouldCheckNoDiff(this.config)) {
33920
34109
  const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
33921
34110
  if (noDiff) {
33922
34111
  this.logger.info("No changes detected after generation \u2014 skipping push");
@@ -33928,7 +34117,18 @@ var GithubStep = class extends BaseStep {
33928
34117
  success: true
33929
34118
  };
33930
34119
  if (!this.config.previewMode) {
33931
- await repository.pushWithRebasingRemote();
34120
+ const octokit = new Octokit2({ auth: this.config.token });
34121
+ const { owner, repo } = parseRepository(this.config.uri);
34122
+ await pushSignedCommit({
34123
+ repository,
34124
+ octokit,
34125
+ owner,
34126
+ repo,
34127
+ branch: baseBranch,
34128
+ force: false,
34129
+ rebaseOnConflict: true,
34130
+ logger: this.logger
34131
+ });
33932
34132
  const pushedBranch = await repository.getCurrentBranch();
33933
34133
  result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
33934
34134
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
@@ -33987,6 +34187,12 @@ _Fern Run ID: \`${config.runId}\`_`;
33987
34187
  function shouldEnableAutomerge(config) {
33988
34188
  return config.automationMode === true && config.autoMerge === true && config.hasBreakingChanges !== true;
33989
34189
  }
34190
+ function shouldCheckNoDiff(config) {
34191
+ return config.skipIfNoDiff === true;
34192
+ }
34193
+ function shouldPushGenerationBaseTag(replayResult) {
34194
+ return (replayResult?.patchesWithConflicts ?? 0) > 0;
34195
+ }
33990
34196
  function resolveBranchAction({
33991
34197
  automationMode,
33992
34198
  skipCommit,
@@ -34125,18 +34331,24 @@ async function replayRun(params) {
34125
34331
  }
34126
34332
  }
34127
34333
  if (shouldSync && tagSha != null) {
34128
- const syncService = new ReplayService(outputDir, { enabled: true });
34129
- await syncService.syncFromDivergentMerge(tagSha, {
34130
- cliVersion,
34131
- generatorVersions,
34132
- baseBranchHead: baseBranchHead ?? void 0
34133
- });
34134
- try {
34135
- const freshLockManager = new LockfileManager(outputDir);
34136
- if (freshLockManager.exists()) {
34137
- previousGenerationSha = freshLockManager.read().current_generation;
34334
+ if (!isTagMergedIntoHead(outputDir, tagSha)) {
34335
+ logger?.warn(
34336
+ `fern-generation-base tag ${tagSha} is not reachable from HEAD \u2014 skipping divergent-merge sync. The tag likely points at an unmerged generation (PR closed without merge).`
34337
+ );
34338
+ } else {
34339
+ const syncService = new ReplayService(outputDir, { enabled: true });
34340
+ await syncService.syncFromDivergentMerge(tagSha, {
34341
+ cliVersion,
34342
+ generatorVersions,
34343
+ baseBranchHead: baseBranchHead ?? void 0
34344
+ });
34345
+ try {
34346
+ const freshLockManager = new LockfileManager(outputDir);
34347
+ if (freshLockManager.exists()) {
34348
+ previousGenerationSha = freshLockManager.read().current_generation;
34349
+ }
34350
+ } catch {
34138
34351
  }
34139
- } catch {
34140
34352
  }
34141
34353
  }
34142
34354
  }
@@ -34186,6 +34398,30 @@ async function replayRun(params) {
34186
34398
  baseBranchHead: resolvedBaseBranchHead
34187
34399
  };
34188
34400
  }
34401
+ function isTagMergedIntoHead(cwd2, tagSha) {
34402
+ try {
34403
+ (0, import_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
34404
+ cwd: cwd2,
34405
+ stdio: "pipe"
34406
+ });
34407
+ return true;
34408
+ } catch {
34409
+ }
34410
+ const tagTree = gitRevParse(cwd2, `${tagSha}^{tree}`);
34411
+ if (tagTree == null) {
34412
+ return false;
34413
+ }
34414
+ try {
34415
+ const trees = (0, import_child_process3.execFileSync)("git", ["log", "HEAD", "--format=%T", "--max-count=500"], {
34416
+ cwd: cwd2,
34417
+ encoding: "utf-8",
34418
+ stdio: "pipe"
34419
+ });
34420
+ return trees.split("\n").some((t2) => t2.trim() === tagTree);
34421
+ } catch {
34422
+ return false;
34423
+ }
34424
+ }
34189
34425
  function gitRevParse(cwd2, rev) {
34190
34426
  try {
34191
34427
  return (0, import_child_process3.execFileSync)("git", ["rev-parse", "--verify", rev], {
@@ -34287,6 +34523,9 @@ var PostGenerationPipeline = class {
34287
34523
  );
34288
34524
  config.replay.enabled = false;
34289
34525
  }
34526
+ if (config.autoVersion?.enabled) {
34527
+ this.steps.push(new AutoVersionStep(config.outputDir, this.logger, config.autoVersion));
34528
+ }
34290
34529
  if (config.replay?.enabled) {
34291
34530
  this.steps.push(
34292
34531
  new ReplayStep(
@@ -34327,6 +34566,9 @@ var PostGenerationPipeline = class {
34327
34566
  if (step.name === "replay") {
34328
34567
  result.steps.replay = stepResult;
34329
34568
  pipelineContext.previousStepResults.replay = stepResult;
34569
+ } else if (step.name === "autoVersion") {
34570
+ result.steps.autoVersion = stepResult;
34571
+ pipelineContext.previousStepResults.autoVersion = stepResult;
34330
34572
  } else if (step.name === "fernignore") {
34331
34573
  result.steps.fernignore = stepResult;
34332
34574
  } else if (step.name === "github") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fern-api/fern.git",