@fern-api/generator-cli 0.6.10 → 0.6.14

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 (4) hide show
  1. package/dist/api.d.ts +21 -19
  2. package/dist/api.js +282 -480
  3. package/dist/cli.js +444 -455
  4. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -7678,7 +7678,7 @@ var require_dist2 = __commonJS({
7678
7678
  }
7679
7679
  });
7680
7680
 
7681
- // ../../node_modules/.pnpm/simple-git@3.30.0/node_modules/simple-git/dist/esm/index.js
7681
+ // ../../node_modules/.pnpm/simple-git@3.33.0/node_modules/simple-git/dist/esm/index.js
7682
7682
  function pathspec(...paths) {
7683
7683
  const key = new String(paths);
7684
7684
  cache.set(key, paths);
@@ -8778,15 +8778,15 @@ function parser3(indexX, indexY, handler2) {
8778
8778
  return [`${indexX}${indexY}`, handler2];
8779
8779
  }
8780
8780
  function conflicts(indexX, ...indexY) {
8781
- return indexY.map((y) => parser3(indexX, y, (result, file) => append(result.conflicted, file)));
8781
+ return indexY.map((y) => parser3(indexX, y, (result, file) => result.conflicted.push(file)));
8782
8782
  }
8783
8783
  function splitLine(result, lineStr) {
8784
8784
  const trimmed2 = lineStr.trim();
8785
8785
  switch (" ") {
8786
8786
  case trimmed2.charAt(2):
8787
- return data(trimmed2.charAt(0), trimmed2.charAt(1), trimmed2.substr(3));
8787
+ return data(trimmed2.charAt(0), trimmed2.charAt(1), trimmed2.slice(3));
8788
8788
  case trimmed2.charAt(1):
8789
- return data(" ", trimmed2.charAt(0), trimmed2.substr(2));
8789
+ return data(" ", trimmed2.charAt(0), trimmed2.slice(2));
8790
8790
  default:
8791
8791
  return;
8792
8792
  }
@@ -8863,6 +8863,28 @@ function versionParser(stdOut) {
8863
8863
  }
8864
8864
  return parseStringResponse(versionResponse(0, 0, 0, stdOut), parsers7, stdOut);
8865
8865
  }
8866
+ function createCloneTask(api, task, repoPath, ...args) {
8867
+ if (!filterString(repoPath)) {
8868
+ return configurationErrorTask(`git.${api}() requires a string 'repoPath'`);
8869
+ }
8870
+ return task(repoPath, filterType(args[0], filterString), getTrailingOptions(arguments));
8871
+ }
8872
+ function clone_default() {
8873
+ return {
8874
+ clone(repo, ...rest) {
8875
+ return this._runTask(
8876
+ createCloneTask("clone", cloneTask, filterType(repo, filterString), ...rest),
8877
+ trailingFunctionArgument(arguments)
8878
+ );
8879
+ },
8880
+ mirror(repo, ...rest) {
8881
+ return this._runTask(
8882
+ createCloneTask("mirror", cloneMirrorTask, filterType(repo, filterString), ...rest),
8883
+ trailingFunctionArgument(arguments)
8884
+ );
8885
+ }
8886
+ };
8887
+ }
8866
8888
  function applyPatchTask(patches, customArgs) {
8867
8889
  return straightThroughStringTask(["apply", ...customArgs, ...patches]);
8868
8890
  }
@@ -8972,23 +8994,6 @@ function checkIgnoreTask(paths) {
8972
8994
  parser: parseCheckIgnore
8973
8995
  };
8974
8996
  }
8975
- function disallowedCommand(command) {
8976
- return /^--upload-pack(=|$)/.test(command);
8977
- }
8978
- function cloneTask(repo, directory, customArgs) {
8979
- const commands = ["clone", ...customArgs];
8980
- filterString(repo) && commands.push(repo);
8981
- filterString(directory) && commands.push(directory);
8982
- const banned = commands.find(disallowedCommand);
8983
- if (banned) {
8984
- return configurationErrorTask(`git.fetch: potential exploit argument blocked.`);
8985
- }
8986
- return straightThroughStringTask(commands);
8987
- }
8988
- function cloneMirrorTask(repo, directory, customArgs) {
8989
- append(customArgs, "--mirror");
8990
- return cloneTask(repo, directory, customArgs);
8991
- }
8992
8997
  function parseFetchResult(stdOut, stdErr) {
8993
8998
  const result = {
8994
8999
  raw: stdOut,
@@ -9000,7 +9005,7 @@ function parseFetchResult(stdOut, stdErr) {
9000
9005
  };
9001
9006
  return parseStringResponse(result, parsers10, [stdOut, stdErr]);
9002
9007
  }
9003
- function disallowedCommand2(command) {
9008
+ function disallowedCommand(command) {
9004
9009
  return /^--upload-pack(=|$)/.test(command);
9005
9010
  }
9006
9011
  function fetchTask(remote, branch, customArgs) {
@@ -9008,7 +9013,7 @@ function fetchTask(remote, branch, customArgs) {
9008
9013
  if (remote && branch) {
9009
9014
  commands.push(remote, branch);
9010
9015
  }
9011
- const banned = commands.find(disallowedCommand2);
9016
+ const banned = commands.find(disallowedCommand);
9012
9017
  if (banned) {
9013
9018
  return configurationErrorTask(`git.fetch: potential exploit argument blocked.`);
9014
9019
  }
@@ -9210,18 +9215,24 @@ function abortPlugin(signal) {
9210
9215
  function isConfigSwitch(arg) {
9211
9216
  return typeof arg === "string" && arg.trim().toLowerCase() === "-c";
9212
9217
  }
9213
- function preventProtocolOverride(arg, next) {
9214
- if (!isConfigSwitch(arg)) {
9215
- return;
9216
- }
9217
- if (!/^\s*protocol(.[a-z]+)?.allow/.test(next)) {
9218
- return;
9218
+ function isCloneUploadPackSwitch(char, arg) {
9219
+ if (typeof arg !== "string" || !arg.includes(char)) {
9220
+ return false;
9219
9221
  }
9220
- throw new GitPluginError(
9221
- void 0,
9222
- "unsafe",
9223
- "Configuring protocol.allow is not permitted without enabling allowUnsafeExtProtocol"
9224
- );
9222
+ const cleaned = arg.trim().replace(/\0/g, "");
9223
+ return /^(--no)?-{1,2}[\dlsqvnobucj]+(\s|$)/.test(cleaned);
9224
+ }
9225
+ function preventConfigBuilder(config, setting, message = String(config)) {
9226
+ const regex = typeof config === "string" ? new RegExp(`\\s*${config}`, "i") : config;
9227
+ return function preventCommand(options, arg, next) {
9228
+ if (options[setting] !== true && isConfigSwitch(arg) && regex.test(next)) {
9229
+ throw new GitPluginError(
9230
+ void 0,
9231
+ "unsafe",
9232
+ `Configuring ${message} is not permitted without enabling ${setting}`
9233
+ );
9234
+ }
9235
+ };
9225
9236
  }
9226
9237
  function preventUploadPack(arg, method) {
9227
9238
  if (/^\s*--(upload|receive)-pack/.test(arg)) {
@@ -9231,7 +9242,7 @@ function preventUploadPack(arg, method) {
9231
9242
  `Use of --upload-pack or --receive-pack is not permitted without enabling allowUnsafePack`
9232
9243
  );
9233
9244
  }
9234
- if (method === "clone" && /^\s*-u\b/.test(arg)) {
9245
+ if (method === "clone" && isCloneUploadPackSwitch("u", arg)) {
9235
9246
  throw new GitPluginError(
9236
9247
  void 0,
9237
9248
  "unsafe",
@@ -9247,16 +9258,16 @@ function preventUploadPack(arg, method) {
9247
9258
  }
9248
9259
  }
9249
9260
  function blockUnsafeOperationsPlugin({
9250
- allowUnsafeProtocolOverride = false,
9251
- allowUnsafePack = false
9261
+ allowUnsafePack = false,
9262
+ ...options
9252
9263
  } = {}) {
9253
9264
  return {
9254
9265
  type: "spawn.args",
9255
9266
  action(args, context) {
9256
9267
  args.forEach((current, index) => {
9257
9268
  const next = index < args.length ? args[index + 1] : "";
9258
- allowUnsafeProtocolOverride || preventProtocolOverride(current, next);
9259
9269
  allowUnsafePack || preventUploadPack(current, context.method);
9270
+ preventUnsafeConfig.forEach((helper) => helper(options, current, next));
9260
9271
  });
9261
9272
  return args;
9262
9273
  }
@@ -9334,7 +9345,7 @@ function completionDetectionPlugin({
9334
9345
  };
9335
9346
  }
9336
9347
  function isBadArgument(arg) {
9337
- return !arg || !/^([a-z]:)?([a-z0-9/.\\_-]+)$/i.test(arg);
9348
+ return !arg || !/^([a-z]:)?([a-z0-9/.\\_~-]+)$/i.test(arg);
9338
9349
  }
9339
9350
  function toBinaryConfig(input, allowUnsafe) {
9340
9351
  if (input.length < 1 || input.length > 2) {
@@ -9522,20 +9533,20 @@ function gitInstanceFactory(baseDir, options) {
9522
9533
  plugins.add(commandConfigPrefixingPlugin(config.config));
9523
9534
  }
9524
9535
  plugins.add(blockUnsafeOperationsPlugin(config.unsafe));
9525
- plugins.add(suffixPathsPlugin());
9526
9536
  plugins.add(completionDetectionPlugin(config.completion));
9527
9537
  config.abort && plugins.add(abortPlugin(config.abort));
9528
9538
  config.progress && plugins.add(progressMonitorPlugin(config.progress));
9529
9539
  config.timeout && plugins.add(timeoutPlugin(config.timeout));
9530
9540
  config.spawnOptions && plugins.add(spawnOptionsPlugin(config.spawnOptions));
9541
+ plugins.add(suffixPathsPlugin());
9531
9542
  plugins.add(errorDetectionPlugin(errorDetectionHandler(true)));
9532
9543
  config.errors && plugins.add(errorDetectionPlugin(config.errors));
9533
9544
  customBinaryPlugin(plugins, config.binary, config.unsafe?.allowUnsafeCustomBinary);
9534
9545
  return new Git(config, plugins);
9535
9546
  }
9536
- var import_node_buffer, import_file_exists, import_debug, import_child_process, import_promise_deferred, import_node_path, import_promise_deferred2, import_node_events, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __hasOwnProp2, __esm2, __commonJS2, __export2, __copyProps2, __toCommonJS, cache, init_pathspec, GitError, init_git_error, GitResponseError, init_git_response_error, TaskConfigurationError, init_task_configuration_error, NULL, NOOP, objectToString, init_util, filterArray, filterNumber, filterString, filterStringOrStringArray, filterHasLength, init_argument_filters, ExitCodes, init_exit_codes, GitOutputStreams, init_git_output_streams, LineParser, RemoteLineParser, init_line_parser, defaultOptions, init_simple_git_options, init_task_options, init_task_parser, utils_exports, init_utils, check_is_repo_exports, CheckRepoActions, onError, parser2, init_check_is_repo, CleanResponse, removalRegexp, dryRunRemovalRegexp, isFolderRegexp, init_CleanSummary, task_exports, EMPTY_COMMANDS, init_task, clean_exports, CONFIG_ERROR_INTERACTIVE_MODE, CONFIG_ERROR_MODE_REQUIRED, CONFIG_ERROR_UNKNOWN_OPTION, CleanOptions, CleanOptionValues, init_clean, ConfigList, init_ConfigList, GitConfigScope, init_config, DiffNameStatus, diffNameStatus, init_diff_name_status, disallowedOptions, Query, _a3, GrepQuery, init_grep, reset_exports, ResetMode, validResetModes, init_reset, init_git_logger, TasksPendingQueue, init_tasks_pending_queue, GitExecutorChain, init_git_executor_chain, git_executor_exports, GitExecutor, init_git_executor, init_task_callback, init_change_working_directory, init_checkout, parser22, init_count_objects, parsers, init_parse_commit, init_commit, init_first_commit, init_hash_object, InitSummary, initResponseRegex, reInitResponseRegex, init_InitSummary, bareCommand, init_init, logFormatRegex, init_log_format, DiffSummary, init_DiffSummary, statParser, numStatParser, nameOnlyParser, nameStatusParser, diffSummaryParsers, init_parse_diff_summary, START_BOUNDARY, COMMIT_BOUNDARY, SPLITTER, defaultFieldNames, init_parse_list_log_summary, diff_exports, init_diff, excludeOptions, init_log, MergeSummaryConflict, MergeSummaryDetail, init_MergeSummary, PullSummary, PullFailedSummary, init_PullSummary, remoteMessagesObjectParsers, init_parse_remote_objects, parsers2, RemoteMessageSummary, init_parse_remote_messages, FILE_UPDATE_REGEX, SUMMARY_REGEX, ACTION_REGEX, parsers3, errorParsers, parsePullDetail, parsePullResult, init_parse_pull, parsers4, parseMergeResult, parseMergeDetail, init_parse_merge, init_merge, parsers5, parsePushResult, parsePushDetail, init_parse_push, push_exports, init_push, init_show, fromPathRegex, FileStatusSummary, init_FileStatusSummary, StatusSummary, parsers6, parseStatusSummary, init_StatusSummary, ignoredOptions, init_status, NOT_INSTALLED, parsers7, init_version, simple_git_api_exports, SimpleGitApi, init_simple_git_api, scheduler_exports, createScheduledTask, Scheduler, init_scheduler, apply_patch_exports, init_apply_patch, BranchDeletionBatch, init_BranchDeleteSummary, deleteSuccessRegex, deleteErrorRegex, parsers8, parseBranchDeletions, init_parse_branch_delete, BranchSummaryResult, init_BranchSummary, parsers9, currentBranchParser, init_parse_branch, branch_exports, init_branch, parseCheckIgnore, init_CheckIgnore, check_ignore_exports, init_check_ignore, clone_exports, init_clone, parsers10, init_parse_fetch, fetch_exports, init_fetch, parsers11, init_parse_move, move_exports, init_move, pull_exports, init_pull, init_GetRemoteSummary, remote_exports, init_remote, stash_list_exports, init_stash_list, sub_module_exports, init_sub_module, TagList, parseTagList, init_TagList, tag_exports, init_tag, require_git, GitConstructError, GitPluginError, never, WRONG_NUMBER_ERR, WRONG_CHARS_ERR, PluginStore, Git, simpleGit;
9547
+ var import_node_buffer, import_file_exists, import_debug, import_child_process, import_promise_deferred, import_node_path, import_promise_deferred2, import_node_events, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __hasOwnProp2, __esm2, __commonJS2, __export2, __copyProps2, __toCommonJS, cache, init_pathspec, GitError, init_git_error, GitResponseError, init_git_response_error, TaskConfigurationError, init_task_configuration_error, NULL, NOOP, objectToString, init_util, filterArray, filterNumber, filterString, filterStringOrStringArray, filterHasLength, init_argument_filters, ExitCodes, init_exit_codes, GitOutputStreams, init_git_output_streams, LineParser, RemoteLineParser, init_line_parser, defaultOptions, init_simple_git_options, init_task_options, init_task_parser, utils_exports, init_utils, check_is_repo_exports, CheckRepoActions, onError, parser2, init_check_is_repo, CleanResponse, removalRegexp, dryRunRemovalRegexp, isFolderRegexp, init_CleanSummary, task_exports, EMPTY_COMMANDS, init_task, clean_exports, CONFIG_ERROR_INTERACTIVE_MODE, CONFIG_ERROR_MODE_REQUIRED, CONFIG_ERROR_UNKNOWN_OPTION, CleanOptions, CleanOptionValues, init_clean, ConfigList, init_ConfigList, GitConfigScope, init_config, DiffNameStatus, diffNameStatus, init_diff_name_status, disallowedOptions, Query, _a3, GrepQuery, init_grep, reset_exports, ResetMode, validResetModes, init_reset, init_git_logger, TasksPendingQueue, init_tasks_pending_queue, GitExecutorChain, init_git_executor_chain, git_executor_exports, GitExecutor, init_git_executor, init_task_callback, init_change_working_directory, init_checkout, parser22, init_count_objects, parsers, init_parse_commit, init_commit, init_first_commit, init_hash_object, InitSummary, initResponseRegex, reInitResponseRegex, init_InitSummary, bareCommand, init_init, logFormatRegex, init_log_format, DiffSummary, init_DiffSummary, statParser, numStatParser, nameOnlyParser, nameStatusParser, diffSummaryParsers, init_parse_diff_summary, START_BOUNDARY, COMMIT_BOUNDARY, SPLITTER, defaultFieldNames, init_parse_list_log_summary, diff_exports, init_diff, excludeOptions, init_log, MergeSummaryConflict, MergeSummaryDetail, init_MergeSummary, PullSummary, PullFailedSummary, init_PullSummary, remoteMessagesObjectParsers, init_parse_remote_objects, parsers2, RemoteMessageSummary, init_parse_remote_messages, FILE_UPDATE_REGEX, SUMMARY_REGEX, ACTION_REGEX, parsers3, errorParsers, parsePullDetail, parsePullResult, init_parse_pull, parsers4, parseMergeResult, parseMergeDetail, init_parse_merge, init_merge, parsers5, parsePushResult, parsePushDetail, init_parse_push, push_exports, init_push, init_show, fromPathRegex, FileStatusSummary, init_FileStatusSummary, StatusSummary, parsers6, parseStatusSummary, init_StatusSummary, ignoredOptions, init_status, NOT_INSTALLED, parsers7, init_version, cloneTask, cloneMirrorTask, init_clone, simple_git_api_exports, SimpleGitApi, init_simple_git_api, scheduler_exports, createScheduledTask, Scheduler, init_scheduler, apply_patch_exports, init_apply_patch, BranchDeletionBatch, init_BranchDeleteSummary, deleteSuccessRegex, deleteErrorRegex, parsers8, parseBranchDeletions, init_parse_branch_delete, BranchSummaryResult, init_BranchSummary, parsers9, currentBranchParser, init_parse_branch, branch_exports, init_branch, parseCheckIgnore, init_CheckIgnore, check_ignore_exports, init_check_ignore, parsers10, init_parse_fetch, fetch_exports, init_fetch, parsers11, init_parse_move, move_exports, init_move, pull_exports, init_pull, init_GetRemoteSummary, remote_exports, init_remote, stash_list_exports, init_stash_list, sub_module_exports, init_sub_module, TagList, parseTagList, init_TagList, tag_exports, init_tag, require_git, GitConstructError, GitPluginError, preventUnsafeConfig, never, WRONG_NUMBER_ERR, WRONG_CHARS_ERR, PluginStore, Git, simpleGit;
9537
9548
  var init_esm4 = __esm({
9538
- "../../node_modules/.pnpm/simple-git@3.30.0/node_modules/simple-git/dist/esm/index.js"() {
9549
+ "../../node_modules/.pnpm/simple-git@3.33.0/node_modules/simple-git/dist/esm/index.js"() {
9539
9550
  "use strict";
9540
9551
  import_node_buffer = require("buffer");
9541
9552
  import_file_exists = __toESM(require_dist(), 1);
@@ -9631,7 +9642,7 @@ var init_esm4 = __esm({
9631
9642
  return typeof input === "number";
9632
9643
  };
9633
9644
  filterString = (input) => {
9634
- return typeof input === "string";
9645
+ return typeof input === "string" || isPathSpec(input);
9635
9646
  };
9636
9647
  filterStringOrStringArray = (input) => {
9637
9648
  return filterString(input) || Array.isArray(input) && input.every(filterString);
@@ -11010,58 +11021,54 @@ var init_esm4 = __esm({
11010
11021
  parser3(
11011
11022
  " ",
11012
11023
  "A",
11013
- (result, file) => append(result.created, file)
11014
- ),
11015
- parser3(
11016
- " ",
11017
- "D",
11018
- (result, file) => append(result.deleted, file)
11019
- ),
11020
- parser3(
11021
- " ",
11022
- "M",
11023
- (result, file) => append(result.modified, file)
11024
+ (result, file) => result.created.push(file)
11024
11025
  ),
11025
11026
  parser3(
11026
- "A",
11027
11027
  " ",
11028
- (result, file) => append(result.created, file) && append(result.staged, file)
11029
- ),
11030
- parser3(
11031
- "A",
11032
- "M",
11033
- (result, file) => append(result.created, file) && append(result.staged, file) && append(result.modified, file)
11034
- ),
11035
- parser3(
11036
11028
  "D",
11037
- " ",
11038
- (result, file) => append(result.deleted, file) && append(result.staged, file)
11029
+ (result, file) => result.deleted.push(file)
11039
11030
  ),
11040
11031
  parser3(
11041
- "M",
11042
11032
  " ",
11043
- (result, file) => append(result.modified, file) && append(result.staged, file)
11044
- ),
11045
- parser3(
11046
11033
  "M",
11047
- "M",
11048
- (result, file) => append(result.modified, file) && append(result.staged, file)
11034
+ (result, file) => result.modified.push(file)
11049
11035
  ),
11036
+ parser3("A", " ", (result, file) => {
11037
+ result.created.push(file);
11038
+ result.staged.push(file);
11039
+ }),
11040
+ parser3("A", "M", (result, file) => {
11041
+ result.created.push(file);
11042
+ result.staged.push(file);
11043
+ result.modified.push(file);
11044
+ }),
11045
+ parser3("D", " ", (result, file) => {
11046
+ result.deleted.push(file);
11047
+ result.staged.push(file);
11048
+ }),
11049
+ parser3("M", " ", (result, file) => {
11050
+ result.modified.push(file);
11051
+ result.staged.push(file);
11052
+ }),
11053
+ parser3("M", "M", (result, file) => {
11054
+ result.modified.push(file);
11055
+ result.staged.push(file);
11056
+ }),
11050
11057
  parser3("R", " ", (result, file) => {
11051
- append(result.renamed, renamedFile(file));
11058
+ result.renamed.push(renamedFile(file));
11052
11059
  }),
11053
11060
  parser3("R", "M", (result, file) => {
11054
11061
  const renamed = renamedFile(file);
11055
- append(result.renamed, renamed);
11056
- append(result.modified, renamed.to);
11062
+ result.renamed.push(renamed);
11063
+ result.modified.push(renamed.to);
11057
11064
  }),
11058
11065
  parser3("!", "!", (_result, _file) => {
11059
- append(_result.ignored = _result.ignored || [], _file);
11066
+ (_result.ignored = _result.ignored || []).push(_file);
11060
11067
  }),
11061
11068
  parser3(
11062
11069
  "?",
11063
11070
  "?",
11064
- (result, file) => append(result.not_added, file)
11071
+ (result, file) => result.not_added.push(file)
11065
11072
  ),
11066
11073
  ...conflicts(
11067
11074
  "A",
@@ -11154,6 +11161,24 @@ var init_esm4 = __esm({
11154
11161
  ];
11155
11162
  }
11156
11163
  });
11164
+ init_clone = __esm2({
11165
+ "src/lib/tasks/clone.ts"() {
11166
+ "use strict";
11167
+ init_task();
11168
+ init_utils();
11169
+ init_pathspec();
11170
+ cloneTask = (repo, directory, customArgs) => {
11171
+ const commands = ["clone", ...customArgs];
11172
+ filterString(repo) && commands.push(pathspec(repo));
11173
+ filterString(directory) && commands.push(pathspec(directory));
11174
+ return straightThroughStringTask(commands);
11175
+ };
11176
+ cloneMirrorTask = (repo, directory, customArgs) => {
11177
+ append(customArgs, "--mirror");
11178
+ return cloneTask(repo, directory, customArgs);
11179
+ };
11180
+ }
11181
+ });
11157
11182
  simple_git_api_exports = {};
11158
11183
  __export2(simple_git_api_exports, {
11159
11184
  SimpleGitApi: () => SimpleGitApi
@@ -11179,6 +11204,7 @@ var init_esm4 = __esm({
11179
11204
  init_task();
11180
11205
  init_version();
11181
11206
  init_utils();
11207
+ init_clone();
11182
11208
  SimpleGitApi = class {
11183
11209
  constructor(_executor) {
11184
11210
  this._executor = _executor;
@@ -11281,6 +11307,7 @@ var init_esm4 = __esm({
11281
11307
  Object.assign(
11282
11308
  SimpleGitApi.prototype,
11283
11309
  checkout_default(),
11310
+ clone_default(),
11284
11311
  commit_default(),
11285
11312
  config_default(),
11286
11313
  count_objects_default(),
@@ -11484,18 +11511,6 @@ var init_esm4 = __esm({
11484
11511
  init_CheckIgnore();
11485
11512
  }
11486
11513
  });
11487
- clone_exports = {};
11488
- __export2(clone_exports, {
11489
- cloneMirrorTask: () => cloneMirrorTask,
11490
- cloneTask: () => cloneTask
11491
- });
11492
- init_clone = __esm2({
11493
- "src/lib/tasks/clone.ts"() {
11494
- "use strict";
11495
- init_task();
11496
- init_utils();
11497
- }
11498
- });
11499
11514
  init_parse_fetch = __esm2({
11500
11515
  "src/lib/parsers/parse-fetch.ts"() {
11501
11516
  "use strict";
@@ -11677,7 +11692,7 @@ var init_esm4 = __esm({
11677
11692
  var { GitExecutor: GitExecutor2 } = (init_git_executor(), __toCommonJS(git_executor_exports));
11678
11693
  var { SimpleGitApi: SimpleGitApi2 } = (init_simple_git_api(), __toCommonJS(simple_git_api_exports));
11679
11694
  var { Scheduler: Scheduler2 } = (init_scheduler(), __toCommonJS(scheduler_exports));
11680
- var { configurationErrorTask: configurationErrorTask2 } = (init_task(), __toCommonJS(task_exports));
11695
+ var { adhocExecTask: adhocExecTask2, configurationErrorTask: configurationErrorTask2 } = (init_task(), __toCommonJS(task_exports));
11681
11696
  var {
11682
11697
  asArray: asArray2,
11683
11698
  filterArray: filterArray2,
@@ -11698,7 +11713,6 @@ var init_esm4 = __esm({
11698
11713
  } = (init_branch(), __toCommonJS(branch_exports));
11699
11714
  var { checkIgnoreTask: checkIgnoreTask2 } = (init_check_ignore(), __toCommonJS(check_ignore_exports));
11700
11715
  var { checkIsRepoTask: checkIsRepoTask2 } = (init_check_is_repo(), __toCommonJS(check_is_repo_exports));
11701
- var { cloneTask: cloneTask2, cloneMirrorTask: cloneMirrorTask2 } = (init_clone(), __toCommonJS(clone_exports));
11702
11716
  var { cleanWithOptionsTask: cleanWithOptionsTask2, isCleanOptionsArray: isCleanOptionsArray2 } = (init_clean(), __toCommonJS(clean_exports));
11703
11717
  var { diffSummaryTask: diffSummaryTask2 } = (init_diff(), __toCommonJS(diff_exports));
11704
11718
  var { fetchTask: fetchTask2 } = (init_fetch(), __toCommonJS(fetch_exports));
@@ -11753,24 +11767,6 @@ var init_esm4 = __esm({
11753
11767
  trailingFunctionArgument2(arguments)
11754
11768
  );
11755
11769
  };
11756
- function createCloneTask(api, task, repoPath, localPath) {
11757
- if (typeof repoPath !== "string") {
11758
- return configurationErrorTask2(`git.${api}() requires a string 'repoPath'`);
11759
- }
11760
- return task(repoPath, filterType2(localPath, filterString2), getTrailingOptions2(arguments));
11761
- }
11762
- Git2.prototype.clone = function() {
11763
- return this._runTask(
11764
- createCloneTask("clone", cloneTask2, ...arguments),
11765
- trailingFunctionArgument2(arguments)
11766
- );
11767
- };
11768
- Git2.prototype.mirror = function() {
11769
- return this._runTask(
11770
- createCloneTask("mirror", cloneMirrorTask2, ...arguments),
11771
- trailingFunctionArgument2(arguments)
11772
- );
11773
- };
11774
11770
  Git2.prototype.mv = function(from, to) {
11775
11771
  return this._runTask(moveTask2(from, to), trailingFunctionArgument2(arguments));
11776
11772
  };
@@ -11803,10 +11799,13 @@ var init_esm4 = __esm({
11803
11799
  );
11804
11800
  };
11805
11801
  Git2.prototype.silent = function(silence) {
11806
- console.warn(
11807
- "simple-git deprecation notice: git.silent: logging should be configured using the `debug` library / `DEBUG` environment variable, this will be an error in version 3"
11802
+ return this._runTask(
11803
+ adhocExecTask2(
11804
+ () => console.warn(
11805
+ "simple-git deprecation notice: git.silent: logging should be configured using the `debug` library / `DEBUG` environment variable, this method will be removed."
11806
+ )
11807
+ )
11808
11808
  );
11809
- return this;
11810
11809
  };
11811
11810
  Git2.prototype.tags = function(options, then) {
11812
11811
  return this._runTask(
@@ -12032,7 +12031,13 @@ var init_esm4 = __esm({
12032
12031
  return this._runTask(task);
12033
12032
  };
12034
12033
  Git2.prototype.clearQueue = function() {
12035
- return this;
12034
+ return this._runTask(
12035
+ adhocExecTask2(
12036
+ () => console.warn(
12037
+ "simple-git deprecation notice: clearQueue() is deprecated and will be removed, switch to using the abortPlugin instead."
12038
+ )
12039
+ )
12040
+ );
12036
12041
  };
12037
12042
  Git2.prototype.checkIgnore = function(pathnames, then) {
12038
12043
  return this._runTask(
@@ -12075,6 +12080,17 @@ var init_esm4 = __esm({
12075
12080
  init_diff_name_status();
12076
12081
  init_grep();
12077
12082
  init_reset();
12083
+ preventUnsafeConfig = [
12084
+ preventConfigBuilder(
12085
+ /^\s*protocol(.[a-z]+)?.allow/i,
12086
+ "allowUnsafeProtocolOverride",
12087
+ "protocol.allow"
12088
+ ),
12089
+ preventConfigBuilder("core.sshCommand", "allowUnsafeSshCommand"),
12090
+ preventConfigBuilder("core.gitProxy", "allowUnsafeGitProxy"),
12091
+ preventConfigBuilder("core.hooksPath", "allowUnsafeHooksPath"),
12092
+ preventConfigBuilder("diff.external", "allowUnsafeDiffExternal")
12093
+ ];
12078
12094
  init_utils();
12079
12095
  init_utils();
12080
12096
  never = (0, import_promise_deferred2.deferred)().promise;
@@ -19568,7 +19584,7 @@ var init_diff3 = __esm({
19568
19584
  }
19569
19585
  });
19570
19586
 
19571
- // ../../node_modules/.pnpm/@fern-api+replay@0.6.2/node_modules/@fern-api/replay/dist/index.js
19587
+ // ../../node_modules/.pnpm/@fern-api+replay@0.7.0/node_modules/@fern-api/replay/dist/index.js
19572
19588
  var dist_exports = {};
19573
19589
  __export(dist_exports, {
19574
19590
  FERN_BOT_EMAIL: () => FERN_BOT_EMAIL2,
@@ -19891,17 +19907,82 @@ async function resolve7(outputDir, options) {
19891
19907
  return { success: false, reason: "no-patches" };
19892
19908
  }
19893
19909
  const git = new GitClient(outputDir);
19910
+ const unresolvedPatches = lockManager.getUnresolvedPatches();
19911
+ const resolvingPatches = lockManager.getResolvingPatches();
19912
+ if (unresolvedPatches.length > 0) {
19913
+ const applicator = new ReplayApplicator(git, lockManager, outputDir);
19914
+ await applicator.applyPatches(unresolvedPatches);
19915
+ const markerFiles = await findConflictMarkerFiles(git);
19916
+ if (markerFiles.length > 0) {
19917
+ for (const patch of unresolvedPatches) {
19918
+ lockManager.updatePatch(patch.id, { status: "resolving" });
19919
+ }
19920
+ lockManager.save();
19921
+ return {
19922
+ success: false,
19923
+ reason: "conflicts-applied",
19924
+ unresolvedFiles: markerFiles,
19925
+ phase: "applied",
19926
+ patchesApplied: unresolvedPatches.length
19927
+ };
19928
+ }
19929
+ }
19894
19930
  if (options?.checkMarkers !== false) {
19895
- const markerFiles = await git.exec(["grep", "-l", "<<<<<<<", "--", "."]).catch(() => "");
19896
- if (markerFiles.trim()) {
19897
- const files = markerFiles.trim().split("\n").filter(Boolean);
19898
- return { success: false, reason: "unresolved-conflicts", unresolvedFiles: files };
19931
+ const currentMarkerFiles = await findConflictMarkerFiles(git);
19932
+ if (currentMarkerFiles.length > 0) {
19933
+ return { success: false, reason: "unresolved-conflicts", unresolvedFiles: currentMarkerFiles };
19934
+ }
19935
+ }
19936
+ const patchesToCommit = [...resolvingPatches, ...unresolvedPatches];
19937
+ if (patchesToCommit.length > 0) {
19938
+ const currentGen = lock.current_generation;
19939
+ const detector = new ReplayDetector(git, lockManager, outputDir);
19940
+ let patchesResolved = 0;
19941
+ for (const patch of patchesToCommit) {
19942
+ const diff = await git.exec(["diff", currentGen, "--", ...patch.files]).catch(() => null);
19943
+ if (!diff || !diff.trim()) {
19944
+ lockManager.removePatch(patch.id);
19945
+ continue;
19946
+ }
19947
+ const newContentHash = detector.computeContentHash(diff);
19948
+ const changedFiles = await getChangedFiles(git, currentGen, patch.files);
19949
+ lockManager.markPatchResolved(patch.id, {
19950
+ patch_content: diff,
19951
+ content_hash: newContentHash,
19952
+ base_generation: currentGen,
19953
+ files: changedFiles
19954
+ });
19955
+ patchesResolved++;
19899
19956
  }
19957
+ lockManager.save();
19958
+ const committer2 = new ReplayCommitter(git, outputDir);
19959
+ await committer2.stageAll();
19960
+ const commitSha2 = await committer2.commitReplay(
19961
+ lock.patches.length,
19962
+ lock.patches,
19963
+ "[fern-replay] Resolved conflicts"
19964
+ );
19965
+ return {
19966
+ success: true,
19967
+ commitSha: commitSha2,
19968
+ phase: "committed",
19969
+ patchesResolved
19970
+ };
19900
19971
  }
19901
19972
  const committer = new ReplayCommitter(git, outputDir);
19902
19973
  await committer.stageAll();
19903
19974
  const commitSha = await committer.commitReplay(lock.patches.length, lock.patches);
19904
- return { success: true, commitSha };
19975
+ return { success: true, commitSha, phase: "committed" };
19976
+ }
19977
+ async function findConflictMarkerFiles(git) {
19978
+ const output = await git.exec(["grep", "-l", "<<<<<<<", "--", "."]).catch(() => "");
19979
+ return output.trim() ? output.trim().split("\n").filter(Boolean) : [];
19980
+ }
19981
+ async function getChangedFiles(git, currentGen, files) {
19982
+ const filesOutput = await git.exec(["diff", "--name-only", currentGen, "--", ...files]).catch(() => null);
19983
+ if (!filesOutput || !filesOutput.trim()) return files;
19984
+ const changed = filesOutput.trim().split("\n").filter(Boolean).filter((f) => !f.startsWith(".fern/"));
19985
+ return changed.length > 0 ? changed : files;
19905
19986
  }
19906
19987
  function status(outputDir) {
19907
19988
  const lockManager = new LockfileManager(outputDir);
@@ -19927,7 +20008,7 @@ function status(outputDir) {
19927
20008
  }
19928
20009
  var import_fs6, import_path8, import_yaml, import_crypto, import_promises4, import_os, import_path9, import_fs7, import_path10, import_crypto2, import_fs8, import_path11, import_yaml2, import_crypto3, import_fs9, import_path12, import_fs10, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, FERN_BOT_NAME2, FERN_BOT_EMAIL2, FERN_BOT_LOGIN2, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileManager, INFRASTRUCTURE_FILES, ReplayDetector, BINARY_EXTENSIONS, ReplayApplicator, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES;
19929
20010
  var init_dist = __esm({
19930
- "../../node_modules/.pnpm/@fern-api+replay@0.6.2/node_modules/@fern-api/replay/dist/index.js"() {
20011
+ "../../node_modules/.pnpm/@fern-api+replay@0.7.0/node_modules/@fern-api/replay/dist/index.js"() {
19931
20012
  "use strict";
19932
20013
  init_esm4();
19933
20014
  import_fs6 = require("fs");
@@ -20158,6 +20239,26 @@ var init_dist = __esm({
20158
20239
  this.ensureLoaded();
20159
20240
  this.lock.patches = [];
20160
20241
  }
20242
+ getUnresolvedPatches() {
20243
+ this.ensureLoaded();
20244
+ return this.lock.patches.filter((p) => p.status === "unresolved");
20245
+ }
20246
+ getResolvingPatches() {
20247
+ this.ensureLoaded();
20248
+ return this.lock.patches.filter((p) => p.status === "resolving");
20249
+ }
20250
+ markPatchUnresolved(patchId) {
20251
+ this.updatePatch(patchId, { status: "unresolved" });
20252
+ }
20253
+ markPatchResolved(patchId, updates) {
20254
+ this.ensureLoaded();
20255
+ const patch = this.lock.patches.find((p) => p.id === patchId);
20256
+ if (!patch) {
20257
+ throw new Error(`Patch not found: ${patchId}`);
20258
+ }
20259
+ delete patch.status;
20260
+ Object.assign(patch, updates);
20261
+ }
20161
20262
  getPatches() {
20162
20263
  this.ensureLoaded();
20163
20264
  return this.lock.patches;
@@ -20801,12 +20902,12 @@ CLI Version: ${options.cliVersion}`;
20801
20902
  await this.git.exec(["commit", "-m", fullMessage]);
20802
20903
  return (await this.git.exec(["rev-parse", "HEAD"])).trim();
20803
20904
  }
20804
- async commitReplay(_patchCount, patches) {
20905
+ async commitReplay(_patchCount, patches, message) {
20805
20906
  await this.stageAll();
20806
20907
  if (!await this.hasStagedChanges()) {
20807
20908
  return (await this.git.exec(["rev-parse", "HEAD"])).trim();
20808
20909
  }
20809
- let fullMessage = `[fern-replay] Applied customizations`;
20910
+ let fullMessage = message ?? `[fern-replay] Applied customizations`;
20810
20911
  if (patches && patches.length > 0) {
20811
20912
  fullMessage += "\n\nPatches replayed:";
20812
20913
  for (const patch of patches) {
@@ -20896,13 +20997,27 @@ CLI Version: ${options.cliVersion}`;
20896
20997
  this.lockManager.initializeInMemory(record2);
20897
20998
  } else {
20898
20999
  this.lockManager.read();
21000
+ const unresolvedPatches = [
21001
+ ...this.lockManager.getUnresolvedPatches(),
21002
+ ...this.lockManager.getResolvingPatches()
21003
+ ];
20899
21004
  this.lockManager.addGeneration(record2);
20900
21005
  this.lockManager.clearPatches();
21006
+ for (const patch of unresolvedPatches) {
21007
+ this.lockManager.addPatch(patch);
21008
+ }
20901
21009
  }
20902
21010
  this.lockManager.save();
20903
21011
  try {
20904
21012
  const redetectedPatches = await this.detector.detectNewPatches();
20905
21013
  if (redetectedPatches.length > 0) {
21014
+ const redetectedFiles = new Set(redetectedPatches.flatMap((p) => p.files));
21015
+ const currentPatches = this.lockManager.getPatches();
21016
+ for (const patch of currentPatches) {
21017
+ if (patch.status != null && patch.files.some((f) => redetectedFiles.has(f))) {
21018
+ this.lockManager.removePatch(patch.id);
21019
+ }
21020
+ }
20906
21021
  for (const patch of redetectedPatches) {
20907
21022
  this.lockManager.addPatch(patch);
20908
21023
  }
@@ -21010,6 +21125,12 @@ CLI Version: ${options.cliVersion}`;
21010
21125
  let results = [];
21011
21126
  if (newPatches.length > 0) {
21012
21127
  results = await this.applicator.applyPatches(newPatches);
21128
+ this.revertConflictingFiles(results);
21129
+ for (const result of results) {
21130
+ if (result.status === "conflict") {
21131
+ result.patch.status = "unresolved";
21132
+ }
21133
+ }
21013
21134
  }
21014
21135
  const rebaseCounts = await this.rebasePatches(results, genRecord.commit_sha);
21015
21136
  for (const patch of newPatches) {
@@ -21020,10 +21141,8 @@ CLI Version: ${options.cliVersion}`;
21020
21141
  this.lockManager.save();
21021
21142
  if (newPatches.length > 0) {
21022
21143
  if (!options?.stageOnly) {
21023
- const appliedCount = results.filter((r) => r.status === "applied" || r.status === "conflict").length;
21024
- if (appliedCount > 0) {
21025
- await this.committer.commitReplay(appliedCount, newPatches);
21026
- }
21144
+ const appliedCount = results.filter((r) => r.status === "applied").length;
21145
+ await this.committer.commitReplay(appliedCount, newPatches);
21027
21146
  } else {
21028
21147
  await this.committer.stageAll();
21029
21148
  }
@@ -21071,20 +21190,32 @@ CLI Version: ${options.cliVersion}`;
21071
21190
  const genRecord = await this.committer.createGenerationRecord(commitOpts);
21072
21191
  this.lockManager.addGeneration(genRecord);
21073
21192
  const results = await this.applicator.applyPatches(allPatches);
21193
+ this.revertConflictingFiles(results);
21194
+ for (const result of results) {
21195
+ if (result.status === "conflict") {
21196
+ result.patch.status = "unresolved";
21197
+ }
21198
+ }
21074
21199
  const rebaseCounts = await this.rebasePatches(results, genRecord.commit_sha);
21075
21200
  for (const patch of newPatches) {
21076
21201
  if (!rebaseCounts.absorbedPatchIds.has(patch.id)) {
21077
21202
  this.lockManager.addPatch(patch);
21078
21203
  }
21079
21204
  }
21205
+ for (const result of results) {
21206
+ if (result.status === "conflict") {
21207
+ try {
21208
+ this.lockManager.markPatchUnresolved(result.patch.id);
21209
+ } catch {
21210
+ }
21211
+ }
21212
+ }
21080
21213
  this.lockManager.save();
21081
21214
  if (options?.stageOnly) {
21082
21215
  await this.committer.stageAll();
21083
21216
  } else {
21084
- const appliedCount = results.filter((r) => r.status === "applied" || r.status === "conflict").length;
21085
- if (appliedCount > 0) {
21086
- await this.committer.commitReplay(appliedCount, allPatches);
21087
- }
21217
+ const appliedCount = results.filter((r) => r.status === "applied").length;
21218
+ await this.committer.commitReplay(appliedCount, allPatches);
21088
21219
  }
21089
21220
  return this.buildReport(
21090
21221
  "normal-regeneration",
@@ -21232,6 +21363,10 @@ CLI Version: ${options.cliVersion}`;
21232
21363
  let conflictAbsorbed = 0;
21233
21364
  let contentRefreshed = 0;
21234
21365
  for (const patch of patches) {
21366
+ if (patch.status != null) {
21367
+ delete patch.status;
21368
+ continue;
21369
+ }
21235
21370
  if (patch.base_generation === currentGen) {
21236
21371
  try {
21237
21372
  const diff = await this.git.exec(["diff", currentGen, "HEAD", "--", ...patch.files]).catch(() => null);
@@ -21282,6 +21417,55 @@ CLI Version: ${options.cliVersion}`;
21282
21417
  }
21283
21418
  return { conflictResolved, conflictAbsorbed, contentRefreshed };
21284
21419
  }
21420
+ /**
21421
+ * Strip conflict markers from file content, keeping the OURS (Generated) side.
21422
+ * Preserves clean patches' non-conflicting changes on shared files.
21423
+ */
21424
+ stripConflictMarkers(content) {
21425
+ const lines = content.split("\n");
21426
+ const result = [];
21427
+ let inConflict = false;
21428
+ let inOurs = false;
21429
+ for (const line of lines) {
21430
+ if (line.startsWith("<<<<<<< ")) {
21431
+ inConflict = true;
21432
+ inOurs = true;
21433
+ continue;
21434
+ }
21435
+ if (inConflict && line === "=======") {
21436
+ inOurs = false;
21437
+ continue;
21438
+ }
21439
+ if (inConflict && line.startsWith(">>>>>>> ")) {
21440
+ inConflict = false;
21441
+ inOurs = false;
21442
+ continue;
21443
+ }
21444
+ if (!inConflict || inOurs) {
21445
+ result.push(line);
21446
+ }
21447
+ }
21448
+ return result.join("\n");
21449
+ }
21450
+ /**
21451
+ * After applyPatches(), strip conflict markers from conflicting files
21452
+ * so only clean content is committed. Keeps the Generated (OURS) side.
21453
+ */
21454
+ revertConflictingFiles(results) {
21455
+ for (const result of results) {
21456
+ if (result.status !== "conflict" || !result.fileResults) continue;
21457
+ for (const fileResult of result.fileResults) {
21458
+ if (fileResult.status !== "conflict") continue;
21459
+ const filePath = (0, import_path10.join)(this.outputDir, fileResult.file);
21460
+ try {
21461
+ const content = (0, import_fs7.readFileSync)(filePath, "utf-8");
21462
+ const stripped = this.stripConflictMarkers(content);
21463
+ (0, import_fs7.writeFileSync)(filePath, stripped);
21464
+ } catch {
21465
+ }
21466
+ }
21467
+ }
21468
+ }
21285
21469
  readFernignorePatterns() {
21286
21470
  const fernignorePath = (0, import_path10.join)(this.outputDir, ".fernignore");
21287
21471
  if (!(0, import_fs7.existsSync)(fernignorePath)) return [];
@@ -21316,6 +21500,12 @@ CLI Version: ${options.cliVersion}`;
21316
21500
  patchesRefreshed: preRebaseCounts && preRebaseCounts.contentRefreshed > 0 ? preRebaseCounts.contentRefreshed : void 0,
21317
21501
  conflicts: conflictResults.flatMap((r) => r.fileResults?.filter((f) => f.status === "conflict") ?? []),
21318
21502
  conflictDetails: conflictDetails.length > 0 ? conflictDetails : void 0,
21503
+ unresolvedPatches: conflictResults.length > 0 ? conflictResults.map((r) => ({
21504
+ patchId: r.patch.id,
21505
+ patchMessage: r.patch.original_message,
21506
+ files: r.patch.files,
21507
+ conflictDetails: r.fileResults?.filter((f) => f.status === "conflict") ?? []
21508
+ })) : void 0,
21319
21509
  wouldApply: options?.dryRun ? patches : void 0,
21320
21510
  warnings: warnings && warnings.length > 0 ? warnings : void 0
21321
21511
  };
@@ -21514,6 +21704,21 @@ CLI Version: ${options.cliVersion}`;
21514
21704
  }
21515
21705
  });
21516
21706
 
21707
+ // ../commons/core-utils/lib/extractErrorMessage.js
21708
+ function extractErrorMessage(e) {
21709
+ if (typeof e === "string") {
21710
+ return e.length > 0 ? e : "Unknown error";
21711
+ }
21712
+ if (e instanceof Error) {
21713
+ return e.message.length > 0 ? e.message : "Unknown error";
21714
+ }
21715
+ if (typeof e === "object" && e !== null && "message" in e && typeof e["message"] === "string") {
21716
+ return e["message"].length > 0 ? e["message"] : "Unknown error";
21717
+ }
21718
+ const stringified = String(e);
21719
+ return stringified.length > 0 ? stringified : "Unknown error";
21720
+ }
21721
+
21517
21722
  // ../commons/path-utils/lib/convertToOsPath.js
21518
21723
  function convertToOsPath(path5) {
21519
21724
  return path5.replace(/\\/g, "/");
@@ -23464,7 +23669,7 @@ function parseRepository(githubRepository) {
23464
23669
  } else if (parts.length === 3 && parts[0] != null && parts[1] != null && parts[2] != null) {
23465
23670
  [remote, owner, repo] = parts;
23466
23671
  } else {
23467
- throw new Error(`Failed to parse GitHub repostiory ${githubRepository}`);
23672
+ throw new Error(`Failed to parse GitHub repository ${githubRepository}`);
23468
23673
  }
23469
23674
  return newRepositoryReference({ remote, owner, repo });
23470
23675
  }
@@ -23545,7 +23750,7 @@ async function cloneRepository({ githubRepository, installationToken, targetDire
23545
23750
  await git.clone(cloneUrl, ".");
23546
23751
  } catch (error) {
23547
23752
  const elapsed = Date.now() - startTime;
23548
- const errorMessage = error instanceof Error ? error.message : String(error);
23753
+ const errorMessage = extractErrorMessage(error);
23549
23754
  if (errorMessage.includes("ENOENT") || errorMessage.includes("spawn git")) {
23550
23755
  const diagnostics = getGitDiagnostics();
23551
23756
  throw new Error(`Failed to clone repository: git command not found. Self-hosted GitHub mode requires git to be installed on the host machine where the Fern CLI runs. URL: ${sanitizedUrl}. Elapsed: ${elapsed}ms. Debug info: ${diagnostics}. Original error: ${errorMessage}`);
@@ -27227,9 +27432,6 @@ async function githubRelease(params) {
27227
27432
  await github.release();
27228
27433
  }
27229
27434
 
27230
- // src/api/generate-readme.ts
27231
- var import_node_stream = require("stream");
27232
-
27233
27435
  // ../../node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/predicate/isLength.mjs
27234
27436
  function isLength(value) {
27235
27437
  return Number.isSafeInteger(value) && value >= 0;
@@ -30048,16 +30250,25 @@ var ReadmeGenerator = class {
30048
30250
  this.apiName = this.readmeConfig.apiName ?? this.organizationPascalCase;
30049
30251
  }
30050
30252
  async generateReadme({ output }) {
30253
+ const writer = new StreamWriter(output);
30254
+ await this.writeReadmeContent({ writer });
30255
+ await writer.end();
30256
+ }
30257
+ async generateReadmeToString() {
30258
+ const writer = new StringWriter();
30259
+ await this.writeReadmeContent({ writer });
30260
+ await writer.end();
30261
+ return writer.toString();
30262
+ }
30263
+ async writeReadmeContent({ writer }) {
30051
30264
  const blocks = await this.generateBlocks();
30052
30265
  const mergedBlocks = await this.mergeBlocks({ blocks });
30053
- const writer = new StreamWriter(output);
30054
30266
  await this.writeHeader({ writer });
30055
30267
  await this.writeTableOfContents({ writer, blocks: mergedBlocks });
30056
30268
  await this.writeBlocks({
30057
30269
  writer,
30058
30270
  blocks: mergedBlocks
30059
30271
  });
30060
- await writer.end();
30061
30272
  }
30062
30273
  async generateBlocks() {
30063
30274
  const blocks = [];
@@ -30507,7 +30718,7 @@ var ReadmeGenerator = class {
30507
30718
  await writer.writeLine();
30508
30719
  await writer.writeLine("```groovy");
30509
30720
  await writer.writeLine("dependencies {");
30510
- await writer.writeLine(` implementation '${maven.group}:${maven.artifact}'`);
30721
+ await writer.writeLine(` implementation '${maven.group}:${maven.artifact}:${maven.version}'`);
30511
30722
  await writer.writeLine("}");
30512
30723
  await writer.writeLine("```");
30513
30724
  await writer.writeLine();
@@ -30927,9 +31138,6 @@ async function generateReadmeToStream(params) {
30927
31138
  });
30928
31139
  }
30929
31140
 
30930
- // src/api/generate-reference.ts
30931
- var import_node_stream2 = require("stream");
30932
-
30933
31141
  // src/reference/ReferenceGenerator.ts
30934
31142
  var ReferenceGenerator = class {
30935
31143
  referenceConfig;
@@ -30940,6 +31148,16 @@ var ReferenceGenerator = class {
30940
31148
  }
30941
31149
  async generate({ output }) {
30942
31150
  const writer = new StreamWriter(output);
31151
+ await this.writeReferenceContent({ writer });
31152
+ await writer.end();
31153
+ }
31154
+ async generateToString() {
31155
+ const writer = new StringWriter();
31156
+ await this.writeReferenceContent({ writer });
31157
+ await writer.end();
31158
+ return writer.toString();
31159
+ }
31160
+ async writeReferenceContent({ writer }) {
30943
31161
  await writer.writeLine("# Reference");
30944
31162
  if (this.referenceConfig.rootSection != null) {
30945
31163
  await this.writeRootSection({
@@ -30950,7 +31168,6 @@ var ReferenceGenerator = class {
30950
31168
  for (const section of this.referenceConfig.sections) {
30951
31169
  await this.writeSection({ section, writer });
30952
31170
  }
30953
- await writer.end();
30954
31171
  }
30955
31172
  async writeRootSection({
30956
31173
  section,
@@ -31090,41 +31307,19 @@ var import_path7 = require("path");
31090
31307
 
31091
31308
  // src/pipeline/github/createReplayBranch.ts
31092
31309
  async function createReplayBranch(repository, branchName, commitMessage, replayConflictInfo, logger) {
31093
- if (replayConflictInfo?.hasConflicts) {
31094
- const parentSha = replayConflictInfo.previousGenerationSha;
31095
- const lockfileRestoreSha = replayConflictInfo.baseBranchHead ?? replayConflictInfo.previousGenerationSha;
31096
- logger.debug(`Creating divergent PR branch with generation tree (parent: ${parentSha.substring(0, 7)})`);
31097
- const genTreeHash = await repository.getCommitTreeHash(replayConflictInfo.currentGenerationSha);
31098
- const syntheticCommitSha = await repository.commitTree(
31099
- genTreeHash,
31100
- parentSha,
31101
- `[fern-generated] ${commitMessage ?? "Update SDK"}`
31102
- );
31103
- await repository.createBranchFromCommit(branchName, syntheticCommitSha);
31104
- try {
31105
- await repository.restoreFilesFromCommit(lockfileRestoreSha, ".fern/replay.lock");
31106
- await repository.commitAllChanges(`[fern-generated] ${commitMessage ?? "Update SDK"}`);
31107
- } catch (error) {
31108
- logger.debug(
31109
- `Could not restore lockfile from base branch: ${error instanceof Error ? error.message : String(error)}`
31110
- );
31111
- }
31112
- return syntheticCommitSha;
31113
- } else if (replayConflictInfo != null) {
31114
- const parentSha = replayConflictInfo.previousGenerationSha;
31115
- logger.debug(`Creating linear PR branch from HEAD (no conflicts)`);
31116
- await repository.createBranchFromHead(branchName);
31117
- const genTreeHash = await repository.getCommitTreeHash(replayConflictInfo.currentGenerationSha);
31118
- const tagCommitSha = await repository.commitTree(
31119
- genTreeHash,
31120
- parentSha,
31121
- `[fern-generated] ${commitMessage ?? "Update SDK"}`
31122
- );
31123
- return tagCommitSha;
31124
- } else {
31310
+ if (replayConflictInfo == null) {
31125
31311
  await repository.createBranchFromHead(branchName);
31126
31312
  return void 0;
31127
31313
  }
31314
+ const parentSha = replayConflictInfo.previousGenerationSha;
31315
+ await repository.createBranchFromHead(branchName);
31316
+ const genTreeHash = await repository.getCommitTreeHash(replayConflictInfo.currentGenerationSha);
31317
+ const tagCommitSha = await repository.commitTree(
31318
+ genTreeHash,
31319
+ parentSha,
31320
+ `[fern-generated] ${commitMessage ?? "Update SDK"}`
31321
+ );
31322
+ return tagCommitSha;
31128
31323
  }
31129
31324
 
31130
31325
  // src/pipeline/github/findExistingUpdatablePR.ts
@@ -31170,7 +31365,7 @@ async function findExistingUpdatablePR(octokit, owner, repo, baseBranch, logger)
31170
31365
  }
31171
31366
  return void 0;
31172
31367
  } catch (error) {
31173
- logger.debug(`Error finding existing PRs: ${error instanceof Error ? error.message : String(error)}`);
31368
+ logger.debug(`Error finding existing PRs: ${extractErrorMessage(error)}`);
31174
31369
  return void 0;
31175
31370
  }
31176
31371
  }
@@ -31197,16 +31392,22 @@ async function checkPRHasOnlyGenerationCommits(octokit, owner, repo, pullNumber,
31197
31392
  }
31198
31393
  return true;
31199
31394
  } catch (error) {
31200
- logger.debug(`Error checking PR commits: ${error instanceof Error ? error.message : String(error)}`);
31395
+ logger.debug(`Error checking PR commits: ${extractErrorMessage(error)}`);
31201
31396
  return false;
31202
31397
  }
31203
31398
  }
31204
31399
 
31205
31400
  // src/pipeline/github/parseCommitMessage.ts
31206
- function parseCommitMessageForPR(commitMessage) {
31401
+ function parseCommitMessageForPR(commitMessage, changelogEntry, prDescription, versionBumpReason) {
31207
31402
  const lines = commitMessage.split("\n");
31208
31403
  const prTitle = lines[0]?.trim() || "SDK Generation";
31209
- const prBody = lines.slice(1).join("\n").trim() || "Automated SDK generation by Fern";
31404
+ const bodyFromCommit = lines.slice(1).join("\n").trim() || "Automated SDK generation by Fern";
31405
+ let prBody = prDescription?.trim() || changelogEntry?.trim() || bodyFromCommit;
31406
+ if (versionBumpReason?.trim()) {
31407
+ prBody = `**Version Bump:** ${versionBumpReason.trim()}
31408
+
31409
+ ${prBody}`;
31410
+ }
31210
31411
  return { prTitle, prBody };
31211
31412
  }
31212
31413
 
@@ -31219,11 +31420,11 @@ function formatConflictReason(reason) {
31219
31420
  case "same-line-edit":
31220
31421
  return "The new generation changed the same lines you edited";
31221
31422
  case "new-file-both":
31222
- return "You and the generator both created this file";
31423
+ return "Both the generator and your customization created this file";
31223
31424
  case "base-generation-mismatch":
31224
- return "The generated code changed significantly around your edit";
31425
+ return "This customization was from a previous generation";
31225
31426
  case "patch-apply-failed":
31226
- return "Your change could not be applied to the new generated code";
31427
+ return "The customization could not be applied to the new code";
31227
31428
  default:
31228
31429
  return "Your edit overlaps with changes in the new generation";
31229
31430
  }
@@ -31232,7 +31433,7 @@ function patchDescription(detail) {
31232
31433
  if (detail.patchMessage && detail.patchMessage !== "update") {
31233
31434
  return detail.patchMessage;
31234
31435
  }
31235
- const firstFile = detail.files[0]?.file;
31436
+ const firstFile = detail.files[0];
31236
31437
  return firstFile != null ? `changes in ${firstFile}` : "customization";
31237
31438
  }
31238
31439
  function formatReplayPrBody(result, options) {
@@ -31241,70 +31442,66 @@ function formatReplayPrBody(result, options) {
31241
31442
  }
31242
31443
  const applied = result.patchesApplied ?? 0;
31243
31444
  const absorbed = result.patchesAbsorbed ?? 0;
31244
- const conflicts2 = result.patchesWithConflicts ?? 0;
31445
+ const unresolvedPatches = result.unresolvedPatches ?? [];
31446
+ const hasUnresolved = unresolvedPatches.length > 0;
31245
31447
  const preserved = applied - absorbed;
31246
- if (preserved === 0 && conflicts2 === 0) {
31448
+ if (preserved === 0 && !hasUnresolved) {
31247
31449
  return void 0;
31248
31450
  }
31249
31451
  const parts = [];
31250
- if (preserved > 0 && conflicts2 === 0) {
31452
+ if (preserved > 0 && !hasUnresolved) {
31251
31453
  parts.push(`\u2705 Customizations automatically preserved in this update.`);
31252
31454
  } else if (preserved > 0) {
31455
+ const totalFiles = unresolvedPatches.reduce((sum, patch) => sum + patch.conflictDetails.length, 0);
31253
31456
  parts.push(
31254
- `\u2705 Customizations automatically preserved, but ${plural(conflicts2, "file")} ${conflicts2 === 1 ? "needs" : "need"} your attention.`
31457
+ `\u2705 Customizations automatically preserved, but ${plural(totalFiles, "file")} ${totalFiles === 1 ? "needs" : "need"} your attention.`
31255
31458
  );
31256
31459
  }
31257
- if (conflicts2 > 0) {
31258
- const allFiles = (result.conflictDetails ?? []).flatMap((d) => d.files);
31259
- const totalFiles = allFiles.length;
31460
+ if (hasUnresolved) {
31461
+ const totalFiles = unresolvedPatches.reduce((sum, patch) => sum + patch.conflictDetails.length, 0);
31260
31462
  parts.push(`
31261
- ### \u26A0\uFE0F Action required: ${plural(totalFiles, "file")} with customization conflicts
31463
+ ### Action required: ${plural(totalFiles, "file")} with unresolved customization conflicts
31262
31464
  `);
31263
31465
  parts.push(
31264
- `You previously customized ${totalFiles === 1 ? "a file" : "files"} in this SDK. This generation changed the same code, so your ${totalFiles === 1 ? "edit" : "edits"} couldn't be applied automatically.
31265
- `
31266
- );
31267
- parts.push(
31268
- `> \u26A0\uFE0F **Label guide:** In GitHub's conflict editor, \`<<<<<<< HEAD\` ("Accept current") = new generated code. \`>>>>>>> main\` ("Accept incoming") = your customization.
31466
+ `The new generation changed code you previously customized. Non-conflicting customizations have been applied automatically. The following files need manual resolution:
31269
31467
  `
31270
31468
  );
31271
31469
  parts.push(`| File | Your customization | Why it conflicted |`);
31272
31470
  parts.push(`|------|-------------------|-------------------|`);
31273
- for (const detail of result.conflictDetails ?? []) {
31274
- const description = patchDescription(detail);
31275
- for (const f of detail.files) {
31276
- parts.push(`| \`${f.file}\` | ${description} | ${formatConflictReason(f.conflictReason)} |`);
31471
+ for (const patch of unresolvedPatches) {
31472
+ const description = patchDescription(patch);
31473
+ for (const file of patch.conflictDetails) {
31474
+ parts.push(`| \`${file.file}\` | ${description} | ${formatConflictReason(file.conflictReason)} |`);
31277
31475
  }
31278
31476
  }
31279
31477
  const branch = options?.branchName ?? "<branch-name>";
31478
+ const repoUri = options?.repoUri;
31479
+ const repoName = repoUri?.split("/").pop() ?? "<repo>";
31280
31480
  parts.push(`
31281
- #### How to fix
31282
- `);
31283
- parts.push(`**Option A: Resolve in GitHub (recommended for simple conflicts)**
31284
- `);
31285
- parts.push(`1. Click the **Resolve conflicts** button below`);
31286
- parts.push(`2. For each file, choose which code to keep:`);
31287
- parts.push(` - \`<<<<<<< HEAD\` / "Accept current changes" = **new generated code**`);
31288
- parts.push(` - \`>>>>>>> main\` / "Accept incoming changes" = **your customization**`);
31289
- parts.push(` - Or manually combine both, then delete the conflict markers`);
31290
- parts.push(`3. Click **Mark as resolved** for each file, then **Commit merge**
31481
+ #### How to resolve
31291
31482
  `);
31292
- parts.push(`**Option B: Resolve locally**
31293
- `);
31294
- parts.push(`1. Fetch and check out this branch:`);
31483
+ parts.push(`1. Check out this branch:`);
31295
31484
  parts.push(` \`\`\`sh`);
31296
- parts.push(` git fetch origin && git checkout ${branch}`);
31485
+ parts.push(` git fetch origin && git checkout -b ${branch} origin/${branch}`);
31297
31486
  parts.push(` \`\`\``);
31298
- parts.push(`2. Merge the base branch and resolve conflicts in your editor:`);
31299
- parts.push(` \`\`\`sh`);
31300
- parts.push(` git merge origin/main`);
31301
- parts.push(` \`\`\``);
31302
- parts.push(`3. Commit and push:`);
31303
- parts.push(` \`\`\`sh`);
31304
- parts.push(` git add -A && git commit -m "resolve conflicts" && git push`);
31305
- parts.push(` \`\`\`
31487
+ if (repoUri != null) {
31488
+ parts.push(` Or if you don't have the repo cloned:`);
31489
+ parts.push(` \`\`\`sh`);
31490
+ parts.push(
31491
+ ` git clone https://github.com/${repoUri}.git && cd ${repoName} && git checkout -b ${branch} origin/${branch}`
31492
+ );
31493
+ parts.push(` \`\`\``);
31494
+ }
31495
+ parts.push(`2. Run: \`fern replay resolve\``);
31496
+ parts.push(`3. Open the conflicting files in your editor \u2014 you'll see standard merge conflict markers`);
31497
+ parts.push(`4. Resolve using your editor's merge tools (VS Code, IntelliJ, etc.)`);
31498
+ parts.push(`5. Run: \`fern replay resolve\` again to finalize`);
31499
+ parts.push(`6. Push your changes
31306
31500
  `);
31307
- parts.push(`Your resolved changes will be remembered on future SDK generations.`);
31501
+ parts.push(`Your resolved customizations will be remembered on future SDK generations.`);
31502
+ parts.push(
31503
+ `If you merge this PR without resolving, your unresolved customizations will conflict again on the next generation.`
31504
+ );
31308
31505
  }
31309
31506
  return parts.join("\n");
31310
31507
  }
@@ -31434,22 +31631,18 @@ var GithubStep = class extends BaseStep {
31434
31631
  this.logger.debug(`Pushed ${tagName} tag for generation tracking`);
31435
31632
  result.generationBaseTagSha = generationBaseSha;
31436
31633
  } catch (error) {
31437
- this.logger.debug(
31438
- `Could not push generation tag: ${error instanceof Error ? error.message : String(error)}`
31439
- );
31634
+ this.logger.debug(`Could not push generation tag: ${extractErrorMessage(error)}`);
31440
31635
  }
31441
31636
  }
31442
31637
  }
31443
- if (!this.config.previewMode) {
31444
- const headSha = await repository.getHeadSha();
31445
- await this.postReplayConflictStatus(octokit, owner, repo, headSha, replayConflictInfo, replayResult);
31446
- if (isUpdatingExistingPR && existingPR != null) {
31447
- await this.togglePrDraftState(octokit, existingPR, replayConflictInfo);
31448
- }
31449
- }
31450
31638
  const finalCommitMessage = this.config.commitMessage ?? "SDK Generation";
31451
- const { prTitle, prBody } = parseCommitMessageForPR(finalCommitMessage);
31452
- const replaySection = formatReplayPrBody(replayResult, { branchName: prBranch });
31639
+ const { prTitle, prBody } = parseCommitMessageForPR(
31640
+ finalCommitMessage,
31641
+ this.config.changelogEntry,
31642
+ this.config.prDescription,
31643
+ this.config.versionBumpReason
31644
+ );
31645
+ const replaySection = formatReplayPrBody(replayResult, { branchName: prBranch, repoUri: this.config.uri });
31453
31646
  const enrichedBody = replaySection != null ? prBody + "\n\n---\n\n" + replaySection : prBody;
31454
31647
  if (isUpdatingExistingPR && existingPR != null) {
31455
31648
  this.logger.info(`Updated existing pull request: ${existingPR.htmlUrl}`);
@@ -31465,13 +31658,10 @@ var GithubStep = class extends BaseStep {
31465
31658
  });
31466
31659
  this.logger.debug(`Updated PR #${existingPR.number} title and body`);
31467
31660
  } catch (error) {
31468
- this.logger.debug(
31469
- `Failed to update PR title/body: ${error instanceof Error ? error.message : String(error)}`
31470
- );
31661
+ this.logger.debug(`Failed to update PR title/body: ${extractErrorMessage(error)}`);
31471
31662
  }
31472
31663
  } else {
31473
31664
  const head = `${owner}:${prBranch}`;
31474
- const hasConflicts = replayConflictInfo?.hasConflicts === true;
31475
31665
  try {
31476
31666
  const { data: pullRequest } = await octokit.pulls.create({
31477
31667
  owner,
@@ -31479,14 +31669,13 @@ var GithubStep = class extends BaseStep {
31479
31669
  title: prTitle,
31480
31670
  body: enrichedBody,
31481
31671
  head,
31482
- base: baseBranch,
31483
- draft: hasConflicts
31672
+ base: baseBranch
31484
31673
  });
31485
31674
  this.logger.info(`Created pull request: ${pullRequest.html_url}`);
31486
31675
  result.prUrl = pullRequest.html_url;
31487
31676
  result.prNumber = pullRequest.number;
31488
31677
  } catch (error) {
31489
- const message = error instanceof Error ? error.message : String(error);
31678
+ const message = extractErrorMessage(error);
31490
31679
  if (message.includes("A pull request already exists for")) {
31491
31680
  this.logger.warn(`A pull request already exists for ${head}`);
31492
31681
  } else {
@@ -31494,17 +31683,6 @@ var GithubStep = class extends BaseStep {
31494
31683
  }
31495
31684
  }
31496
31685
  }
31497
- if (!this.config.previewMode && result.prNumber != null && replayConflictInfo?.hasConflicts === true && replayResult != null) {
31498
- await this.postWebEditorFallbackComment(
31499
- octokit,
31500
- owner,
31501
- repo,
31502
- result.prNumber,
31503
- prBranch,
31504
- baseBranch,
31505
- replayResult
31506
- );
31507
- }
31508
31686
  return result;
31509
31687
  }
31510
31688
  async executePushMode(repository) {
@@ -31550,198 +31728,17 @@ var GithubStep = class extends BaseStep {
31550
31728
  if (replayResult == null) {
31551
31729
  return void 0;
31552
31730
  }
31553
- const hasConflicts = (replayResult.patchesWithConflicts ?? 0) > 0;
31554
31731
  const previousGenerationSha = replayResult.previousGenerationSha;
31555
31732
  const currentGenerationSha = replayResult.currentGenerationSha;
31556
31733
  if (previousGenerationSha != null && currentGenerationSha != null) {
31557
31734
  return {
31558
31735
  previousGenerationSha,
31559
- currentGenerationSha,
31560
- hasConflicts,
31561
- baseBranchHead: replayResult.baseBranchHead
31736
+ currentGenerationSha
31562
31737
  };
31563
31738
  }
31564
31739
  return void 0;
31565
31740
  }
31566
- async togglePrDraftState(octokit, existingPR, replayConflictInfo) {
31567
- const hasConflicts = replayConflictInfo?.hasConflicts === true;
31568
- if (hasConflicts && !existingPR.isDraft) {
31569
- await this.convertPrToDraft(octokit, existingPR.nodeId, existingPR.number);
31570
- } else if (!hasConflicts && existingPR.isDraft) {
31571
- await this.markPrReady(octokit, existingPR.nodeId, existingPR.number);
31572
- }
31573
- }
31574
- async convertPrToDraft(octokit, nodeId, prNumber) {
31575
- try {
31576
- await octokit.graphql(
31577
- `mutation($id: ID!) {
31578
- convertPullRequestToDraft(input: {pullRequestId: $id}) {
31579
- pullRequest { isDraft }
31580
- }
31581
- }`,
31582
- { id: nodeId }
31583
- );
31584
- this.logger.info(`Converted PR #${prNumber} to draft due to replay conflicts`);
31585
- } catch (error) {
31586
- this.logger.debug(
31587
- `Could not convert PR to draft: ${error instanceof Error ? error.message : String(error)}`
31588
- );
31589
- }
31590
- }
31591
- async markPrReady(octokit, nodeId, prNumber) {
31592
- try {
31593
- await octokit.graphql(
31594
- `mutation($id: ID!) {
31595
- markPullRequestReadyForReview(input: {pullRequestId: $id}) {
31596
- pullRequest { isDraft }
31597
- }
31598
- }`,
31599
- { id: nodeId }
31600
- );
31601
- this.logger.info(`Marked PR #${prNumber} as ready (conflicts resolved)`);
31602
- } catch (error) {
31603
- this.logger.debug(`Could not mark PR as ready: ${error instanceof Error ? error.message : String(error)}`);
31604
- }
31605
- }
31606
- async postReplayConflictStatus(octokit, owner, repo, sha, replayConflictInfo, replayResult) {
31607
- if (replayResult == null || !replayResult.executed) {
31608
- return;
31609
- }
31610
- const hasConflicts = replayConflictInfo?.hasConflicts === true;
31611
- const conflictFileCount = (replayResult.conflictDetails ?? []).reduce(
31612
- (sum, detail) => sum + detail.files.length,
31613
- 0
31614
- );
31615
- const sanitizedName = this.config.generatorName?.replace(/\//g, "--");
31616
- const context = sanitizedName != null ? `fern / sdk customizations / ${sanitizedName}` : "fern / sdk customizations";
31617
- try {
31618
- await octokit.repos.createCommitStatus({
31619
- owner,
31620
- repo,
31621
- sha,
31622
- state: hasConflicts ? "failure" : "success",
31623
- context,
31624
- description: hasConflicts ? `${conflictFileCount} file(s) need manual conflict resolution \u2014 see PR description` : "All customizations applied"
31625
- });
31626
- this.logger.debug(`Posted ${hasConflicts ? "failing" : "passing"} commit status (${context})`);
31627
- } catch (error) {
31628
- this.logger.debug(
31629
- `Could not post commit status: ${error instanceof Error ? error.message : String(error)}`
31630
- );
31631
- }
31632
- }
31633
- async postWebEditorFallbackComment(octokit, owner, repo, prNumber, branchName, baseBranch, replayResult) {
31634
- try {
31635
- const webEditorLikelyDisabled = await this.isWebEditorLikelyDisabled(
31636
- octokit,
31637
- owner,
31638
- repo,
31639
- prNumber,
31640
- replayResult
31641
- );
31642
- if (!webEditorLikelyDisabled) {
31643
- this.logger.debug(`PR #${prNumber}: web conflict editor appears usable, skipping fallback comment`);
31644
- return;
31645
- }
31646
- const comment = buildWebEditorFallbackComment(branchName, baseBranch);
31647
- await octokit.issues.createComment({
31648
- owner,
31649
- repo,
31650
- issue_number: prNumber,
31651
- body: comment
31652
- });
31653
- this.logger.info(`Posted web-editor fallback comment on PR #${prNumber}`);
31654
- } catch (error) {
31655
- this.logger.debug(
31656
- `Could not post web-editor fallback comment: ${error instanceof Error ? error.message : String(error)}`
31657
- );
31658
- }
31659
- }
31660
- async isWebEditorLikelyDisabled(octokit, owner, repo, prNumber, replayResult) {
31661
- const conflictDetails = replayResult.conflictDetails ?? [];
31662
- const allConflictFiles = conflictDetails.flatMap((d) => d.files);
31663
- const totalConflictFiles = allConflictFiles.length;
31664
- const hasFileDeletionConflict = allConflictFiles.some((f) => {
31665
- const status2 = (f.status ?? "").toLowerCase();
31666
- const reason = (f.conflictReason ?? "").toLowerCase();
31667
- return status2 === "skipped" || reason.includes("delete") || reason.includes("removed");
31668
- });
31669
- if (hasFileDeletionConflict) {
31670
- this.logger.debug(`PR #${prNumber}: detected file deletion conflict, web editor likely disabled`);
31671
- return true;
31672
- }
31673
- if (totalConflictFiles >= WEB_EDITOR_FILE_THRESHOLD) {
31674
- this.logger.debug(
31675
- `PR #${prNumber}: ${totalConflictFiles} conflicting files exceeds threshold (${WEB_EDITOR_FILE_THRESHOLD}), web editor likely disabled`
31676
- );
31677
- return true;
31678
- }
31679
- const totalHunks = (replayResult.conflicts ?? []).reduce(
31680
- (sum, fileConflict) => sum + fileConflict.conflicts.length,
31681
- 0
31682
- );
31683
- if (totalHunks >= WEB_EDITOR_HUNK_THRESHOLD) {
31684
- this.logger.debug(
31685
- `PR #${prNumber}: ${totalHunks} conflict hunks exceeds threshold (${WEB_EDITOR_HUNK_THRESHOLD}), web editor likely disabled`
31686
- );
31687
- return true;
31688
- }
31689
- const mergeableState = await this.pollMergeableState(octokit, owner, repo, prNumber);
31690
- if (mergeableState.mergeable === null) {
31691
- this.logger.debug(`PR #${prNumber}: mergeable state still null after polling, web editor likely disabled`);
31692
- return true;
31693
- }
31694
- return false;
31695
- }
31696
- async pollMergeableState(octokit, owner, repo, prNumber) {
31697
- for (let attempt2 = 0; attempt2 < MERGEABLE_POLL_MAX_ATTEMPTS; attempt2++) {
31698
- const { data: pr } = await octokit.pulls.get({
31699
- owner,
31700
- repo,
31701
- pull_number: prNumber
31702
- });
31703
- if (pr.mergeable != null) {
31704
- return {
31705
- mergeable: pr.mergeable,
31706
- mergeableState: pr.mergeable_state
31707
- };
31708
- }
31709
- if (attempt2 < MERGEABLE_POLL_MAX_ATTEMPTS - 1) {
31710
- await sleep(MERGEABLE_POLL_DELAY_MS);
31711
- }
31712
- }
31713
- return { mergeable: null, mergeableState: "unknown" };
31714
- }
31715
31741
  };
31716
- var WEB_EDITOR_FILE_THRESHOLD = 20;
31717
- var WEB_EDITOR_HUNK_THRESHOLD = 50;
31718
- var MERGEABLE_POLL_MAX_ATTEMPTS = 3;
31719
- var MERGEABLE_POLL_DELAY_MS = 1500;
31720
- function buildWebEditorFallbackComment(branchName, baseBranch) {
31721
- const lines = [
31722
- `> **Note:** These conflicts may be too complex for GitHub's web editor. To resolve locally:`,
31723
- `>`,
31724
- `> 1. Check out this branch:`,
31725
- `> \`\`\`sh`,
31726
- `> git fetch origin && git checkout ${branchName}`,
31727
- `> \`\`\``,
31728
- `> 2. Merge the base branch:`,
31729
- `> \`\`\`sh`,
31730
- `> git merge origin/${baseBranch}`,
31731
- `> \`\`\``,
31732
- `> 3. Resolve conflicts in your editor (VS Code, IntelliJ, etc. have built-in merge tools)`,
31733
- `> 4. Commit and push:`,
31734
- `> \`\`\`sh`,
31735
- `> git add -A && git commit -m "resolve conflicts" && git push`,
31736
- `> \`\`\``,
31737
- `>`,
31738
- `> **Label guide:** In your editor's merge view, "current" = new generated code, "incoming" = your customization.`
31739
- ];
31740
- return lines.join("\n");
31741
- }
31742
- function sleep(ms) {
31743
- return new Promise((resolve8) => setTimeout(resolve8, ms));
31744
- }
31745
31742
 
31746
31743
  // src/replay/replay-run.ts
31747
31744
  init_dist();
@@ -31950,8 +31947,7 @@ var ReplayStep = class extends BaseStep {
31950
31947
  flow: "first-generation",
31951
31948
  patchesDetected: 0,
31952
31949
  patchesApplied: 0,
31953
- patchesWithConflicts: 0,
31954
- conflicts: []
31950
+ patchesWithConflicts: 0
31955
31951
  };
31956
31952
  }
31957
31953
  const report = result.report;
@@ -31969,22 +31965,12 @@ var ReplayStep = class extends BaseStep {
31969
31965
  patchesRepointed: report.patchesRepointed,
31970
31966
  patchesContentRebased: report.patchesContentRebased,
31971
31967
  patchesKeptAsUserOwned: report.patchesKeptAsUserOwned,
31972
- conflicts: report.conflicts.map((fileResult) => ({
31973
- filePath: fileResult.file,
31974
- conflicts: fileResult.conflicts?.map((conflict) => ({
31975
- startLine: conflict.startLine,
31976
- endLine: conflict.endLine,
31977
- ours: conflict.ours,
31978
- theirs: conflict.theirs
31979
- })) ?? []
31980
- })),
31981
- conflictDetails: report.conflictDetails?.map((detail) => ({
31982
- patchId: detail.patchId,
31983
- patchMessage: detail.patchMessage,
31984
- reason: detail.reason,
31985
- files: detail.files.map((f) => ({
31968
+ unresolvedPatches: report.unresolvedPatches?.map((info) => ({
31969
+ patchId: info.patchId,
31970
+ patchMessage: info.patchMessage,
31971
+ files: info.files,
31972
+ conflictDetails: info.conflictDetails.map((f) => ({
31986
31973
  file: f.file,
31987
- status: f.status,
31988
31974
  conflictReason: f.conflictReason
31989
31975
  }))
31990
31976
  })),
@@ -32055,7 +32041,7 @@ var PostGenerationPipeline = class {
32055
32041
  } catch (error) {
32056
32042
  result.success = false;
32057
32043
  result.errors = result.errors ?? [];
32058
- const errorMessage = error instanceof Error ? error.message : String(error);
32044
+ const errorMessage = extractErrorMessage(error);
32059
32045
  result.errors.push(`${step.name} step error: ${errorMessage}`);
32060
32046
  }
32061
32047
  }
@@ -32248,6 +32234,9 @@ function buildPrBody(result) {
32248
32234
  return lines.join("\n");
32249
32235
  }
32250
32236
 
32237
+ // src/replay/replay-resolve.ts
32238
+ init_dist();
32239
+
32251
32240
  // src/configuration/loadGitHubConfig.ts
32252
32241
  var import_promises6 = require("fs/promises");
32253
32242
  async function loadGitHubConfig({
@@ -32432,7 +32421,7 @@ void yargs_default(hideBin(process.argv)).scriptName(process.env.CLI_NAME ?? "ge
32432
32421
  try {
32433
32422
  config = JSON.parse(configContent);
32434
32423
  } catch (parseError) {
32435
- const parseMessage = parseError instanceof Error ? parseError.message : String(parseError);
32424
+ const parseMessage = extractErrorMessage(parseError);
32436
32425
  throw new Error(`Failed to parse pipeline config as JSON: ${parseMessage}`);
32437
32426
  }
32438
32427
  config.outputDir = resolve(wd, argv["output-dir"]);
@@ -32466,7 +32455,7 @@ ${result.errors.map((e) => ` - ${e}`).join("\n")}
32466
32455
  process.stdout.write(JSON.stringify(result) + "\n");
32467
32456
  process.exitCode = result.success ? 0 : 1;
32468
32457
  } catch (error) {
32469
- const errorMessage = error instanceof Error ? error.message : String(error);
32458
+ const errorMessage = extractErrorMessage(error);
32470
32459
  process.stderr.write(`Pipeline failed: ${errorMessage}
32471
32460
  `);
32472
32461
  process.exitCode = 1;
@@ -32545,7 +32534,7 @@ ${result.errors.map((e) => ` - ${e}`).join("\n")}
32545
32534
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
32546
32535
  process.exit(0);
32547
32536
  } catch (error) {
32548
- const errorMessage = error instanceof Error ? error.message : String(error);
32537
+ const errorMessage = extractErrorMessage(error);
32549
32538
  process.stderr.write(`Replay init failed: ${errorMessage}
32550
32539
  `);
32551
32540
  process.exit(1);
@@ -32627,7 +32616,7 @@ Bootstrap complete! Lockfile saved to ${outputDir}/.fern/replay.lock
32627
32616
  }
32628
32617
  process.exit(0);
32629
32618
  } catch (error) {
32630
- const errorMessage = error instanceof Error ? error.message : String(error);
32619
+ const errorMessage = extractErrorMessage(error);
32631
32620
  process.stderr.write(`Bootstrap failed: ${errorMessage}
32632
32621
  `);
32633
32622
  process.exit(1);