@fern-api/generator-cli 0.9.22 → 0.9.24

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
@@ -572,7 +572,7 @@ interface ReplayRunParams {
572
572
  logger?: PipelineLogger;
573
573
  }
574
574
  interface ReplayRunResult {
575
- /** null if replay wasn't initialized (no lockfile) */
575
+ /** null if replay wasn't initialized (no lockfile) OR if prepare/apply crashed (see failureReason) */
576
576
  report: ReplayReport | null;
577
577
  /** Whether .fernignore was updated */
578
578
  fernignoreUpdated: boolean;
@@ -582,6 +582,20 @@ interface ReplayRunResult {
582
582
  currentGenerationSha: string | null;
583
583
  /** SHA of main's HEAD before replay ran. Always on main's lineage, stable after squash merges. */
584
584
  baseBranchHead: string | null;
585
+ /** True when this run inlined `bootstrap()` to create the lockfile (auto-init from `fern generate`). */
586
+ autoBootstrapped: boolean;
587
+ /**
588
+ * True when the lockfile-missing branch was entered, regardless of bootstrap outcome.
589
+ * Distinct from `autoBootstrapped` (true only on success) — together they let telemetry
590
+ * distinguish "tried but no anchor / threw" from "lockfile already existed".
591
+ */
592
+ bootstrapAttempted: boolean;
593
+ /**
594
+ * Set when prepare or apply crashed (e.g. corrupted lockfile, git failure, library bug).
595
+ * Distinguishes a real failure from "no replay initialized" (lockfile missing → null report, no failureReason).
596
+ * Generation never fails on replay errors — callers should surface this for telemetry/logging only.
597
+ */
598
+ failureReason?: string;
585
599
  }
586
600
  /**
587
601
  * Backwards-compatible atomic entry point. Composes `replayPrepare` +
package/dist/api.js CHANGED
@@ -6173,7 +6173,9 @@ function newRepositoryReference({ remote, owner, repo }) {
6173
6173
  repoUrl,
6174
6174
  cloneUrl,
6175
6175
  getAuthedCloneUrl: (installationToken) => {
6176
- return cloneUrl.replace("https://", `https://x-access-token:${installationToken}@`);
6176
+ const isInstallationToken = installationToken.startsWith("ghs_") || installationToken.startsWith("ghu_");
6177
+ const userPrefix = isInstallationToken ? "x-access-token:" : "";
6178
+ return cloneUrl.replace("https://", `https://${userPrefix}${installationToken}@`);
6177
6179
  }
6178
6180
  };
6179
6181
  }
@@ -9894,7 +9896,7 @@ function cwd() {
9894
9896
  // ../commons/fs-utils/lib/resolve.js
9895
9897
  var import_path2 = __toESM(require("path"), 1);
9896
9898
  function resolve2(...paths) {
9897
- return import_path2.default.resolve(...paths.map(convertToOsPath));
9899
+ return convertToOsPath(import_path2.default.resolve(...paths.map(convertToOsPath)));
9898
9900
  }
9899
9901
 
9900
9902
  // src/github/GitHub.ts
@@ -10245,7 +10247,7 @@ var import_replay4 = require("@fern-api/replay");
10245
10247
  var import_child_process3 = require("child_process");
10246
10248
  var import_fs3 = require("fs");
10247
10249
  var import_path5 = require("path");
10248
- async function replayPrepare(params) {
10250
+ async function replayPrepare(params, state) {
10249
10251
  const {
10250
10252
  outputDir,
10251
10253
  cliVersion,
@@ -10256,8 +10258,36 @@ async function replayPrepare(params) {
10256
10258
  logger
10257
10259
  } = params;
10258
10260
  const lockfilePath = (0, import_path5.join)(outputDir, ".fern", "replay.lock");
10261
+ let autoBootstrapped = false;
10262
+ let bootstrapAttempted = false;
10259
10263
  if (!(0, import_fs3.existsSync)(lockfilePath)) {
10260
- return null;
10264
+ if (process.env.FERN_DISABLE_AUTO_BOOTSTRAP === "true" || process.env.FERN_DISABLE_AUTO_BOOTSTRAP === "1") {
10265
+ return null;
10266
+ }
10267
+ bootstrapAttempted = true;
10268
+ if (state) {
10269
+ state.bootstrapAttempted = true;
10270
+ }
10271
+ try {
10272
+ const bootstrapResult = await (0, import_replay4.bootstrap)(outputDir, {
10273
+ fernignoreAction: "skip",
10274
+ force: false,
10275
+ importHistory: false
10276
+ });
10277
+ if (bootstrapResult.generationCommit == null) {
10278
+ return null;
10279
+ }
10280
+ autoBootstrapped = true;
10281
+ } catch (error) {
10282
+ logger?.warn("Replay auto-bootstrap failed, continuing without replay: " + String(error));
10283
+ try {
10284
+ if ((0, import_fs3.existsSync)(lockfilePath)) {
10285
+ (0, import_fs3.unlinkSync)(lockfilePath);
10286
+ }
10287
+ } catch {
10288
+ }
10289
+ return null;
10290
+ }
10261
10291
  }
10262
10292
  const baseBranchHead = gitRevParse(outputDir, "HEAD");
10263
10293
  let previousGenerationSha = null;
@@ -10295,12 +10325,17 @@ async function replayPrepare(params) {
10295
10325
  `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).`
10296
10326
  );
10297
10327
  } else {
10298
- const syncService = new import_replay4.ReplayService(outputDir, { enabled: true });
10299
- await syncService.syncFromDivergentMerge(tagSha, {
10300
- cliVersion,
10301
- generatorVersions,
10302
- baseBranchHead: baseBranchHead ?? void 0
10303
- });
10328
+ try {
10329
+ const syncService = new import_replay4.ReplayService(outputDir, { enabled: true });
10330
+ await syncService.syncFromDivergentMerge(tagSha, {
10331
+ cliVersion,
10332
+ generatorVersions,
10333
+ baseBranchHead: baseBranchHead ?? void 0
10334
+ });
10335
+ } catch (error) {
10336
+ logger?.warn("Replay divergent-merge sync failed, continuing without sync: " + String(error));
10337
+ throw new ReplayPrepareError(String(error), error);
10338
+ }
10304
10339
  try {
10305
10340
  const freshLockManager = new import_replay4.LockfileManager(outputDir);
10306
10341
  if (freshLockManager.exists()) {
@@ -10322,8 +10357,8 @@ async function replayPrepare(params) {
10322
10357
  baseBranchHead: baseBranchHead ?? void 0
10323
10358
  });
10324
10359
  } catch (error) {
10325
- logger?.warn("Replay failed, continuing without replay: " + String(error));
10326
- return null;
10360
+ logger?.warn("Replay prepare failed, continuing without replay: " + String(error));
10361
+ throw new ReplayPrepareError(String(error), error);
10327
10362
  }
10328
10363
  return {
10329
10364
  _service: service,
@@ -10332,7 +10367,9 @@ async function replayPrepare(params) {
10332
10367
  flow: preparation.flow,
10333
10368
  previousGenerationSha,
10334
10369
  currentGenerationSha: preparation.currentGenerationSha,
10335
- baseBranchHead
10370
+ baseBranchHead,
10371
+ autoBootstrapped,
10372
+ bootstrapAttempted
10336
10373
  };
10337
10374
  }
10338
10375
  async function replayApply(prepared, params = {}) {
@@ -10341,13 +10378,16 @@ async function replayApply(prepared, params = {}) {
10341
10378
  try {
10342
10379
  report = await prepared._service.applyPreparedReplay(prepared._preparation, { stageOnly });
10343
10380
  } catch (error) {
10344
- logger?.warn("Replay failed, continuing without replay: " + String(error));
10381
+ logger?.warn("Replay apply failed, continuing without replay: " + String(error));
10345
10382
  return {
10346
10383
  report: null,
10347
10384
  fernignoreUpdated: false,
10348
10385
  previousGenerationSha: prepared.previousGenerationSha,
10349
10386
  currentGenerationSha: prepared.currentGenerationSha,
10350
- baseBranchHead: prepared.baseBranchHead
10387
+ baseBranchHead: prepared.baseBranchHead,
10388
+ autoBootstrapped: prepared.autoBootstrapped,
10389
+ bootstrapAttempted: prepared.bootstrapAttempted,
10390
+ failureReason: String(error)
10351
10391
  };
10352
10392
  }
10353
10393
  let resolvedBaseBranchHead = prepared.baseBranchHead;
@@ -10369,22 +10409,53 @@ async function replayApply(prepared, params = {}) {
10369
10409
  fernignoreUpdated,
10370
10410
  previousGenerationSha: prepared.previousGenerationSha,
10371
10411
  currentGenerationSha: prepared.currentGenerationSha,
10372
- baseBranchHead: resolvedBaseBranchHead
10412
+ baseBranchHead: resolvedBaseBranchHead,
10413
+ autoBootstrapped: prepared.autoBootstrapped,
10414
+ bootstrapAttempted: prepared.bootstrapAttempted
10373
10415
  };
10374
10416
  }
10375
10417
  async function replayRun(params) {
10376
- const prepared = await replayPrepare(params);
10418
+ const prepareState = { bootstrapAttempted: false };
10419
+ let prepared;
10420
+ try {
10421
+ prepared = await replayPrepare(params, prepareState);
10422
+ } catch (error) {
10423
+ return {
10424
+ report: null,
10425
+ fernignoreUpdated: false,
10426
+ previousGenerationSha: null,
10427
+ currentGenerationSha: null,
10428
+ baseBranchHead: null,
10429
+ autoBootstrapped: false,
10430
+ bootstrapAttempted: prepareState.bootstrapAttempted,
10431
+ failureReason: error instanceof ReplayPrepareError ? error.reason : String(error)
10432
+ };
10433
+ }
10377
10434
  if (prepared == null) {
10378
10435
  return {
10379
10436
  report: null,
10380
10437
  fernignoreUpdated: false,
10381
10438
  previousGenerationSha: null,
10382
10439
  currentGenerationSha: null,
10383
- baseBranchHead: null
10440
+ baseBranchHead: null,
10441
+ autoBootstrapped: false,
10442
+ bootstrapAttempted: prepareState.bootstrapAttempted
10384
10443
  };
10385
10444
  }
10386
10445
  return replayApply(prepared, { stageOnly: params.stageOnly, logger: params.logger });
10387
10446
  }
10447
+ var ReplayPrepareError = class extends Error {
10448
+ reason;
10449
+ constructor(reason, cause) {
10450
+ super(`Replay prepare failed: ${reason}`, { cause });
10451
+ Object.setPrototypeOf(this, new.target.prototype);
10452
+ if (Error.captureStackTrace) {
10453
+ Error.captureStackTrace(this, this.constructor);
10454
+ }
10455
+ this.name = this.constructor.name;
10456
+ this.reason = reason;
10457
+ }
10458
+ };
10388
10459
  function isTagMergedIntoHead(cwd2, tagSha) {
10389
10460
  try {
10390
10461
  (0, import_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
package/dist/cli.js CHANGED
@@ -29211,11 +29211,11 @@ var VersionBump2;
29211
29211
  var init_types = __esm({
29212
29212
  "../cli/ai/lib/baml_client/types.js"() {
29213
29213
  "use strict";
29214
- (function(VersionBump3) {
29215
- VersionBump3["MAJOR"] = "MAJOR";
29216
- VersionBump3["MINOR"] = "MINOR";
29217
- VersionBump3["PATCH"] = "PATCH";
29218
- VersionBump3["NO_CHANGE"] = "NO_CHANGE";
29214
+ (function(VersionBump4) {
29215
+ VersionBump4["MAJOR"] = "MAJOR";
29216
+ VersionBump4["MINOR"] = "MINOR";
29217
+ VersionBump4["PATCH"] = "PATCH";
29218
+ VersionBump4["NO_CHANGE"] = "NO_CHANGE";
29219
29219
  })(VersionBump2 || (VersionBump2 = {}));
29220
29220
  }
29221
29221
  });
@@ -29245,6 +29245,24 @@ var init_watchers = __esm({
29245
29245
  });
29246
29246
 
29247
29247
  // ../cli/ai/lib/baml_client/index.js
29248
+ var baml_client_exports = {};
29249
+ __export(baml_client_exports, {
29250
+ BamlClientFinishReasonError: () => import_baml6.BamlClientFinishReasonError,
29251
+ BamlClientHttpError: () => import_baml6.BamlClientHttpError,
29252
+ BamlValidationError: () => import_baml6.BamlValidationError,
29253
+ VersionBump: () => VersionBump2,
29254
+ all_succeeded: () => all_succeeded,
29255
+ b: () => b2,
29256
+ flush: () => flush,
29257
+ get_checks: () => get_checks,
29258
+ onLogEvent: () => onLogEvent,
29259
+ resetBamlEnvVars: () => resetBamlEnvVars,
29260
+ setTags: () => setTags,
29261
+ traceAsync: () => traceAsync,
29262
+ traceSync: () => traceSync,
29263
+ version: () => version,
29264
+ watchers: () => watchers_exports
29265
+ });
29248
29266
  var import_baml5, import_baml6, version;
29249
29267
  var init_baml_client = __esm({
29250
29268
  "../cli/ai/lib/baml_client/index.js"() {
@@ -29262,6 +29280,10 @@ var init_baml_client = __esm({
29262
29280
  });
29263
29281
 
29264
29282
  // ../cli/ai/lib/configureBamlClient.js
29283
+ var configureBamlClient_exports = {};
29284
+ __export(configureBamlClient_exports, {
29285
+ configureBamlClient: () => configureBamlClient
29286
+ });
29265
29287
  function configureBamlClient(config) {
29266
29288
  const registry = new import_baml7.ClientRegistry();
29267
29289
  const clientOptions = {
@@ -29282,31 +29304,59 @@ var init_configureBamlClient = __esm({
29282
29304
  }
29283
29305
  });
29284
29306
 
29307
+ // ../cli/ai/lib/loader.js
29308
+ async function loadBamlDependencies() {
29309
+ try {
29310
+ const [baml, bamlClient, config] = await Promise.all([
29311
+ import("@boundaryml/baml"),
29312
+ Promise.resolve().then(() => (init_baml_client(), baml_client_exports)),
29313
+ Promise.resolve().then(() => (init_configureBamlClient(), configureBamlClient_exports))
29314
+ ]);
29315
+ return {
29316
+ ClientRegistry: baml.ClientRegistry,
29317
+ BamlClient: bamlClient.b,
29318
+ configureBamlClient: config.configureBamlClient
29319
+ };
29320
+ } catch (error) {
29321
+ const original = error instanceof Error ? error.message : String(error);
29322
+ throw new Error(`${INSTALL_MESSAGE}
29323
+
29324
+ Original error: ${original}`);
29325
+ }
29326
+ }
29327
+ var INSTALL_MESSAGE;
29328
+ var init_loader = __esm({
29329
+ "../cli/ai/lib/loader.js"() {
29330
+ "use strict";
29331
+ INSTALL_MESSAGE = "@boundaryml/baml is required for AI features (auto-versioning, sdk-diff).\nInstall it with:\n npm install @boundaryml/baml\n pnpm add @boundaryml/baml";
29332
+ }
29333
+ });
29334
+
29335
+ // ../cli/ai/lib/types.js
29336
+ var VersionBump3;
29337
+ var init_types2 = __esm({
29338
+ "../cli/ai/lib/types.js"() {
29339
+ "use strict";
29340
+ (function(VersionBump4) {
29341
+ VersionBump4["MAJOR"] = "MAJOR";
29342
+ VersionBump4["MINOR"] = "MINOR";
29343
+ VersionBump4["PATCH"] = "PATCH";
29344
+ VersionBump4["NO_CHANGE"] = "NO_CHANGE";
29345
+ })(VersionBump3 || (VersionBump3 = {}));
29346
+ }
29347
+ });
29348
+
29285
29349
  // ../cli/ai/lib/index.js
29286
29350
  var lib_exports = {};
29287
29351
  __export(lib_exports, {
29288
- BamlClientFinishReasonError: () => import_baml6.BamlClientFinishReasonError,
29289
- BamlClientHttpError: () => import_baml6.BamlClientHttpError,
29290
- BamlValidationError: () => import_baml6.BamlValidationError,
29291
- VersionBump: () => VersionBump2,
29292
- all_succeeded: () => all_succeeded,
29293
- b: () => b2,
29294
- configureBamlClient: () => configureBamlClient,
29295
- flush: () => flush,
29296
- get_checks: () => get_checks,
29297
- onLogEvent: () => onLogEvent,
29298
- resetBamlEnvVars: () => resetBamlEnvVars,
29299
- setTags: () => setTags,
29300
- traceAsync: () => traceAsync,
29301
- traceSync: () => traceSync,
29302
- version: () => version,
29303
- watchers: () => watchers_exports
29352
+ VersionBump: () => VersionBump3,
29353
+ loadBamlDependencies: () => loadBamlDependencies
29304
29354
  });
29305
29355
  var init_lib = __esm({
29306
29356
  "../cli/ai/lib/index.js"() {
29307
29357
  "use strict";
29308
- init_baml_client();
29309
- init_configureBamlClient();
29358
+ init_loader();
29359
+ init_types2();
29310
29360
  }
29311
29361
  });
29312
29362
 
@@ -29355,7 +29405,7 @@ async function doesPathExist(filepath, mode) {
29355
29405
  // ../commons/fs-utils/lib/resolve.js
29356
29406
  var import_path = __toESM(require("path"), 1);
29357
29407
  function resolve(...paths) {
29358
- return import_path.default.resolve(...paths.map(convertToOsPath));
29408
+ return convertToOsPath(import_path.default.resolve(...paths.map(convertToOsPath)));
29359
29409
  }
29360
29410
 
29361
29411
  // src/cli.ts
@@ -31347,7 +31397,9 @@ function newRepositoryReference({ remote, owner, repo }) {
31347
31397
  repoUrl,
31348
31398
  cloneUrl,
31349
31399
  getAuthedCloneUrl: (installationToken) => {
31350
- return cloneUrl.replace("https://", `https://x-access-token:${installationToken}@`);
31400
+ const isInstallationToken = installationToken.startsWith("ghs_") || installationToken.startsWith("ghu_");
31401
+ const userPrefix = isInstallationToken ? "x-access-token:" : "";
31402
+ return cloneUrl.replace("https://", `https://${userPrefix}${installationToken}@`);
31351
31403
  }
31352
31404
  };
31353
31405
  }
@@ -39248,7 +39300,7 @@ init_dist3();
39248
39300
  var import_child_process4 = require("child_process");
39249
39301
  var import_fs12 = require("fs");
39250
39302
  var import_path17 = require("path");
39251
- async function replayPrepare(params) {
39303
+ async function replayPrepare(params, state) {
39252
39304
  const {
39253
39305
  outputDir,
39254
39306
  cliVersion,
@@ -39259,8 +39311,36 @@ async function replayPrepare(params) {
39259
39311
  logger
39260
39312
  } = params;
39261
39313
  const lockfilePath = (0, import_path17.join)(outputDir, ".fern", "replay.lock");
39314
+ let autoBootstrapped = false;
39315
+ let bootstrapAttempted = false;
39262
39316
  if (!(0, import_fs12.existsSync)(lockfilePath)) {
39263
- return null;
39317
+ if (process.env.FERN_DISABLE_AUTO_BOOTSTRAP === "true" || process.env.FERN_DISABLE_AUTO_BOOTSTRAP === "1") {
39318
+ return null;
39319
+ }
39320
+ bootstrapAttempted = true;
39321
+ if (state) {
39322
+ state.bootstrapAttempted = true;
39323
+ }
39324
+ try {
39325
+ const bootstrapResult = await bootstrap(outputDir, {
39326
+ fernignoreAction: "skip",
39327
+ force: false,
39328
+ importHistory: false
39329
+ });
39330
+ if (bootstrapResult.generationCommit == null) {
39331
+ return null;
39332
+ }
39333
+ autoBootstrapped = true;
39334
+ } catch (error) {
39335
+ logger?.warn("Replay auto-bootstrap failed, continuing without replay: " + String(error));
39336
+ try {
39337
+ if ((0, import_fs12.existsSync)(lockfilePath)) {
39338
+ (0, import_fs12.unlinkSync)(lockfilePath);
39339
+ }
39340
+ } catch {
39341
+ }
39342
+ return null;
39343
+ }
39264
39344
  }
39265
39345
  const baseBranchHead = gitRevParse(outputDir, "HEAD");
39266
39346
  let previousGenerationSha = null;
@@ -39298,12 +39378,17 @@ async function replayPrepare(params) {
39298
39378
  `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).`
39299
39379
  );
39300
39380
  } else {
39301
- const syncService = new ReplayService(outputDir, { enabled: true });
39302
- await syncService.syncFromDivergentMerge(tagSha, {
39303
- cliVersion,
39304
- generatorVersions,
39305
- baseBranchHead: baseBranchHead ?? void 0
39306
- });
39381
+ try {
39382
+ const syncService = new ReplayService(outputDir, { enabled: true });
39383
+ await syncService.syncFromDivergentMerge(tagSha, {
39384
+ cliVersion,
39385
+ generatorVersions,
39386
+ baseBranchHead: baseBranchHead ?? void 0
39387
+ });
39388
+ } catch (error) {
39389
+ logger?.warn("Replay divergent-merge sync failed, continuing without sync: " + String(error));
39390
+ throw new ReplayPrepareError(String(error), error);
39391
+ }
39307
39392
  try {
39308
39393
  const freshLockManager = new LockfileManager(outputDir);
39309
39394
  if (freshLockManager.exists()) {
@@ -39325,8 +39410,8 @@ async function replayPrepare(params) {
39325
39410
  baseBranchHead: baseBranchHead ?? void 0
39326
39411
  });
39327
39412
  } catch (error) {
39328
- logger?.warn("Replay failed, continuing without replay: " + String(error));
39329
- return null;
39413
+ logger?.warn("Replay prepare failed, continuing without replay: " + String(error));
39414
+ throw new ReplayPrepareError(String(error), error);
39330
39415
  }
39331
39416
  return {
39332
39417
  _service: service,
@@ -39335,7 +39420,9 @@ async function replayPrepare(params) {
39335
39420
  flow: preparation.flow,
39336
39421
  previousGenerationSha,
39337
39422
  currentGenerationSha: preparation.currentGenerationSha,
39338
- baseBranchHead
39423
+ baseBranchHead,
39424
+ autoBootstrapped,
39425
+ bootstrapAttempted
39339
39426
  };
39340
39427
  }
39341
39428
  async function replayApply(prepared, params = {}) {
@@ -39344,13 +39431,16 @@ async function replayApply(prepared, params = {}) {
39344
39431
  try {
39345
39432
  report = await prepared._service.applyPreparedReplay(prepared._preparation, { stageOnly });
39346
39433
  } catch (error) {
39347
- logger?.warn("Replay failed, continuing without replay: " + String(error));
39434
+ logger?.warn("Replay apply failed, continuing without replay: " + String(error));
39348
39435
  return {
39349
39436
  report: null,
39350
39437
  fernignoreUpdated: false,
39351
39438
  previousGenerationSha: prepared.previousGenerationSha,
39352
39439
  currentGenerationSha: prepared.currentGenerationSha,
39353
- baseBranchHead: prepared.baseBranchHead
39440
+ baseBranchHead: prepared.baseBranchHead,
39441
+ autoBootstrapped: prepared.autoBootstrapped,
39442
+ bootstrapAttempted: prepared.bootstrapAttempted,
39443
+ failureReason: String(error)
39354
39444
  };
39355
39445
  }
39356
39446
  let resolvedBaseBranchHead = prepared.baseBranchHead;
@@ -39372,22 +39462,53 @@ async function replayApply(prepared, params = {}) {
39372
39462
  fernignoreUpdated,
39373
39463
  previousGenerationSha: prepared.previousGenerationSha,
39374
39464
  currentGenerationSha: prepared.currentGenerationSha,
39375
- baseBranchHead: resolvedBaseBranchHead
39465
+ baseBranchHead: resolvedBaseBranchHead,
39466
+ autoBootstrapped: prepared.autoBootstrapped,
39467
+ bootstrapAttempted: prepared.bootstrapAttempted
39376
39468
  };
39377
39469
  }
39378
39470
  async function replayRun(params) {
39379
- const prepared = await replayPrepare(params);
39471
+ const prepareState = { bootstrapAttempted: false };
39472
+ let prepared;
39473
+ try {
39474
+ prepared = await replayPrepare(params, prepareState);
39475
+ } catch (error) {
39476
+ return {
39477
+ report: null,
39478
+ fernignoreUpdated: false,
39479
+ previousGenerationSha: null,
39480
+ currentGenerationSha: null,
39481
+ baseBranchHead: null,
39482
+ autoBootstrapped: false,
39483
+ bootstrapAttempted: prepareState.bootstrapAttempted,
39484
+ failureReason: error instanceof ReplayPrepareError ? error.reason : String(error)
39485
+ };
39486
+ }
39380
39487
  if (prepared == null) {
39381
39488
  return {
39382
39489
  report: null,
39383
39490
  fernignoreUpdated: false,
39384
39491
  previousGenerationSha: null,
39385
39492
  currentGenerationSha: null,
39386
- baseBranchHead: null
39493
+ baseBranchHead: null,
39494
+ autoBootstrapped: false,
39495
+ bootstrapAttempted: prepareState.bootstrapAttempted
39387
39496
  };
39388
39497
  }
39389
39498
  return replayApply(prepared, { stageOnly: params.stageOnly, logger: params.logger });
39390
39499
  }
39500
+ var ReplayPrepareError = class extends Error {
39501
+ reason;
39502
+ constructor(reason, cause) {
39503
+ super(`Replay prepare failed: ${reason}`, { cause });
39504
+ Object.setPrototypeOf(this, new.target.prototype);
39505
+ if (Error.captureStackTrace) {
39506
+ Error.captureStackTrace(this, this.constructor);
39507
+ }
39508
+ this.name = this.constructor.name;
39509
+ this.reason = reason;
39510
+ }
39511
+ };
39391
39512
  function isTagMergedIntoHead(cwd2, tagSha) {
39392
39513
  try {
39393
39514
  (0, import_child_process4.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
@@ -39482,7 +39603,7 @@ var consolePipelineLogger = {
39482
39603
  };
39483
39604
 
39484
39605
  // src/pipeline/PostGenerationPipeline.ts
39485
- var import_child_process6 = require("child_process");
39606
+ var import_child_process7 = require("child_process");
39486
39607
 
39487
39608
  // src/pipeline/github/constants.ts
39488
39609
  var FERN_BOT_NAME2 = "fern-api";
@@ -40564,7 +40685,12 @@ var AutoVersionStep = class extends BaseStep {
40564
40685
  async handleNormalFlow(params) {
40565
40686
  const { prepared, service, language, mappedMagicVersion, previousGenerationSha } = params;
40566
40687
  const rawDiff = this.gitDiff(previousGenerationSha, prepared.currentGenerationSha);
40567
- const previousVersion = await this.resolvePreviousVersion({ service, rawDiff, mappedMagicVersion });
40688
+ const previousVersion = await this.resolvePreviousVersion({
40689
+ service,
40690
+ rawDiff,
40691
+ mappedMagicVersion,
40692
+ baseVersion: this.config.baseVersion
40693
+ });
40568
40694
  if (previousVersion == null) {
40569
40695
  return await this.handleFirstGeneration({ service, language, mappedMagicVersion });
40570
40696
  }
@@ -40701,7 +40827,11 @@ var AutoVersionStep = class extends BaseStep {
40701
40827
  };
40702
40828
  }
40703
40829
  async resolvePreviousVersion(params) {
40704
- const { service, rawDiff, mappedMagicVersion } = params;
40830
+ const { service, rawDiff, mappedMagicVersion, baseVersion } = params;
40831
+ if (baseVersion != null && isValidSemver(baseVersion)) {
40832
+ this.logger.debug(`AutoVersionStep: previous version from pipeline baseVersion: ${baseVersion}`);
40833
+ return this.normalizeVersionPrefix(baseVersion, mappedMagicVersion);
40834
+ }
40705
40835
  try {
40706
40836
  const extracted = service.extractPreviousVersion(rawDiff, mappedMagicVersion);
40707
40837
  if (extracted != null) {
@@ -40810,7 +40940,7 @@ ${newBlock}${remainder}`;
40810
40940
  return `${message.trimEnd()}${FERN_TRAILER}`;
40811
40941
  }
40812
40942
  async analyzeSingle(cleanedDiff, language, previousVersion) {
40813
- const { client, VersionBump: VersionBump3 } = await this.loadBaml();
40943
+ const { client, VersionBump: VersionBump4 } = await this.loadBaml();
40814
40944
  const result = await client.AnalyzeSdkDiff(
40815
40945
  cleanedDiff,
40816
40946
  language,
@@ -40818,7 +40948,7 @@ ${newBlock}${remainder}`;
40818
40948
  this.config.priorChangelog ?? "",
40819
40949
  this.config.specCommitMessage ?? ""
40820
40950
  );
40821
- if (result.version_bump === VersionBump3.NO_CHANGE) {
40951
+ if (result.version_bump === VersionBump4.NO_CHANGE) {
40822
40952
  return null;
40823
40953
  }
40824
40954
  return {
@@ -40829,8 +40959,8 @@ ${newBlock}${remainder}`;
40829
40959
  };
40830
40960
  }
40831
40961
  async analyzeChunks(chunks, language, previousVersion) {
40832
- const { client, VersionBump: VersionBump3 } = await this.loadBaml();
40833
- let bestBump = VersionBump3.NO_CHANGE;
40962
+ const { client, VersionBump: VersionBump4 } = await this.loadBaml();
40963
+ let bestBump = VersionBump4.NO_CHANGE;
40834
40964
  let bestMessage = "";
40835
40965
  let bestVersionBumpReason;
40836
40966
  const changelogEntries = [];
@@ -40846,7 +40976,7 @@ ${newBlock}${remainder}`;
40846
40976
  this.config.priorChangelog ?? "",
40847
40977
  this.config.specCommitMessage ?? ""
40848
40978
  );
40849
- if (analysis.version_bump === VersionBump3.NO_CHANGE) {
40979
+ if (analysis.version_bump === VersionBump4.NO_CHANGE) {
40850
40980
  continue;
40851
40981
  }
40852
40982
  const prev = bestBump;
@@ -40860,7 +40990,7 @@ ${newBlock}${remainder}`;
40860
40990
  changelogEntries.push(entry);
40861
40991
  }
40862
40992
  }
40863
- if (bestBump === VersionBump3.NO_CHANGE) {
40993
+ if (bestBump === VersionBump4.NO_CHANGE) {
40864
40994
  return null;
40865
40995
  }
40866
40996
  if (changelogEntries.length <= 1) {
@@ -40907,11 +41037,12 @@ ${newBlock}${remainder}`;
40907
41037
  if (this.config.ai == null) {
40908
41038
  throw new Error("AutoVersionStep: ai config is missing. Set autoVersion.ai to a BAML provider+model pair.");
40909
41039
  }
40910
- const cliAi = await Promise.resolve().then(() => (init_lib(), lib_exports));
40911
- const registry = cliAi.configureBamlClient(this.config.ai);
41040
+ const { loadBamlDependencies: loadBamlDependencies2, VersionBump: VersionBump4 } = await Promise.resolve().then(() => (init_lib(), lib_exports));
41041
+ const { BamlClient, configureBamlClient: configureBamlClient2 } = await loadBamlDependencies2();
41042
+ const registry = configureBamlClient2(this.config.ai);
40912
41043
  return {
40913
- client: cliAi.b.withOptions({ clientRegistry: registry }),
40914
- VersionBump: cliAi.VersionBump
41044
+ client: BamlClient.withOptions({ clientRegistry: registry }),
41045
+ VersionBump: VersionBump4
40915
41046
  };
40916
41047
  }
40917
41048
  /**
@@ -40938,6 +41069,7 @@ ${newBlock}${remainder}`;
40938
41069
  };
40939
41070
 
40940
41071
  // src/pipeline/steps/GenerationCommitStep.ts
41072
+ var import_child_process6 = require("child_process");
40941
41073
  var GenerationCommitStep = class extends BaseStep {
40942
41074
  constructor(outputDir, logger, config, cliVersion, generatorVersions, generatorName) {
40943
41075
  super(outputDir, logger);
@@ -40952,19 +41084,46 @@ var GenerationCommitStep = class extends BaseStep {
40952
41084
  generatorName;
40953
41085
  name = "generationCommit";
40954
41086
  async execute(_context) {
40955
- const prepared = await replayPrepare({
40956
- outputDir: this.outputDir,
40957
- cliVersion: this.cliVersion,
40958
- generatorVersions: this.generatorVersions,
40959
- generatorName: this.generatorName,
40960
- skipApplication: this.config.skipApplication,
40961
- logger: this.logger
40962
- });
41087
+ const headBeforePrepare = tryRevParse(this.outputDir, "HEAD");
41088
+ const prepareState = { bootstrapAttempted: false };
41089
+ let prepared;
41090
+ try {
41091
+ prepared = await replayPrepare(
41092
+ {
41093
+ outputDir: this.outputDir,
41094
+ cliVersion: this.cliVersion,
41095
+ generatorVersions: this.generatorVersions,
41096
+ generatorName: this.generatorName,
41097
+ skipApplication: this.config.skipApplication,
41098
+ logger: this.logger
41099
+ },
41100
+ prepareState
41101
+ );
41102
+ } catch (error) {
41103
+ const reason = error instanceof ReplayPrepareError ? error.reason : String(error);
41104
+ if (headBeforePrepare != null) {
41105
+ try {
41106
+ (0, import_child_process6.execFileSync)("git", ["reset", "--hard", headBeforePrepare], {
41107
+ cwd: this.outputDir,
41108
+ stdio: "pipe"
41109
+ });
41110
+ } catch {
41111
+ }
41112
+ }
41113
+ return {
41114
+ executed: true,
41115
+ success: true,
41116
+ errorMessage: reason,
41117
+ preparedReplay: null,
41118
+ bootstrapAttempted: prepareState.bootstrapAttempted
41119
+ };
41120
+ }
40963
41121
  if (prepared == null) {
40964
41122
  return {
40965
41123
  executed: true,
40966
41124
  success: true,
40967
- preparedReplay: null
41125
+ preparedReplay: null,
41126
+ bootstrapAttempted: prepareState.bootstrapAttempted
40968
41127
  };
40969
41128
  }
40970
41129
  return {
@@ -40974,10 +41133,22 @@ var GenerationCommitStep = class extends BaseStep {
40974
41133
  previousGenerationSha: prepared.previousGenerationSha ?? void 0,
40975
41134
  currentGenerationSha: prepared.currentGenerationSha,
40976
41135
  baseBranchHead: prepared.baseBranchHead ?? void 0,
40977
- flow: prepared.flow
41136
+ flow: prepared.flow,
41137
+ bootstrapAttempted: prepareState.bootstrapAttempted
40978
41138
  };
40979
41139
  }
40980
41140
  };
41141
+ function tryRevParse(cwd2, rev) {
41142
+ try {
41143
+ return (0, import_child_process6.execFileSync)("git", ["rev-parse", "--verify", rev], {
41144
+ cwd: cwd2,
41145
+ encoding: "utf-8",
41146
+ stdio: "pipe"
41147
+ }).trim();
41148
+ } catch {
41149
+ return null;
41150
+ }
41151
+ }
40981
41152
 
40982
41153
  // src/pipeline/steps/GithubStep.ts
40983
41154
  var import_promises14 = require("fs/promises");
@@ -41708,10 +41879,26 @@ var ReplayStep = class extends BaseStep {
41708
41879
  async execute(context) {
41709
41880
  const generationCommit = context.previousStepResults.generationCommit;
41710
41881
  const prepared = generationCommit?.preparedReplay;
41882
+ if (generationCommit != null && generationCommit.errorMessage != null && prepared == null) {
41883
+ return {
41884
+ executed: true,
41885
+ success: true,
41886
+ replayCrashed: true,
41887
+ errorMessage: generationCommit.errorMessage,
41888
+ autoBootstrapped: false,
41889
+ bootstrapAttempted: generationCommit.bootstrapAttempted === true,
41890
+ flow: "normal-regeneration",
41891
+ patchesDetected: 0,
41892
+ patchesApplied: 0,
41893
+ patchesWithConflicts: 0
41894
+ };
41895
+ }
41711
41896
  if (generationCommit != null && prepared == null) {
41712
41897
  return {
41713
41898
  executed: true,
41714
41899
  success: true,
41900
+ autoBootstrapped: false,
41901
+ bootstrapAttempted: generationCommit.bootstrapAttempted === true,
41715
41902
  flow: "first-generation",
41716
41903
  patchesDetected: 0,
41717
41904
  patchesApplied: 0,
@@ -41730,6 +41917,23 @@ var ReplayStep = class extends BaseStep {
41730
41917
  skipApplication: this.config.skipApplication,
41731
41918
  logger: this.logger
41732
41919
  });
41920
+ if (result.failureReason != null) {
41921
+ return {
41922
+ executed: true,
41923
+ success: true,
41924
+ replayCrashed: true,
41925
+ errorMessage: result.failureReason,
41926
+ previousGenerationSha: result.previousGenerationSha ?? void 0,
41927
+ currentGenerationSha: result.currentGenerationSha ?? void 0,
41928
+ baseBranchHead: result.baseBranchHead ?? void 0,
41929
+ autoBootstrapped: result.autoBootstrapped,
41930
+ bootstrapAttempted: result.bootstrapAttempted,
41931
+ flow: "normal-regeneration",
41932
+ patchesDetected: 0,
41933
+ patchesApplied: 0,
41934
+ patchesWithConflicts: 0
41935
+ };
41936
+ }
41733
41937
  if (result.report == null) {
41734
41938
  return {
41735
41939
  executed: true,
@@ -41737,6 +41941,8 @@ var ReplayStep = class extends BaseStep {
41737
41941
  previousGenerationSha: result.previousGenerationSha ?? void 0,
41738
41942
  currentGenerationSha: result.currentGenerationSha ?? void 0,
41739
41943
  baseBranchHead: result.baseBranchHead ?? void 0,
41944
+ autoBootstrapped: result.autoBootstrapped,
41945
+ bootstrapAttempted: result.bootstrapAttempted,
41740
41946
  flow: "first-generation",
41741
41947
  patchesDetected: 0,
41742
41948
  patchesApplied: 0,
@@ -41750,6 +41956,8 @@ var ReplayStep = class extends BaseStep {
41750
41956
  previousGenerationSha: result.previousGenerationSha ?? void 0,
41751
41957
  currentGenerationSha: result.currentGenerationSha ?? void 0,
41752
41958
  baseBranchHead: result.baseBranchHead ?? void 0,
41959
+ autoBootstrapped: result.autoBootstrapped,
41960
+ bootstrapAttempted: result.bootstrapAttempted,
41753
41961
  flow: report.flow,
41754
41962
  patchesDetected: report.patchesDetected,
41755
41963
  patchesApplied: report.patchesApplied,
@@ -41758,6 +41966,11 @@ var ReplayStep = class extends BaseStep {
41758
41966
  patchesRepointed: report.patchesRepointed,
41759
41967
  patchesContentRebased: report.patchesContentRebased,
41760
41968
  patchesKeptAsUserOwned: report.patchesKeptAsUserOwned,
41969
+ patchesSkipped: report.patchesSkipped,
41970
+ patchesPartiallyApplied: report.patchesPartiallyApplied,
41971
+ patchesConflictResolved: report.patchesConflictResolved,
41972
+ patchesReverted: report.patchesReverted,
41973
+ patchesRefreshed: report.patchesRefreshed,
41761
41974
  unresolvedPatches: report.unresolvedPatches?.map((info) => ({
41762
41975
  patchId: info.patchId,
41763
41976
  patchMessage: info.patchMessage,
@@ -41826,8 +42039,8 @@ var PostGenerationPipeline = class {
41826
42039
  async run() {
41827
42040
  if (this.config.github?.enabled) {
41828
42041
  try {
41829
- (0, import_child_process6.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
41830
- (0, import_child_process6.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
42042
+ (0, import_child_process7.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
42043
+ (0, import_child_process7.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
41831
42044
  } catch {
41832
42045
  }
41833
42046
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.9.22",
3
+ "version": "0.9.24",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fern-api/fern.git",