@fern-api/fern-api-dev 4.68.4 → 4.68.5-8-g6594a748f1f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli.cjs +598 -220
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -627016,7 +627016,7 @@ var AccessTokenPosthogManager = class {
627016
627016
  properties: {
627017
627017
  ...event,
627018
627018
  ...event.properties,
627019
- version: "4.68.4",
627019
+ version: "4.68.5-8-g6594a748f1f",
627020
627020
  usingAccessToken: true
627021
627021
  }
627022
627022
  });
@@ -627070,7 +627070,7 @@ var UserPosthogManager = class {
627070
627070
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
627071
627071
  event: "CLI",
627072
627072
  properties: {
627073
- version: "4.68.4",
627073
+ version: "4.68.5-8-g6594a748f1f",
627074
627074
  ...event,
627075
627075
  ...event.properties,
627076
627076
  usingAccessToken: false,
@@ -844122,7 +844122,7 @@ var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
844122
844122
  var LOGS_FOLDER_NAME = "logs";
844123
844123
  var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
844124
844124
  function getCliSource() {
844125
- const version7 = "4.68.4";
844125
+ const version7 = "4.68.5-8-g6594a748f1f";
844126
844126
  return `cli@${version7}`;
844127
844127
  }
844128
844128
  var DebugLogger = class {
@@ -855372,7 +855372,7 @@ var LegacyDocsPublisher = class {
855372
855372
  previewId,
855373
855373
  disableTemplates: void 0,
855374
855374
  skipUpload,
855375
- cliVersion: "4.68.4"
855375
+ cliVersion: "4.68.5-8-g6594a748f1f"
855376
855376
  });
855377
855377
  if (taskContext.getResult() === TaskResult.Failure) {
855378
855378
  return { success: false };
@@ -906294,7 +906294,7 @@ var AsyncHttpRequest = class {
906294
906294
  throw (0, import_baml.toBamlError)(error50);
906295
906295
  }
906296
906296
  }
906297
- async ConsolidateChangelog(raw_entries, version_bump, language, __baml_options__) {
906297
+ async ConsolidateChangelog(raw_entries, version_bump, language, previous_version, new_version, __baml_options__) {
906298
906298
  try {
906299
906299
  const __rawEnv__ = __baml_options__?.env ? { ...process.env, ...__baml_options__.env } : { ...process.env };
906300
906300
  const __env__ = Object.fromEntries(Object.entries(__rawEnv__).filter(([_16, value]) => value !== void 0));
@@ -906306,7 +906306,9 @@ var AsyncHttpRequest = class {
906306
906306
  return await this.runtime.buildRequest("ConsolidateChangelog", {
906307
906307
  "raw_entries": raw_entries,
906308
906308
  "version_bump": version_bump,
906309
- "language": language
906309
+ "language": language,
906310
+ "previous_version": previous_version,
906311
+ "new_version": new_version
906310
906312
  }, this.ctxManager.cloneContext(), __baml_options__?.tb?.__tb(), __clientRegistry__, false, __env__);
906311
906313
  } catch (error50) {
906312
906314
  throw (0, import_baml.toBamlError)(error50);
@@ -906340,7 +906342,7 @@ var AsyncHttpStreamRequest = class {
906340
906342
  throw (0, import_baml.toBamlError)(error50);
906341
906343
  }
906342
906344
  }
906343
- async ConsolidateChangelog(raw_entries, version_bump, language, __baml_options__) {
906345
+ async ConsolidateChangelog(raw_entries, version_bump, language, previous_version, new_version, __baml_options__) {
906344
906346
  try {
906345
906347
  const __rawEnv__ = __baml_options__?.env ? { ...process.env, ...__baml_options__.env } : { ...process.env };
906346
906348
  const __env__ = Object.fromEntries(Object.entries(__rawEnv__).filter(([_16, value]) => value !== void 0));
@@ -906352,7 +906354,9 @@ var AsyncHttpStreamRequest = class {
906352
906354
  return await this.runtime.buildRequest("ConsolidateChangelog", {
906353
906355
  "raw_entries": raw_entries,
906354
906356
  "version_bump": version_bump,
906355
- "language": language
906357
+ "language": language,
906358
+ "previous_version": previous_version,
906359
+ "new_version": new_version
906356
906360
  }, this.ctxManager.cloneContext(), __baml_options__?.tb?.__tb(), __clientRegistry__, true, __env__);
906357
906361
  } catch (error50) {
906358
906362
  throw (0, import_baml.toBamlError)(error50);
@@ -906420,7 +906424,7 @@ var import_baml3 = require("@boundaryml/baml");
906420
906424
 
906421
906425
  // ../ai/lib/baml_client/inlinedbaml.js
906422
906426
  var fileMap = {
906423
- "diff_analyzer.baml": '// SDK Diff Analyzer\n// Analyzes git diffs of SDK code and produces semantic commit messages and version bumps\n\nenum VersionBump {\n MAJOR\n MINOR\n PATCH\n NO_CHANGE\n}\n\nclass AnalyzeCommitDiffRequest {\n diff string @description("The git diff to analyze for generating a commit message")\n}\n\nclass AnalyzeCommitDiffResponse {\n message string\n @description("Developer-facing git commit message. Use conventional commit format. Reference specific code symbols (function names, class names). Keep summary under 72 chars.")\n\n changelog_entry string\n @description("User-facing release note for CHANGELOG.md and GitHub Releases. Describe the impact on SDK consumers, not implementation details. Include migration instructions for MAJOR. Use plain prose, not conventional commit format. Empty string for PATCH.")\n\n version_bump VersionBump\n @description("The recommended semantic version bump: MAJOR for breaking changes, MINOR for new features, PATCH for bug fixes and other changes, NO_CHANGE for empty diffs")\n\n version_bump_reason string\n @description("One sentence explaining WHY this version bump was chosen. For MAJOR: name the specific breaking symbol(s). For MINOR: name the new capability. For PATCH: describe the fix. For NO_CHANGE: \'No functional changes detected.\' Example: \'MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`.\'")\n}\n\n// Main function that analyzes SDK diffs\nfunction AnalyzeSdkDiff(\n diff: string @description("The git diff to analyze"),\n language: string @description("The SDK programming language, e.g. \'typescript\', \'python\', \'java\'"),\n previous_version: string @description("The current published version before this change, e.g. \'1.2.3\'"),\n prior_changelog: string @description("The last 3 changelog entries for this SDK, empty string if none. Use this to match the existing commit message style and understand the versioning pattern."),\n spec_commit_message: string @description("The commit message from the API spec repository that triggered this SDK generation. Use as a hint for the intent of the change, but verify against the actual diff. Empty string if unavailable.")\n) -> AnalyzeCommitDiffResponse {\n client DefaultClient\n\n prompt #"\n You are an expert software engineer analyzing changes to generate semantic commit messages.\n\n Analyze the provided git diff and return a structured response with these fields:\n - message: A git commit message formatted like the example below\n - version_bump: One of: MAJOR, MINOR, PATCH, or NO_CHANGE\n\n Version Bump Guidelines:\n - MAJOR: Breaking changes (removed/renamed functions, changed signatures, removed parameters)\n - MINOR: New features that are backward compatible (new functions, new optional parameters).\n Also MINOR: behavioral changes invisible to the public API surface that still affect consumers:\n - Changed HTTP status code handling (e.g. 404 now throws instead of returning null)\n - Changed default parameter values (timeout, retry count, page size, base URL)\n - Changed serialization behavior (date formats, null handling, field ordering)\n - Changed error message text that consumers may depend on\n - Changed HTTP header names or values sent to the server\n - Changed retry or backoff behavior (different retry counts, delay strategies)\n - PATCH: Bug fixes, documentation, internal refactoring with no observable behavioral change\n - NO_CHANGE: The diff is empty\n\n --- Examples ---\n\n Examples of correct classifications:\n\n --- MAJOR: removed exported TypeScript function ---\n diff --git a/src/api/client.ts b/src/api/client.ts\n -export async function getUser(id: string): Promise<User> {\n - return this.request("GET", `/users/${id}`);\n -}\n version_bump: MAJOR\n reason: Existing callers of getUser() will get a compile error.\n\n --- MAJOR: removed Python public method ---\n diff --git a/vital/client.py b/vital/client.py\n - def get_user(self, user_id: str) -> User:\n - return self._request("GET", f"/users/{user_id}")\n version_bump: MAJOR\n reason: Existing callers crash with AttributeError.\n\n --- MINOR: new optional TypeScript parameter ---\n diff --git a/src/api/client.ts b/src/api/client.ts\n -async createUser(name: string): Promise<User>\n +async createUser(name: string, role?: UserRole): Promise<User>\n version_bump: MINOR\n reason: Existing callers unaffected \u2014 new parameter is optional.\n\n --- MINOR: new Java public method ---\n diff --git a/src/.../UsersClient.java b/src/.../UsersClient.java\n + public CompletableFuture<User> getUserAsync(String userId) {\n + return this.httpClient.sendAsync(...);\n + }\n version_bump: MINOR\n reason: New capability added, nothing removed or changed.\n\n --- MINOR: changed default retry count ---\n diff --git a/src/core/http_client.py b/src/core/http_client.py\n -MAX_RETRIES = 3\n +MAX_RETRIES = 5\n version_bump: MINOR\n reason: Changed default retry count \u2014 existing consumers will experience different retry behavior.\n\n --- PATCH: Go import reorganization ---\n diff --git a/client.go b/client.go\n -import "fmt"\n -import "net/http"\n +import (\n + "fmt"\n + "net/http"\n +)\n version_bump: PATCH\n reason: Formatting change only, no functional difference.\n\n --- End Examples ---\n\n {% if language == "typescript" %}\n Language-specific breaking change rules for TypeScript:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, function, or exported symbol is MAJOR\n - Making a response field optional is MAJOR (type changes from T to T | undefined, breaking existing property access without null checks)\n - Changing a method return type (e.g. Promise<T> to Promise<T | undefined>, or T to T | null) is MAJOR\n - New enum values are MAJOR if the SDK generates exhaustive switch/if-else chains (callers get compile errors on unhandled cases)\n - Changing a union type (adding/removing variants) is MAJOR if callers use exhaustive type narrowing or discriminated unions\n - Adding a new required property to a request/input type is MAJOR (existing callers won\'t compile)\n - Removing or renaming an exported type, interface, or type alias is MAJOR\n - Changing the type of an existing property (e.g. string to number, or string to string[]) is MAJOR\n - Changing a generic type parameter constraint (e.g. <T extends Foo> to <T extends Bar>) is MAJOR\n - Converting a synchronous method to async (or vice versa) is MAJOR (changes return type to Promise<T>)\n - Removing a default export or switching between default and named exports is MAJOR\n - Changing the structure of a discriminated union (e.g. changing the discriminant field name) is MAJOR\n - Removing or renaming environment/server URL constants is MAJOR\n - Changing the constructor signature of a client class (adding required params) is MAJOR\n - Narrowing a parameter type (e.g. string | number to string) is MAJOR (callers passing number break)\n\n MINOR (backward-compatible additions):\n - Adding a new optional parameter to a function is MINOR\n - Adding new exported types, interfaces, or classes is MINOR\n - Adding new methods to an existing client class is MINOR\n - Adding new optional properties to request types is MINOR\n - Adding new enum values when NOT used in exhaustive checks is MINOR\n - Adding new environment/server URL constants is MINOR\n - Widening a parameter type (e.g. string to string | number) is MINOR\n - Adding new re-exports from index files is MINOR\n - Adding new error types or exception classes is MINOR\n - Adding new RequestOptions fields (e.g. timeout, retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n\n PATCH (no API surface change):\n - Changes to internal/private modules (core/, _internal/, utils/) are PATCH\n - Reordering imports, formatting, or comment changes are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring HTTP client internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in package.json is PATCH\n - Adding or modifying JSDoc/TSDoc comments is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to .npmignore, tsconfig.json, or build configuration are PATCH\n - Updating serialization/deserialization logic that preserves the same public types is PATCH\n\n {% elif language == "python" %}\n Language-specific breaking change rules for Python:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or function is always MAJOR\n - Adding a new required parameter to a public method is MAJOR (callers get TypeError)\n - Renaming a parameter in a public method is MAJOR if callers use keyword arguments\n - Removing a parameter from a public method signature is MAJOR\n - Changing the type of a parameter from one concrete type to an incompatible one is MAJOR\n - Changing exception types raised by a method (callers catching specific exceptions break) is MAJOR\n - Removing or renaming a public module or subpackage is MAJOR (import statements break)\n - Moving a public class/function to a different module without re-exporting from the original is MAJOR\n - Changing a class from inheriting one base to another when callers use isinstance() checks is MAJOR\n - Removing a public class attribute or property is MAJOR\n\n MINOR (backward-compatible additions):\n - Making a response field optional is usually MINOR (Python uses None propagation; callers rarely type-check strictly)\n - New enum values are MINOR (unknown values are handled gracefully with string fallbacks)\n - Changing a return type from a concrete type to Optional is MINOR (duck typing absorbs this)\n - Adding new public methods, classes, or modules is MINOR\n - Adding new optional parameters (with defaults) is MINOR\n - Adding new optional fields to Pydantic models is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new class attributes or properties is MINOR\n - Adding new type overloads (@overload decorator) is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, max_retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n - Widening a type annotation (e.g. str to Union[str, int]) is MINOR\n\n PATCH (no API surface change):\n - Changes to private methods (prefixed with _) are PATCH\n - Changes to type hints only (no runtime effect) are PATCH\n - Reformatting, docstring updates, or comment changes are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) are PATCH\n - Refactoring httpx/requests client internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in pyproject.toml/setup.py is PATCH\n - Updating serialization/deserialization logic that preserves the same public types is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to __init__.py that don\'t alter public re-exports are PATCH\n - Changes to conftest.py, test files, or CI configuration are PATCH\n\n {% elif language == "java" %}\n Language-specific breaking change rules for Java:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or interface is always MAJOR\n - Making a response field optional (e.g. T to Optional<T>) is MAJOR (callers must handle Optional unwrapping)\n - New enum values are MAJOR if the SDK generates exhaustive switch statements\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR (even if compatible at runtime, recompilation fails)\n - Removing or changing a public static final constant is MAJOR\n - Changing a class from concrete to abstract (or vice versa) is MAJOR\n - Changing the checked exceptions declared in a throws clause is MAJOR\n - Removing a public constructor or changing its parameter list is MAJOR\n - Removing an interface that a public class implements is MAJOR\n - Changing generic type parameters on a public class (e.g. Foo<T> to Foo<T, U>) is MAJOR\n - Moving a public class to a different package without re-exporting is MAJOR\n - Narrowing a parameter type (e.g. Object to String) is MAJOR\n - Making a non-final class final is MAJOR (breaks subclassing)\n - Changing the type of a builder method parameter is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new overloaded methods is MINOR\n - Adding new public classes or interfaces is MINOR\n - Adding new optional builder methods is MINOR\n - Adding new enum values when NOT used in exhaustive switch statements is MINOR\n - Adding new optional fields to request objects is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new static utility methods is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, retries) is MINOR\n - Widening a parameter type (e.g. String to Object) is MINOR\n - Adding default methods to interfaces (Java 8+) is MINOR\n - Deprecating (but not removing) public APIs with @Deprecated is MINOR\n\n PATCH (no API surface change):\n - Changes to package-private or private methods are PATCH\n - Changes to annotations (other than public API annotations), Javadoc, or formatting are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring OkHttp/HttpClient internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in build.gradle/pom.xml is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization logic (Jackson/Gson config) that preserves public types is PATCH\n - Changes to test files, CI configuration, or build scripts are PATCH\n\n {% elif language == "go" %}\n Language-specific breaking change rules for Go:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming an exported function, method, or type is always MAJOR\n - Making a response field a pointer type (e.g. string to *string) is MAJOR (callers must dereference)\n - Changing a function signature (adding/removing parameters or return values) is MAJOR (Go has no overloading)\n - Removing or renaming an exported struct field is MAJOR\n - Changing the type of an exported struct field is MAJOR\n - Removing or renaming an exported constant or variable is MAJOR\n - Changing an interface by adding methods is MAJOR (all implementations must add the method)\n - Removing a method from an interface is MAJOR (callers using that method break)\n - Changing a function\'s return type(s) is MAJOR (Go is strict about return types)\n - Changing a variadic parameter to non-variadic (or vice versa) is MAJOR\n - Moving a type/function to a different package without aliasing in the original is MAJOR\n - Changing the receiver type of a method (value receiver to pointer receiver changes method set) is MAJOR\n - Changing an exported error variable\'s type or value is MAJOR (callers using errors.Is break)\n\n MINOR (backward-compatible additions):\n - Adding new exported functions, methods, or types is MINOR\n - New enum-like constants are MINOR (Go enums are not exhaustive by default)\n - Adding new fields to a struct is MINOR (existing code still compiles, zero-value initialization)\n - Making a response field optional (pointer) is usually MINOR if the field was already a struct field\n - Adding new optional function parameters via functional options pattern is MINOR\n - Adding new interface types is MINOR\n - Adding new error types/variables is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOption functions is MINOR\n - Widening a return type from a concrete type to an interface is MINOR (if interface is satisfied)\n - Adding new methods to a concrete type (does not break interface implementations) is MINOR\n\n PATCH (no API surface change):\n - Changes to unexported (lowercase) functions or types are PATCH\n - Changes to go.mod dependencies, import reordering, or formatting are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring http.Client internals without changing observable defaults or behavior is PATCH\n - Updating serialization/deserialization logic (JSON tags, encoding) that preserves identical output is PATCH\n - Refactoring internal implementation without changing exported signatures is PATCH\n - Changes to *_test.go files, Makefile, or CI configuration are PATCH\n - Updating comments, godoc, or code formatting (gofmt) is PATCH\n\n {% elif language == "ruby" %}\n Language-specific breaking change rules for Ruby:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method is MAJOR (callers get NoMethodError)\n - Adding a new required positional parameter is MAJOR\n - Removing a method parameter is MAJOR (callers passing that argument get ArgumentError)\n - Changing the order of positional parameters is MAJOR\n - Removing or renaming a public class or module is MAJOR (callers get NameError)\n - Changing a method from instance to class method (or vice versa) is MAJOR\n - Changing the return type in a breaking way (e.g. returning nil where an object was expected and callers chain methods) is MAJOR\n - Removing a public constant is MAJOR\n - Changing exception types raised by a method is MAJOR (callers rescuing specific exceptions break)\n\n MINOR (backward-compatible additions):\n - Making a response field optional is usually MINOR (Ruby uses nil propagation; callers rarely type-check)\n - New enum values are MINOR (unknown values are handled gracefully)\n - Adding new optional keyword parameters (with defaults) is MINOR\n - Adding new public methods or classes is MINOR\n - Adding new optional fields to response/request objects is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, max_retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n - Adding new modules or mixins is MINOR\n\n PATCH (no API surface change):\n - Changes to private methods are PATCH\n - Gemspec metadata, comment, or formatting changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring Faraday/Net::HTTP internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Gemfile/gemspec is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, Rakefile, or CI configuration are PATCH\n\n {% elif language == "csharp" %}\n Language-specific breaking change rules for C#:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, property, or interface is always MAJOR\n - Making a response field nullable (e.g. T to T?) is MAJOR (callers must handle null checks)\n - New enum values are MAJOR if the SDK generates exhaustive switch expressions\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR\n - Removing or changing a public constant or static readonly field is MAJOR\n - Changing a class from non-sealed to sealed (or abstract to concrete) is MAJOR\n - Changing the base class of a public class is MAJOR\n - Removing an interface implementation from a public class is MAJOR\n - Changing generic type constraints on a public class or method is MAJOR\n - Moving a public type to a different namespace without type forwarding is MAJOR\n - Changing property from read-write to read-only (removing setter) is MAJOR\n - Changing async method to sync (Task<T> to T) or vice versa is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public classes, interfaces, or methods is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new overloaded methods is MINOR\n - Adding new enum values when NOT used in exhaustive switch expressions is MINOR\n - Adding new optional properties to request objects is MINOR\n - Adding new exception types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. Timeout, MaxRetries) is MINOR\n - Adding new extension methods is MINOR\n - Deprecating (but not removing) public APIs with [Obsolete] is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - XML doc comments, formatting, or namespace reorganization are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring HttpClient internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in .csproj is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (System.Text.Json/Newtonsoft) config that preserves public types is PATCH\n - Changes to test files, .sln, or CI configuration are PATCH\n\n {% elif language == "php" %}\n Language-specific breaking change rules for PHP:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method or class is always MAJOR\n - Changing a method signature (adding required parameters) is MAJOR\n - Removing a method parameter is MAJOR\n - Changing the type declaration of a parameter to an incompatible type is MAJOR\n - Removing or renaming a public constant is MAJOR\n - Changing a class from non-final to final is MAJOR (breaks extension)\n - Removing an interface implementation from a public class is MAJOR\n - Changing the return type declaration to an incompatible type is MAJOR\n - Moving a class to a different namespace without aliasing is MAJOR\n - Changing exception types thrown by a method is MAJOR\n\n MINOR (backward-compatible additions):\n - Making a response field nullable is MINOR in most cases (PHP is dynamically typed)\n - Adding new optional parameters (with defaults) is MINOR\n - Adding new public classes or methods is MINOR\n - New enum cases are usually MINOR (PHP enums are not typically used in exhaustive matches)\n - Adding new optional fields to request/response objects is MINOR\n - Adding new exception classes is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new traits or interfaces is MINOR\n - Adding new RequestOptions fields is MINOR\n - Deprecating (but not removing) public APIs is MINOR\n\n PATCH (no API surface change):\n - Changes to private/protected methods are PATCH\n - PHPDoc, formatting, or composer.json metadata changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring Guzzle/cURL internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in composer.json is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, phpunit.xml, or CI configuration are PATCH\n\n {% elif language == "swift" %}\n Language-specific breaking change rules for Swift:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method, property, or type is always MAJOR\n - Making a response field optional (T to T?) is MAJOR (callers must unwrap with if-let/guard)\n - New enum cases are MAJOR (Swift switch statements must be exhaustive unless using default)\n - Adding a new required parameter to a public method is MAJOR\n - Changing the type of a public property is MAJOR\n - Removing or changing a public protocol requirement is MAJOR\n - Removing protocol conformance from a public type is MAJOR\n - Changing a struct to a class (or vice versa) is MAJOR (value vs reference semantics)\n - Making a public initializer failable (init to init?) or vice versa is MAJOR\n - Changing the associated values of an enum case is MAJOR\n - Removing a public typealias is MAJOR\n - Changing access level from public to internal/private is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public types, methods, or properties is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new enum cases when callers use default in switch is MINOR\n - Adding new protocol extensions with default implementations is MINOR\n - Adding new optional fields to request/response structs is MINOR\n - Adding new error types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new convenience initializers is MINOR\n - Deprecating (but not removing) public APIs with @available(*, deprecated) is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - Formatting, comments, or documentation changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring URLSession internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Package.swift is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, xcconfig, or CI configuration are PATCH\n\n {% elif language == "rust" %}\n Language-specific breaking change rules for Rust:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public function, struct, enum, or trait is always MAJOR\n - Making a response field optional (T to Option<T>) is MAJOR (callers must handle the Option)\n - New enum variants are MAJOR (Rust match statements must be exhaustive unless using _ wildcard)\n - Adding a new required field to a public struct is MAJOR (unless #[non_exhaustive])\n - Removing a public trait implementation is MAJOR\n - Changing a function\'s return type is MAJOR\n - Adding a required method to a public trait is MAJOR (all implementations must add it)\n - Changing the type of a public struct field is MAJOR\n - Removing or renaming a public module is MAJOR\n - Making a public type private (pub to pub(crate) or removing pub) is MAJOR\n - Changing a struct from non-exhaustive to exhaustive construction (removing .. Default::default()) is MAJOR\n - Changing generic type parameters or their bounds on public types is MAJOR\n - Changing from Result<T, E1> to Result<T, E2> where E2 is a different error type is MAJOR\n - Removing a public constant or static is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public functions, structs, or enums is MINOR\n - Adding new optional fields to #[non_exhaustive] structs is MINOR\n - Adding new enum variants to #[non_exhaustive] enums is MINOR\n - Adding new trait implementations for existing types is MINOR\n - Adding new public constants or statics is MINOR\n - Adding new methods to existing impl blocks is MINOR\n - Adding new error types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new optional builder methods is MINOR\n - Deprecating (but not removing) public APIs with #[deprecated] is MINOR\n\n PATCH (no API surface change):\n - Changes to pub(crate) or private items are PATCH\n - Cargo.toml metadata, formatting, or comment changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring reqwest/hyper internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Cargo.toml is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (serde) config that preserves public types is PATCH\n - Changes to test files, build.rs, or CI configuration are PATCH\n\n {% elif language == "kotlin" %}\n Language-specific breaking change rules for Kotlin:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public function, class, or property is always MAJOR\n - Making a response field nullable (T to T?) is MAJOR (callers must handle null safety operators)\n - New enum values are MAJOR if used in when() expressions without else branch\n - Adding a new required parameter to a public function is MAJOR\n - Changing a method\'s return type is MAJOR\n - Removing or changing a public constant (const val / companion object val) is MAJOR\n - Changing a class from open to final (or data class to regular class) is MAJOR\n - Removing an interface implementation from a public class is MAJOR\n - Changing generic type parameters or their variance (in/out) on public types is MAJOR\n - Moving a public class to a different package without type aliasing is MAJOR\n - Changing a property from var to val (or removing a setter) is MAJOR\n - Changing a suspend function to non-suspend (or vice versa) is MAJOR\n - Changing sealed class/interface hierarchy (removing subclasses) is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public classes, functions, or extension functions is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new enum values when callers use else in when() is MINOR\n - Adding new optional properties to data classes is MINOR\n - Adding new exception types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new sealed class/interface subtypes is MINOR (if callers have else branch)\n - Deprecating (but not removing) public APIs with @Deprecated is MINOR\n - Adding new companion object functions is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - KDoc, formatting, or build.gradle changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring OkHttp internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in build.gradle.kts is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (kotlinx.serialization/Moshi) config that preserves public types is PATCH\n - Changes to test files or CI configuration are PATCH\n\n {% else %}\n Language-specific breaking change rules (language: {{ language }}):\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or function is always MAJOR\n - Making a response field optional is MAJOR in statically-typed languages (TypeScript, Java, C#, Swift, Rust, Kotlin, Go), usually MINOR in dynamically-typed ones (Python, Ruby, PHP)\n - New enum values are MAJOR if the language enforces exhaustive matching (TypeScript, Java, C#, Swift, Rust), MINOR otherwise\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR\n - Changing the type of an existing field/property is MAJOR\n - Removing or changing public constants is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public APIs (classes, methods, functions) is MINOR\n - Adding new optional parameters is MINOR\n - Adding new optional fields to request/response objects is MINOR\n - Adding new error/exception types is MINOR\n - Deprecating (but not removing) public APIs is MINOR\n\n PATCH (no API surface change):\n - Internal/private changes are PATCH\n - Formatting, documentation, or comment changes are PATCH\n - Dependency version updates are PATCH\n - SDK version header updates are PATCH\n - Refactoring retry/timeout internals without changing observable defaults or behavior is PATCH\n - Refactoring internals without changing public signatures is PATCH\n {% endif %}\n\n Apply these patterns to the diff below. When in doubt between MINOR and PATCH,\n prefer MINOR. When in doubt between MAJOR and MINOR, examine whether existing\n callers would break without any code changes on their side.\n\n Message Format (use this exact structure):\n ```\n <type>: <short summary>\n\n <detailed description of what changed and why it matters>\n\n Key changes:\n - <change 1>\n - <change 2>\n - <change 3>\n ```\n\n Message Guidelines:\n - Use conventional commit types: feat, fix, refactor, docs, chore, test, style, perf\n - Keep the summary line under 72 characters\n - Write in present tense imperative mood ("add" not "added" or "adds")\n - For breaking changes: include migration instructions in the detailed description\n - For new features: highlight new capabilities in the key changes\n - For PATCH: describe the fix or improvement\n - For NO_CHANGE: use type "chore" and state that no functional changes were made\n - Be specific and action-oriented\n - Do not use "Fern regeneration" in commit messages - use "SDK regeneration" instead\n - NEVER include the literal version "0.0.0-fern-placeholder" in the commit message - if you see this placeholder\n in the diff, describe changes generically (e.g., "added X-Fern-SDK-Version header")\n - The previous version is provided for context only. Do not include it\n literally in the commit message summary line.\n\n {% if prior_changelog %}\n Prior changelog entries (for style reference):\n ---\n {{prior_changelog}}\n ---\n Match the tone and format of these entries in your commit message.\n {% endif %}\n\n {% if spec_commit_message %}\n The API spec change that triggered this SDK generation had the following commit message:\n "{{spec_commit_message}}"\n Use this as a hint for understanding the intent of the change, but always verify\n against the actual diff below. The commit message may be vague or inaccurate.\n {% endif %}\n\n Previous version: {{previous_version}}\n SDK language: {{language}}\n\n Git Diff:\n ---\n {{diff}}\n ---\n\n Changelog Entry Guidelines:\n - Write for SDK consumers, not engineers reading the source code\n - MAJOR: explain what broke and how to migrate ("The `getUser` method has been\n removed. Replace calls with `fetchUser(id)` which returns the same type.")\n - MINOR: describe the new capability ("New `createPayment()` method available\n on `PaymentsClient`.")\n - PATCH: leave empty string \u2014 patch changes don\'t warrant changelog entries\n - Do not use conventional commit prefixes (no "feat:", "fix:", etc.)\n - Write in third person ("The SDK now supports..." not "Add support for...")\n - IMPORTANT: Wrap any type references containing angle brackets in backticks\n to prevent MDX parsing issues. For example, write `Optional<String>` not\n Optional<String>, and `Map<String, Object>` not Map<String, Object>.\n\n Remember again that YOU MUST return a structured JSON response with these four fields:\n - message: A git commit message formatted like the example previously provided\n - changelog_entry: A user-facing release note (empty string for PATCH)\n - version_bump: One of: MAJOR, MINOR, PATCH, or NO_CHANGE\n - version_bump_reason: One sentence explaining WHY this bump level was chosen.\n For MAJOR, name the specific breaking symbol(s) and explain why existing callers break.\n For MINOR, name the new capability added.\n For PATCH, describe what was fixed or improved.\n For NO_CHANGE, say "No functional changes detected."\n Example: "MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`, breaking existing callers."\n "#\n}\n\nclass ConsolidateChangelogResponse {\n consolidated_changelog string\n @description("CHANGELOG.md entry in Keep a Changelog format. Group under ### Breaking Changes, ### Added, ### Changed, ### Fixed. Bold symbol names, one tight sentence per bullet. Prose only, no code fences. Append migration action inline for breaking changes.")\n\n pr_description string\n @description("PR description with ## Breaking Changes section (if any) containing ### per breaking change with Before/After code fences and Migration line, then ## What\'s New section summarizing features in prose paragraphs grouped by theme. Do NOT list every class individually \u2014 summarize repetitive changes as a single entry.")\n\n version_bump_reason string\n @description("One sentence explaining WHY the overall version bump was chosen. For MAJOR: name the specific breaking symbol(s). For MINOR: name the new capability. For PATCH: describe the fix. Example: \'MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`.\'")\n}\n\nfunction ConsolidateChangelog(\n raw_entries: string @description("Newline-separated raw changelog entries from chunked diff analysis"),\n version_bump: string @description("The overall version bump: MAJOR, MINOR, or PATCH"),\n language: string @description("The SDK programming language, e.g. \'typescript\', \'python\', \'java\'")\n) -> ConsolidateChangelogResponse {\n client DefaultClient\n\n prompt #"\n You are a technical writer formatting release notes for a {{language}} SDK.\n\n The raw change notes below are noisy and repetitive \u2014 many bullets describe the same\n change across different packages. Deduplicate aggressively: if the same feature appears\n multiple times, merge into one entry.\n\n Raw changelog entries:\n ---\n {{raw_entries}}\n ---\n\n Overall version bump: {{version_bump}}\n\n Produce three outputs:\n\n ---\n\n ## 1. CHANGELOG.md entry (Keep a Changelog format)\n\n - Group under: `### Breaking Changes`, `### Added`, `### Changed`, `### Fixed`\n - Only include sections with entries\n - **Bold the symbol name** first, then one tight sentence for SDK consumers\n - No code fences \u2014 prose only\n - For breaking changes, append the migration action inline\n\n ## 2. PR Description\n\n - `## Breaking Changes` section at top (if any)\n - One `###` per breaking change with **Before/After** code fences and a **Migration:** line\n - `## What\'s New` section summarizing added/changed features in prose paragraphs,\n grouped by theme (e.g. logging, streaming, pagination, builder improvements)\n - Do NOT list every class that got the same method \u2014 summarize as a single entry\n\n ## 3. Version Bump Reason\n\n - One sentence explaining WHY the overall version bump ({{version_bump}}) was chosen\n - For MAJOR: name the specific breaking symbol(s) and explain why existing callers break\n - For MINOR: name the new capability added\n - For PATCH: describe what was fixed or improved\n - Example: "MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`, breaking existing callers."\n\n ---\n\n {{ ctx.output_format }}\n "#\n}\n',
906427
+ "diff_analyzer.baml": '// SDK Diff Analyzer\n// Analyzes git diffs of SDK code and produces semantic commit messages and version bumps\n\nenum VersionBump {\n MAJOR\n MINOR\n PATCH\n NO_CHANGE\n}\n\nclass AnalyzeCommitDiffRequest {\n diff string @description("The git diff to analyze for generating a commit message")\n}\n\nclass AnalyzeCommitDiffResponse {\n message string\n @description("Developer-facing git commit message. Use conventional commit format. Reference specific code symbols (function names, class names). Keep summary under 72 chars.")\n\n changelog_entry string\n @description("User-facing release note for CHANGELOG.md and GitHub Releases. Describe the impact on SDK consumers, not implementation details. Include migration instructions for MAJOR. Use plain prose, not conventional commit format. Empty string for PATCH.")\n\n version_bump VersionBump\n @description("The recommended semantic version bump: MAJOR for breaking changes, MINOR for new features, PATCH for bug fixes and other changes, NO_CHANGE for empty diffs")\n\n version_bump_reason string\n @description("One sentence explaining WHY this version bump was chosen. For MAJOR: name the specific breaking symbol(s). For MINOR: name the new capability. For PATCH: describe the fix. For NO_CHANGE: \'No functional changes detected.\' Example: \'MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`.\'")\n}\n\n// Main function that analyzes SDK diffs\nfunction AnalyzeSdkDiff(\n diff: string @description("The git diff to analyze"),\n language: string @description("The SDK programming language, e.g. \'typescript\', \'python\', \'java\'"),\n previous_version: string @description("The current published version before this change, e.g. \'1.2.3\'"),\n prior_changelog: string @description("The last 3 changelog entries for this SDK, empty string if none. Use this to match the existing commit message style and understand the versioning pattern."),\n spec_commit_message: string @description("The commit message from the API spec repository that triggered this SDK generation. Use as a hint for the intent of the change, but verify against the actual diff. Empty string if unavailable.")\n) -> AnalyzeCommitDiffResponse {\n client DefaultClient\n\n prompt #"\n You are an expert software engineer analyzing changes to generate semantic commit messages.\n\n Analyze the provided git diff and return a structured response with these fields:\n - message: A git commit message formatted like the example below\n - version_bump: One of: MAJOR, MINOR, PATCH, or NO_CHANGE\n\n Version Bump Guidelines:\n - MAJOR: Breaking changes (removed/renamed functions, changed signatures, removed parameters)\n - MINOR: New features that are backward compatible (new functions, new optional parameters).\n Also MINOR: behavioral changes invisible to the public API surface that still affect consumers:\n - Changed HTTP status code handling (e.g. 404 now throws instead of returning null)\n - Changed default parameter values (timeout, retry count, page size, base URL)\n - Changed serialization behavior (date formats, null handling, field ordering)\n - Changed error message text that consumers may depend on\n - Changed HTTP header names or values sent to the server\n - Changed retry or backoff behavior (different retry counts, delay strategies)\n - PATCH: Bug fixes, documentation, internal refactoring with no observable behavioral change\n - NO_CHANGE: The diff is empty\n\n --- Examples ---\n\n Examples of correct classifications:\n\n --- MAJOR: removed exported TypeScript function ---\n diff --git a/src/api/client.ts b/src/api/client.ts\n -export async function getUser(id: string): Promise<User> {\n - return this.request("GET", `/users/${id}`);\n -}\n version_bump: MAJOR\n reason: Existing callers of getUser() will get a compile error.\n\n --- MAJOR: removed Python public method ---\n diff --git a/vital/client.py b/vital/client.py\n - def get_user(self, user_id: str) -> User:\n - return self._request("GET", f"/users/{user_id}")\n version_bump: MAJOR\n reason: Existing callers crash with AttributeError.\n\n --- MINOR: new optional TypeScript parameter ---\n diff --git a/src/api/client.ts b/src/api/client.ts\n -async createUser(name: string): Promise<User>\n +async createUser(name: string, role?: UserRole): Promise<User>\n version_bump: MINOR\n reason: Existing callers unaffected \u2014 new parameter is optional.\n\n --- MINOR: new Java public method ---\n diff --git a/src/.../UsersClient.java b/src/.../UsersClient.java\n + public CompletableFuture<User> getUserAsync(String userId) {\n + return this.httpClient.sendAsync(...);\n + }\n version_bump: MINOR\n reason: New capability added, nothing removed or changed.\n\n --- MINOR: changed default retry count ---\n diff --git a/src/core/http_client.py b/src/core/http_client.py\n -MAX_RETRIES = 3\n +MAX_RETRIES = 5\n version_bump: MINOR\n reason: Changed default retry count \u2014 existing consumers will experience different retry behavior.\n\n --- PATCH: Go import reorganization ---\n diff --git a/client.go b/client.go\n -import "fmt"\n -import "net/http"\n +import (\n + "fmt"\n + "net/http"\n +)\n version_bump: PATCH\n reason: Formatting change only, no functional difference.\n\n --- End Examples ---\n\n {% if language == "typescript" %}\n Language-specific breaking change rules for TypeScript:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, function, or exported symbol is MAJOR\n - Making a response field optional is MAJOR (type changes from T to T | undefined, breaking existing property access without null checks)\n - Changing a method return type (e.g. Promise<T> to Promise<T | undefined>, or T to T | null) is MAJOR\n - New enum values are MAJOR if the SDK generates exhaustive switch/if-else chains (callers get compile errors on unhandled cases)\n - Changing a union type (adding/removing variants) is MAJOR if callers use exhaustive type narrowing or discriminated unions\n - Adding a new required property to a request/input type is MAJOR (existing callers won\'t compile)\n - Removing or renaming an exported type, interface, or type alias is MAJOR\n - Changing the type of an existing property (e.g. string to number, or string to string[]) is MAJOR\n - Changing a generic type parameter constraint (e.g. <T extends Foo> to <T extends Bar>) is MAJOR\n - Converting a synchronous method to async (or vice versa) is MAJOR (changes return type to Promise<T>)\n - Removing a default export or switching between default and named exports is MAJOR\n - Changing the structure of a discriminated union (e.g. changing the discriminant field name) is MAJOR\n - Removing or renaming environment/server URL constants is MAJOR\n - Changing the constructor signature of a client class (adding required params) is MAJOR\n - Narrowing a parameter type (e.g. string | number to string) is MAJOR (callers passing number break)\n\n MINOR (backward-compatible additions):\n - Adding a new optional parameter to a function is MINOR\n - Adding new exported types, interfaces, or classes is MINOR\n - Adding new methods to an existing client class is MINOR\n - Adding new optional properties to request types is MINOR\n - Adding new enum values when NOT used in exhaustive checks is MINOR\n - Adding new environment/server URL constants is MINOR\n - Widening a parameter type (e.g. string to string | number) is MINOR\n - Adding new re-exports from index files is MINOR\n - Adding new error types or exception classes is MINOR\n - Adding new RequestOptions fields (e.g. timeout, retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n\n PATCH (no API surface change):\n - Changes to internal/private modules (core/, _internal/, utils/) are PATCH\n - Reordering imports, formatting, or comment changes are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring HTTP client internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in package.json is PATCH\n - Adding or modifying JSDoc/TSDoc comments is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to .npmignore, tsconfig.json, or build configuration are PATCH\n - Updating serialization/deserialization logic that preserves the same public types is PATCH\n\n {% elif language == "python" %}\n Language-specific breaking change rules for Python:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or function is always MAJOR\n - Adding a new required parameter to a public method is MAJOR (callers get TypeError)\n - Renaming a parameter in a public method is MAJOR if callers use keyword arguments\n - Removing a parameter from a public method signature is MAJOR\n - Changing the type of a parameter from one concrete type to an incompatible one is MAJOR\n - Changing exception types raised by a method (callers catching specific exceptions break) is MAJOR\n - Removing or renaming a public module or subpackage is MAJOR (import statements break)\n - Moving a public class/function to a different module without re-exporting from the original is MAJOR\n - Changing a class from inheriting one base to another when callers use isinstance() checks is MAJOR\n - Removing a public class attribute or property is MAJOR\n\n MINOR (backward-compatible additions):\n - Making a response field optional is usually MINOR (Python uses None propagation; callers rarely type-check strictly)\n - New enum values are MINOR (unknown values are handled gracefully with string fallbacks)\n - Changing a return type from a concrete type to Optional is MINOR (duck typing absorbs this)\n - Adding new public methods, classes, or modules is MINOR\n - Adding new optional parameters (with defaults) is MINOR\n - Adding new optional fields to Pydantic models is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new class attributes or properties is MINOR\n - Adding new type overloads (@overload decorator) is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, max_retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n - Widening a type annotation (e.g. str to Union[str, int]) is MINOR\n\n PATCH (no API surface change):\n - Changes to private methods (prefixed with _) are PATCH\n - Changes to type hints only (no runtime effect) are PATCH\n - Reformatting, docstring updates, or comment changes are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) are PATCH\n - Refactoring httpx/requests client internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in pyproject.toml/setup.py is PATCH\n - Updating serialization/deserialization logic that preserves the same public types is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to __init__.py that don\'t alter public re-exports are PATCH\n - Changes to conftest.py, test files, or CI configuration are PATCH\n\n {% elif language == "java" %}\n Language-specific breaking change rules for Java:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or interface is always MAJOR\n - Making a response field optional (e.g. T to Optional<T>) is MAJOR (callers must handle Optional unwrapping)\n - New enum values are MAJOR if the SDK generates exhaustive switch statements\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR (even if compatible at runtime, recompilation fails)\n - Removing or changing a public static final constant is MAJOR\n - Changing a class from concrete to abstract (or vice versa) is MAJOR\n - Changing the checked exceptions declared in a throws clause is MAJOR\n - Removing a public constructor or changing its parameter list is MAJOR\n - Removing an interface that a public class implements is MAJOR\n - Changing generic type parameters on a public class (e.g. Foo<T> to Foo<T, U>) is MAJOR\n - Moving a public class to a different package without re-exporting is MAJOR\n - Narrowing a parameter type (e.g. Object to String) is MAJOR\n - Making a non-final class final is MAJOR (breaks subclassing)\n - Changing the type of a builder method parameter is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new overloaded methods is MINOR\n - Adding new public classes or interfaces is MINOR\n - Adding new optional builder methods is MINOR\n - Adding new enum values when NOT used in exhaustive switch statements is MINOR\n - Adding new optional fields to request objects is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new static utility methods is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, retries) is MINOR\n - Widening a parameter type (e.g. String to Object) is MINOR\n - Adding default methods to interfaces (Java 8+) is MINOR\n - Deprecating (but not removing) public APIs with @Deprecated is MINOR\n\n PATCH (no API surface change):\n - Changes to package-private or private methods are PATCH\n - Changes to annotations (other than public API annotations), Javadoc, or formatting are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring OkHttp/HttpClient internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in build.gradle/pom.xml is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization logic (Jackson/Gson config) that preserves public types is PATCH\n - Changes to test files, CI configuration, or build scripts are PATCH\n\n {% elif language == "go" %}\n Language-specific breaking change rules for Go:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming an exported function, method, or type is always MAJOR\n - Making a response field a pointer type (e.g. string to *string) is MAJOR (callers must dereference)\n - Changing a function signature (adding/removing parameters or return values) is MAJOR (Go has no overloading)\n - Removing or renaming an exported struct field is MAJOR\n - Changing the type of an exported struct field is MAJOR\n - Removing or renaming an exported constant or variable is MAJOR\n - Changing an interface by adding methods is MAJOR (all implementations must add the method)\n - Removing a method from an interface is MAJOR (callers using that method break)\n - Changing a function\'s return type(s) is MAJOR (Go is strict about return types)\n - Changing a variadic parameter to non-variadic (or vice versa) is MAJOR\n - Moving a type/function to a different package without aliasing in the original is MAJOR\n - Changing the receiver type of a method (value receiver to pointer receiver changes method set) is MAJOR\n - Changing an exported error variable\'s type or value is MAJOR (callers using errors.Is break)\n\n MINOR (backward-compatible additions):\n - Adding new exported functions, methods, or types is MINOR\n - New enum-like constants are MINOR (Go enums are not exhaustive by default)\n - Adding new fields to a struct is MINOR (existing code still compiles, zero-value initialization)\n - Making a response field optional (pointer) is usually MINOR if the field was already a struct field\n - Adding new optional function parameters via functional options pattern is MINOR\n - Adding new interface types is MINOR\n - Adding new error types/variables is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOption functions is MINOR\n - Widening a return type from a concrete type to an interface is MINOR (if interface is satisfied)\n - Adding new methods to a concrete type (does not break interface implementations) is MINOR\n\n PATCH (no API surface change):\n - Changes to unexported (lowercase) functions or types are PATCH\n - Changes to go.mod dependencies, import reordering, or formatting are PATCH\n - Updating SDK version headers (X-Fern-SDK-Version, User-Agent) is PATCH\n - Refactoring http.Client internals without changing observable defaults or behavior is PATCH\n - Updating serialization/deserialization logic (JSON tags, encoding) that preserves identical output is PATCH\n - Refactoring internal implementation without changing exported signatures is PATCH\n - Changes to *_test.go files, Makefile, or CI configuration are PATCH\n - Updating comments, godoc, or code formatting (gofmt) is PATCH\n\n {% elif language == "ruby" %}\n Language-specific breaking change rules for Ruby:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method is MAJOR (callers get NoMethodError)\n - Adding a new required positional parameter is MAJOR\n - Removing a method parameter is MAJOR (callers passing that argument get ArgumentError)\n - Changing the order of positional parameters is MAJOR\n - Removing or renaming a public class or module is MAJOR (callers get NameError)\n - Changing a method from instance to class method (or vice versa) is MAJOR\n - Changing the return type in a breaking way (e.g. returning nil where an object was expected and callers chain methods) is MAJOR\n - Removing a public constant is MAJOR\n - Changing exception types raised by a method is MAJOR (callers rescuing specific exceptions break)\n\n MINOR (backward-compatible additions):\n - Making a response field optional is usually MINOR (Ruby uses nil propagation; callers rarely type-check)\n - New enum values are MINOR (unknown values are handled gracefully)\n - Adding new optional keyword parameters (with defaults) is MINOR\n - Adding new public methods or classes is MINOR\n - Adding new optional fields to response/request objects is MINOR\n - Adding new exception/error classes is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. timeout, max_retries) is MINOR\n - Deprecating (but not removing) a public API is MINOR\n - Adding new modules or mixins is MINOR\n\n PATCH (no API surface change):\n - Changes to private methods are PATCH\n - Gemspec metadata, comment, or formatting changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring Faraday/Net::HTTP internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Gemfile/gemspec is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, Rakefile, or CI configuration are PATCH\n\n {% elif language == "csharp" %}\n Language-specific breaking change rules for C#:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, property, or interface is always MAJOR\n - Making a response field nullable (e.g. T to T?) is MAJOR (callers must handle null checks)\n - New enum values are MAJOR if the SDK generates exhaustive switch expressions\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR\n - Removing or changing a public constant or static readonly field is MAJOR\n - Changing a class from non-sealed to sealed (or abstract to concrete) is MAJOR\n - Changing the base class of a public class is MAJOR\n - Removing an interface implementation from a public class is MAJOR\n - Changing generic type constraints on a public class or method is MAJOR\n - Moving a public type to a different namespace without type forwarding is MAJOR\n - Changing property from read-write to read-only (removing setter) is MAJOR\n - Changing async method to sync (Task<T> to T) or vice versa is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public classes, interfaces, or methods is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new overloaded methods is MINOR\n - Adding new enum values when NOT used in exhaustive switch expressions is MINOR\n - Adding new optional properties to request objects is MINOR\n - Adding new exception types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields (e.g. Timeout, MaxRetries) is MINOR\n - Adding new extension methods is MINOR\n - Deprecating (but not removing) public APIs with [Obsolete] is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - XML doc comments, formatting, or namespace reorganization are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring HttpClient internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in .csproj is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (System.Text.Json/Newtonsoft) config that preserves public types is PATCH\n - Changes to test files, .sln, or CI configuration are PATCH\n\n {% elif language == "php" %}\n Language-specific breaking change rules for PHP:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method or class is always MAJOR\n - Changing a method signature (adding required parameters) is MAJOR\n - Removing a method parameter is MAJOR\n - Changing the type declaration of a parameter to an incompatible type is MAJOR\n - Removing or renaming a public constant is MAJOR\n - Changing a class from non-final to final is MAJOR (breaks extension)\n - Removing an interface implementation from a public class is MAJOR\n - Changing the return type declaration to an incompatible type is MAJOR\n - Moving a class to a different namespace without aliasing is MAJOR\n - Changing exception types thrown by a method is MAJOR\n\n MINOR (backward-compatible additions):\n - Making a response field nullable is MINOR in most cases (PHP is dynamically typed)\n - Adding new optional parameters (with defaults) is MINOR\n - Adding new public classes or methods is MINOR\n - New enum cases are usually MINOR (PHP enums are not typically used in exhaustive matches)\n - Adding new optional fields to request/response objects is MINOR\n - Adding new exception classes is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new traits or interfaces is MINOR\n - Adding new RequestOptions fields is MINOR\n - Deprecating (but not removing) public APIs is MINOR\n\n PATCH (no API surface change):\n - Changes to private/protected methods are PATCH\n - PHPDoc, formatting, or composer.json metadata changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring Guzzle/cURL internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in composer.json is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, phpunit.xml, or CI configuration are PATCH\n\n {% elif language == "swift" %}\n Language-specific breaking change rules for Swift:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public method, property, or type is always MAJOR\n - Making a response field optional (T to T?) is MAJOR (callers must unwrap with if-let/guard)\n - New enum cases are MAJOR (Swift switch statements must be exhaustive unless using default)\n - Adding a new required parameter to a public method is MAJOR\n - Changing the type of a public property is MAJOR\n - Removing or changing a public protocol requirement is MAJOR\n - Removing protocol conformance from a public type is MAJOR\n - Changing a struct to a class (or vice versa) is MAJOR (value vs reference semantics)\n - Making a public initializer failable (init to init?) or vice versa is MAJOR\n - Changing the associated values of an enum case is MAJOR\n - Removing a public typealias is MAJOR\n - Changing access level from public to internal/private is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public types, methods, or properties is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new enum cases when callers use default in switch is MINOR\n - Adding new protocol extensions with default implementations is MINOR\n - Adding new optional fields to request/response structs is MINOR\n - Adding new error types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new convenience initializers is MINOR\n - Deprecating (but not removing) public APIs with @available(*, deprecated) is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - Formatting, comments, or documentation changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring URLSession internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Package.swift is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Changes to test files, xcconfig, or CI configuration are PATCH\n\n {% elif language == "rust" %}\n Language-specific breaking change rules for Rust:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public function, struct, enum, or trait is always MAJOR\n - Making a response field optional (T to Option<T>) is MAJOR (callers must handle the Option)\n - New enum variants are MAJOR (Rust match statements must be exhaustive unless using _ wildcard)\n - Adding a new required field to a public struct is MAJOR (unless #[non_exhaustive])\n - Removing a public trait implementation is MAJOR\n - Changing a function\'s return type is MAJOR\n - Adding a required method to a public trait is MAJOR (all implementations must add it)\n - Changing the type of a public struct field is MAJOR\n - Removing or renaming a public module is MAJOR\n - Making a public type private (pub to pub(crate) or removing pub) is MAJOR\n - Changing a struct from non-exhaustive to exhaustive construction (removing .. Default::default()) is MAJOR\n - Changing generic type parameters or their bounds on public types is MAJOR\n - Changing from Result<T, E1> to Result<T, E2> where E2 is a different error type is MAJOR\n - Removing a public constant or static is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public functions, structs, or enums is MINOR\n - Adding new optional fields to #[non_exhaustive] structs is MINOR\n - Adding new enum variants to #[non_exhaustive] enums is MINOR\n - Adding new trait implementations for existing types is MINOR\n - Adding new public constants or statics is MINOR\n - Adding new methods to existing impl blocks is MINOR\n - Adding new error types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new optional builder methods is MINOR\n - Deprecating (but not removing) public APIs with #[deprecated] is MINOR\n\n PATCH (no API surface change):\n - Changes to pub(crate) or private items are PATCH\n - Cargo.toml metadata, formatting, or comment changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring reqwest/hyper internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in Cargo.toml is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (serde) config that preserves public types is PATCH\n - Changes to test files, build.rs, or CI configuration are PATCH\n\n {% elif language == "kotlin" %}\n Language-specific breaking change rules for Kotlin:\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public function, class, or property is always MAJOR\n - Making a response field nullable (T to T?) is MAJOR (callers must handle null safety operators)\n - New enum values are MAJOR if used in when() expressions without else branch\n - Adding a new required parameter to a public function is MAJOR\n - Changing a method\'s return type is MAJOR\n - Removing or changing a public constant (const val / companion object val) is MAJOR\n - Changing a class from open to final (or data class to regular class) is MAJOR\n - Removing an interface implementation from a public class is MAJOR\n - Changing generic type parameters or their variance (in/out) on public types is MAJOR\n - Moving a public class to a different package without type aliasing is MAJOR\n - Changing a property from var to val (or removing a setter) is MAJOR\n - Changing a suspend function to non-suspend (or vice versa) is MAJOR\n - Changing sealed class/interface hierarchy (removing subclasses) is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public classes, functions, or extension functions is MINOR\n - Adding new optional parameters (with default values) is MINOR\n - Adding new enum values when callers use else in when() is MINOR\n - Adding new optional properties to data classes is MINOR\n - Adding new exception types is MINOR\n - Adding new environment/server URL constants is MINOR\n - Adding new RequestOptions fields is MINOR\n - Adding new sealed class/interface subtypes is MINOR (if callers have else branch)\n - Deprecating (but not removing) public APIs with @Deprecated is MINOR\n - Adding new companion object functions is MINOR\n\n PATCH (no API surface change):\n - Changes to internal or private members are PATCH\n - KDoc, formatting, or build.gradle changes are PATCH\n - Updating SDK version headers is PATCH\n - Refactoring OkHttp internals without changing observable defaults or behavior is PATCH\n - Updating dependency versions in build.gradle.kts is PATCH\n - Refactoring internal implementation without changing public signatures is PATCH\n - Updating serialization/deserialization (kotlinx.serialization/Moshi) config that preserves public types is PATCH\n - Changes to test files or CI configuration are PATCH\n\n {% else %}\n Language-specific breaking change rules (language: {{ language }}):\n\n MAJOR (breaking):\n - Removing a required response field is always MAJOR\n - Removing or renaming a public class, method, or function is always MAJOR\n - Making a response field optional is MAJOR in statically-typed languages (TypeScript, Java, C#, Swift, Rust, Kotlin, Go), usually MINOR in dynamically-typed ones (Python, Ruby, PHP)\n - New enum values are MAJOR if the language enforces exhaustive matching (TypeScript, Java, C#, Swift, Rust), MINOR otherwise\n - Adding a new required parameter to a public method is MAJOR\n - Changing a method\'s return type is MAJOR\n - Changing the type of an existing field/property is MAJOR\n - Removing or changing public constants is MAJOR\n\n MINOR (backward-compatible additions):\n - Adding new public APIs (classes, methods, functions) is MINOR\n - Adding new optional parameters is MINOR\n - Adding new optional fields to request/response objects is MINOR\n - Adding new error/exception types is MINOR\n - Deprecating (but not removing) public APIs is MINOR\n\n PATCH (no API surface change):\n - Internal/private changes are PATCH\n - Formatting, documentation, or comment changes are PATCH\n - Dependency version updates are PATCH\n - SDK version header updates are PATCH\n - Refactoring retry/timeout internals without changing observable defaults or behavior is PATCH\n - Refactoring internals without changing public signatures is PATCH\n {% endif %}\n\n Apply these patterns to the diff below. When in doubt between MINOR and PATCH,\n prefer MINOR. When in doubt between MAJOR and MINOR, examine whether existing\n callers would break without any code changes on their side.\n\n Message Format (use this exact structure):\n ```\n <type>: <short summary>\n\n <detailed description of what changed and why it matters>\n\n Key changes:\n - <change 1>\n - <change 2>\n - <change 3>\n ```\n\n Message Guidelines:\n - The commit type MUST match the version bump:\n - MAJOR \u2192 use "feat!:" prefix (the "!" signals a breaking change per Conventional Commits)\n - MINOR \u2192 use "feat:" prefix\n - PATCH \u2192 use "fix:" or "chore:" prefix (whichever fits the change)\n - NO_CHANGE \u2192 use "chore:" prefix\n - Keep the summary line under 72 characters\n - Write in present tense imperative mood ("add" not "added" or "adds")\n - For MAJOR: the summary MUST name the breaking change (e.g., "feat!: remove parserCreateJob InputStream overloads")\n - For MINOR: the summary should name the new capability\n - For PATCH: describe the fix or improvement\n - Be specific \u2014 do not use generic summaries like "update SDK" or "regenerate SDK"\n - Do not use "Fern regeneration" in commit messages \u2014 use "SDK regeneration" instead\n - NEVER include the literal version "0.0.0-fern-placeholder" in the commit message \u2014 if you see this placeholder\n in the diff, describe changes generically (e.g., "added X-Fern-SDK-Version header")\n - The previous version is provided for context only. Do not include it literally in the summary line.\n\n {% if prior_changelog %}\n Prior changelog entries (for style reference):\n ---\n {{prior_changelog}}\n ---\n Match the tone and format of these entries in your commit message.\n {% endif %}\n\n {% if spec_commit_message %}\n The API spec change that triggered this SDK generation had the following commit message:\n "{{spec_commit_message}}"\n Use this as a hint for understanding the intent of the change, but always verify\n against the actual diff below. The commit message may be vague or inaccurate.\n {% endif %}\n\n Previous version: {{previous_version}}\n SDK language: {{language}}\n\n Git Diff:\n ---\n {{diff}}\n ---\n\n Changelog Entry Guidelines:\n - Write for SDK consumers, not engineers reading the source code\n - Prefix each entry with a category tag: [BREAKING], [ADDED], [CHANGED], or [FIXED]\n - MAJOR changes MUST use [BREAKING]\n - MINOR additions use [ADDED]\n - MINOR behavioral changes use [CHANGED]\n - PATCH fixes use [FIXED] (or empty string if trivial)\n - For [BREAKING]: name the exact symbol, explain what broke, and give a one-line migration\n Example: "[BREAKING] **`parserCreateJob`** now accepts `File[]` instead of `File`. Wrap single files in an array: `parserCreateJob([file], request)`."\n - For [ADDED]: name the new capability in one sentence\n Example: "[ADDED] **`LabAccountClient`** for managing team lab accounts."\n - Describe patterns once, not per-file. If the same method was added to 50 classes,\n write ONE entry: "[ADDED] **`additionalProperty()`** and **`additionalProperties()`** builder methods on all request types."\n Do NOT write 50 separate entries.\n - NEVER silently drop a category of change. If new enum values were added, new clients were introduced,\n or fields were removed, each *category* must appear \u2014 but you don\'t need to list every individual value.\n GOOD: "[ADDED] New enum values added across several types including `ProviderType` and `OrderStatus`."\n BAD: listing every enum value\n - PATCH: leave empty string \u2014 patch changes don\'t warrant changelog entries\n - Do not use conventional commit prefixes (no "feat:", "fix:", etc.)\n - Write in third person present tense\n - Prefer fewer, richer entries over many thin ones. Aim for 3-5 entries per chunk by grouping related changes.\n - IMPORTANT: Wrap type references containing angle brackets in backticks (e.g., `Optional<String>`)\n\n Remember again that YOU MUST return a structured JSON response with these four fields:\n - message: A git commit message formatted like the example previously provided\n - changelog_entry: A user-facing release note (empty string for PATCH)\n - version_bump: One of: MAJOR, MINOR, PATCH, or NO_CHANGE\n - version_bump_reason: One sentence explaining WHY this bump level was chosen.\n For MAJOR, name the specific breaking symbol(s) and explain why existing callers break.\n For MINOR, name the new capability added.\n For PATCH, describe what was fixed or improved.\n For NO_CHANGE, say "No functional changes detected."\n Example: "MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`, breaking existing callers."\n "#\n}\n\nclass ConsolidateChangelogResponse {\n consolidated_changelog string\n @description("CHANGELOG.md entry in Keep a Changelog format. Group under ### Breaking Changes, ### Added, ### Changed, ### Fixed. Bold symbol names, one tight sentence per bullet. Prose only, no code fences. Append migration action inline for breaking changes.")\n\n pr_description string\n @description("PR description with ## Breaking Changes section (if any) containing ### per breaking change with Before/After code fences and Migration line, then ## What\'s New section summarizing features in prose paragraphs grouped by theme. Do NOT list every class individually \u2014 summarize repetitive changes as a single entry.")\n\n version_bump_reason string\n @description("One sentence explaining WHY the overall version bump was chosen. For MAJOR: name the specific breaking symbol(s). For MINOR: name the new capability. For PATCH: describe the fix. Example: \'MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`.\'")\n}\n\nfunction ConsolidateChangelog(\n raw_entries: string @description("Newline-separated raw changelog entries from chunked diff analysis"),\n version_bump: string @description("The overall version bump: MAJOR, MINOR, or PATCH"),\n language: string @description("The SDK programming language, e.g. \'typescript\', \'python\', \'java\'"),\n previous_version: string @description("The previous SDK version before this change, e.g. \'1.2.3\'. Empty string if unknown."),\n new_version: string @description("The new SDK version after this change, e.g. \'1.3.0\'. Empty string if unknown.")\n) -> ConsolidateChangelogResponse {\n client DefaultClient\n\n prompt #"\n You are a technical writer producing release notes for a {{language}} SDK.\n\n ## Input\n\n Raw changelog entries from chunked diff analysis (noisy, repetitive):\n ---\n {{raw_entries}}\n ---\n\n Overall version bump: {{version_bump}}\n {% if previous_version %}Previous version: {{previous_version}}{% endif %}\n {% if new_version %}New version: {{new_version}}{% endif %}\n\n ## Deduplication Rules (CRITICAL)\n\n Before writing anything, apply these deduplication rules:\n\n 1. **Pattern collapse**: If the same method/field/type was added/changed/removed across\n multiple classes or files, write ONE bullet summarizing the pattern.\n BAD: "- `additionalProperty()` added to UserRequest" + "- `additionalProperty()` added to OrderRequest" + ... (x15)\n GOOD: "- **`additionalProperty()`** and **`additionalProperties()`** builder methods added to all request and response types"\n\n 2. **Semantic merge**: If multiple entries describe aspects of the same feature, merge them.\n BAD: "- New LabAccountClient" + "- New getTeamLabAccounts method" + "- Lab account management support"\n GOOD: "- **`LabAccountClient`** \u2014 new client for managing team lab accounts with `getTeamLabAccounts()` support"\n\n 3. **No silent drops**: Every *category* of change (new clients, new methods, removed methods,\n new enum values, field type changes, etc.) must be represented in at least one bullet.\n You don\'t need to list every individual value or class \u2014 just acknowledge the category.\n GOOD: "- **New enum values** added across several types including `ProviderType` and `OrderStatus`"\n BAD: Silently omitting that enum values changed at all\n ALSO BAD: Listing every value: `SamsungHealth`, `SonoraQuest`, `Cancelled`, `Processing`, ...\n\n 4. **Prefer concise output**: Aim for 5-15 bullets total. Prioritize breaking changes and new\n capabilities. Bulk additions (builder methods, enum values) get one summary bullet each.\n\n ## Output 1: consolidated_changelog (CHANGELOG.md entry)\n\n Structure it EXACTLY like this, omitting empty sections:\n\n ### Breaking Changes\n - **`symbolName`** \u2014 what broke and how to migrate. Example: replace `foo(file)` with `foo([file])`.\n\n ### Added\n - **`symbolName`** \u2014 what was added, one sentence.\n\n ### Changed\n - **`symbolName`** \u2014 what changed, one sentence.\n\n ### Fixed\n - **`symbolName`** \u2014 what was fixed, one sentence.\n\n Rules:\n - **Breaking Changes** section MUST come first when present\n - Bold the symbol name, then a dash, then one tight sentence\n - No code fences in the changelog \u2014 prose and backtick-wrapped symbols only\n - Aim for 5-15 total bullets. Every *category* of change must be represented, but individual\n values/classes within a category can be summarized (e.g., "new enum values across several types").\n - One line per change, no multi-line bullets\n\n ## Output 2: pr_description (PR body)\n\n {% if previous_version and new_version %}\n The PR description MUST start with a version summary block:\n\n ## {{previous_version}} \u2192 {{new_version}} ({{version_bump}})\n\n **Reason:** {version_bump_reason}\n\n Then the breaking changes / what\'s new sections follow.\n {% endif %}\n\n If version_bump is MAJOR, start with:\n\n ## Breaking Changes\n\n ### `symbolName` \u2014 short description\n **Before:**\n ```{{language}}\n // old usage\n ```\n **After:**\n ```{{language}}\n // new usage\n ```\n **Migration:** One sentence on how to update.\n\n (repeat for each breaking change)\n\n Then:\n\n ## What\'s New\n Brief prose paragraphs grouped by theme. Do NOT list every class \u2014 summarize patterns.\n\n If version_bump is MINOR or PATCH, just use:\n\n ## What\'s New\n Brief prose paragraphs grouped by theme. Do NOT list every class \u2014 summarize patterns.\n\n Rules:\n - Breaking changes section at top with Before/After code examples\n - What\'s New in prose paragraphs, not bullet lists \u2014 group by theme (e.g., "Lab account management", "Builder improvements")\n - Do NOT list every class that got the same method \u2014 summarize as one theme\n - Every *category* of change from the changelog must be mentioned somewhere in the PR description.\n Don\'t enumerate every value \u2014 summarize bulk changes in a sentence.\n\n ## Output 3: version_bump_reason\n\n One sentence explaining WHY the overall version bump ({{version_bump}}) was chosen.\n - For MAJOR: name the specific breaking symbol(s) and explain why existing callers break\n - For MINOR: name the new capability added\n - For PATCH: describe what was fixed or improved\n - Example: "MAJOR because `parserCreateJob` InputStream overloads were removed from `RawLabReportClient`, breaking existing callers that pass InputStream arguments."\n\n {{ ctx.output_format }}\n "#\n}\n',
906424
906428
  "generators.baml": 'generator target {\n output_type "typescript"\n\n output_dir "../src/"\n\n version "0.219.0"\n\n default_client_mode async\n}\n',
906425
906429
  "main.baml": "// BAML client configuration for LLM providers\n\n// OpenAI client configuration\nclient<llm> OpenAI {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n}\n\n// Anthropic client configuration\nclient<llm> Anthropic {\n provider anthropic\n options {\n model claude-sonnet-4-5-20250929\n api_key env.ANTHROPIC_API_KEY\n }\n}\n\n// Bedrock client configuration\nclient<llm> Bedrock {\n provider aws-bedrock\n options {\n model anthropic.claude-3-5-sonnet-20240620-v1:0\n }\n}\n\n// Fallback client that tries multiple providers\n// TODO(tjb9dc): I wish we didn't have to specify this, we're only going to use one at runtime\nclient<llm> DefaultClient {\n provider fallback\n options {\n strategy [\n Anthropic\n OpenAI\n Bedrock\n ]\n }\n}\n"
906426
906430
  };
@@ -906502,7 +906506,7 @@ var BamlAsyncClient = class _BamlAsyncClient {
906502
906506
  throw (0, import_baml4.toBamlError)(error50);
906503
906507
  }
906504
906508
  }
906505
- async ConsolidateChangelog(raw_entries, version_bump, language, __baml_options__) {
906509
+ async ConsolidateChangelog(raw_entries, version_bump, language, previous_version, new_version, __baml_options__) {
906506
906510
  try {
906507
906511
  const __options__ = { ...this.bamlOptions, ...__baml_options__ || {} };
906508
906512
  const __signal__ = __options__.signal;
@@ -906510,7 +906514,7 @@ var BamlAsyncClient = class _BamlAsyncClient {
906510
906514
  throw new import_baml4.BamlAbortError("Operation was aborted", __signal__.reason);
906511
906515
  }
906512
906516
  if (__options__.onTick) {
906513
- const __stream__ = this.stream.ConsolidateChangelog(raw_entries, version_bump, language, __baml_options__);
906517
+ const __stream__ = this.stream.ConsolidateChangelog(raw_entries, version_bump, language, previous_version, new_version, __baml_options__);
906514
906518
  return await __stream__.getFinalResponse();
906515
906519
  }
906516
906520
  const __collector__ = __options__.collector ? Array.isArray(__options__.collector) ? __options__.collector : [__options__.collector] : [];
@@ -906524,7 +906528,9 @@ var BamlAsyncClient = class _BamlAsyncClient {
906524
906528
  const __raw__ = await this.runtime.callFunction("ConsolidateChangelog", {
906525
906529
  "raw_entries": raw_entries,
906526
906530
  "version_bump": version_bump,
906527
- "language": language
906531
+ "language": language,
906532
+ "previous_version": previous_version,
906533
+ "new_version": new_version
906528
906534
  }, this.ctxManager.cloneContext(), __options__.tb?.__tb(), __clientRegistry__, __collector__, __options__.tags || {}, __env__, __signal__, __options__.watchers);
906529
906535
  return __raw__.parsed(false);
906530
906536
  } catch (error50) {
@@ -906583,7 +906589,7 @@ var BamlStreamClient = class {
906583
906589
  throw (0, import_baml4.toBamlError)(error50);
906584
906590
  }
906585
906591
  }
906586
- ConsolidateChangelog(raw_entries, version_bump, language, __baml_options__) {
906592
+ ConsolidateChangelog(raw_entries, version_bump, language, previous_version, new_version, __baml_options__) {
906587
906593
  try {
906588
906594
  const __options__ = { ...this.bamlOptions, ...__baml_options__ || {} };
906589
906595
  const __signal__ = __options__.signal;
@@ -906616,7 +906622,9 @@ var BamlStreamClient = class {
906616
906622
  const __raw__ = this.runtime.streamFunction("ConsolidateChangelog", {
906617
906623
  "raw_entries": raw_entries,
906618
906624
  "version_bump": version_bump,
906619
- "language": language
906625
+ "language": language,
906626
+ "previous_version": previous_version,
906627
+ "new_version": new_version
906620
906628
  }, void 0, this.ctxManager.cloneContext(), __options__.tb?.__tb(), __clientRegistry__, __collector__, __options__.tags || {}, __env__, __signal__, __onTickWrapper__);
906621
906629
  return new import_baml4.BamlStream(__raw__, (a10) => a10, (a10) => a10, this.ctxManager.cloneContext(), __options__.signal);
906622
906630
  } catch (error50) {
@@ -906962,9 +906970,10 @@ var LocalTaskHandler = class {
906962
906970
  const rawEntries = allChangelogEntries.map((e6) => e6.startsWith("- ") ? e6 : `- ${e6}`).join("\n");
906963
906971
  try {
906964
906972
  this.context.logger.debug(`Consolidating ${allChangelogEntries.length} changelog entries via AI rollup`);
906973
+ const projectedVersion = this.incrementVersion(previousVersion, bestBump);
906965
906974
  const rollup = await b18.withOptions({
906966
906975
  clientRegistry: await this.getClientRegistry()
906967
- }).ConsolidateChangelog(rawEntries, bestBump, this.generatorLanguage ?? "unknown");
906976
+ }).ConsolidateChangelog(rawEntries, bestBump, this.generatorLanguage ?? "unknown", previousVersion, projectedVersion);
906968
906977
  changelogEntry2 = rollup.consolidated_changelog?.trim() || rawEntries;
906969
906978
  prDescription2 = rollup.pr_description?.trim() || void 0;
906970
906979
  versionBumpReason2 = rollup.version_bump_reason?.trim() || void 0;
@@ -928615,7 +928624,10 @@ var SentryClient = class {
928615
928624
  if (isTelemetryEnabled && sentryDsn != null && sentryDsn.length > 0) {
928616
928625
  const sentryEnvironment = "development";
928617
928626
  if (sentryEnvironment == null || sentryEnvironment.length === 0) {
928618
- throw new Error("SENTRY_ENVIRONMENT must be set when SENTRY_DSN is configured");
928627
+ throw new CliError({
928628
+ message: "SENTRY_ENVIRONMENT must be set when SENTRY_DSN is configured",
928629
+ code: CliError.Code.ConfigError
928630
+ });
928619
928631
  }
928620
928632
  this.sentry = init2({
928621
928633
  dsn: sentryDsn,
@@ -928654,7 +928666,10 @@ var StdoutRedirector = class {
928654
928666
  redirected = false;
928655
928667
  redirect() {
928656
928668
  if (this.redirected) {
928657
- throw new Error("StdoutRedirector: already redirected \u2014 did you forget to restore()?");
928669
+ throw new CliError({
928670
+ message: "StdoutRedirector: already redirected \u2014 did you forget to restore()?",
928671
+ code: CliError.Code.InternalError
928672
+ });
928658
928673
  }
928659
928674
  this.originalWrite = process.stdout.write;
928660
928675
  process.stdout.write = process.stderr.write.bind(process.stderr);
@@ -928963,7 +928978,7 @@ async function normalizeGeneratorName2(generatorImage) {
928963
928978
  });
928964
928979
  const generatorResponse = await client3.generators.getGeneratorByImage({ dockerImage: generatorImage });
928965
928980
  if (!generatorResponse.ok || generatorResponse.body == null) {
928966
- throw new Error(`Generator ${generatorImage} not found`);
928981
+ throw new CliError({ message: `Generator ${generatorImage} not found`, code: CliError.Code.InternalError });
928967
928982
  }
928968
928983
  return generatorResponse.body.displayName;
928969
928984
  }
@@ -929144,9 +929159,16 @@ async function getLatestVersionOfCli({
929144
929159
  if (cliEnvironment.packageName !== "fern-api" || cliEnvironment.packageVersion === "0.0.0") {
929145
929160
  return cliEnvironment.packageVersion;
929146
929161
  }
929147
- return latestVersion(cliEnvironment.packageName, {
929148
- version: includePreReleases ? "prerelease" : "latest"
929149
- });
929162
+ try {
929163
+ return await latestVersion(cliEnvironment.packageName, {
929164
+ version: includePreReleases ? "prerelease" : "latest"
929165
+ });
929166
+ } catch (error50) {
929167
+ throw new CliError({
929168
+ message: `Failed to resolve latest CLI version: ${error50 instanceof Error ? error50.message : String(error50)}`,
929169
+ code: CliError.Code.NetworkError
929170
+ });
929171
+ }
929150
929172
  }
929151
929173
 
929152
929174
  // src/cli-context/CliContext.ts
@@ -929193,7 +929215,7 @@ var CliContext = class _CliContext {
929193
929215
  if (false) {
929194
929216
  this.logger.error("CLI_VERSION is not defined");
929195
929217
  }
929196
- return "4.68.4";
929218
+ return "4.68.5-8-g6594a748f1f";
929197
929219
  }
929198
929220
  getCliName() {
929199
929221
  if (false) {
@@ -929474,7 +929496,15 @@ var CliContext = class _CliContext {
929474
929496
  * @returns Promise<string> representing the user's input
929475
929497
  */
929476
929498
  async getInput(config5) {
929477
- return await esm_default10({ message: config5.message, default: config5.default });
929499
+ try {
929500
+ return await esm_default10({ message: config5.message, default: config5.default });
929501
+ } catch (error50) {
929502
+ if (error50?.name === "ExitPromptError") {
929503
+ this.logger.info("\nCancelled by user.");
929504
+ throw new TaskAbortSignal();
929505
+ }
929506
+ throw error50;
929507
+ }
929478
929508
  }
929479
929509
  };
929480
929510
  function wrapWorkspaceNameForPrefix(workspaceName) {
@@ -929689,7 +929719,9 @@ async function getGeneratorList({
929689
929719
  try {
929690
929720
  await (0, import_promises126.writeFile)(outputLocation, generatorsListYaml);
929691
929721
  } catch (error50) {
929692
- cliContext.failAndThrow(`Could not write file to the specified location: ${outputLocation}`, error50);
929722
+ cliContext.failAndThrow(`Could not write file to the specified location: ${outputLocation}`, error50, {
929723
+ code: CliError.Code.ConfigError
929724
+ });
929693
929725
  }
929694
929726
  }
929695
929727
  function isGeneratorInModeSet(generator, modes) {
@@ -929767,7 +929799,9 @@ async function getOrganization({
929767
929799
  try {
929768
929800
  await (0, import_promises127.writeFile)(outputLocation, org);
929769
929801
  } catch (error50) {
929770
- context3.failAndThrow(`Could not write file to the specified location: ${outputLocation}`, error50);
929802
+ context3.failAndThrow(`Could not write file to the specified location: ${outputLocation}`, error50, {
929803
+ code: CliError.Code.ConfigError
929804
+ });
929771
929805
  }
929772
929806
  }
929773
929807
 
@@ -929895,7 +929929,10 @@ async function ensureMigrationsInstalled(logger4) {
929895
929929
  const packageJsonContent = await (0, import_promises128.readFile)(packageJsonPath, "utf-8");
929896
929930
  const packageJson2 = JSON.parse(packageJsonContent);
929897
929931
  if (packageJson2.main == null) {
929898
- throw new Error(`No main field found in package.json for ${MIGRATION_PACKAGE_NAME2}`);
929932
+ throw new CliError({
929933
+ message: `No main field found in package.json for ${MIGRATION_PACKAGE_NAME2}`,
929934
+ code: CliError.Code.InternalError
929935
+ });
929899
929936
  }
929900
929937
  const packageEntryPoint = (0, import_path78.join)(packageDir, packageJson2.main);
929901
929938
  const { migrations } = await import((0, import_url9.pathToFileURL)(packageEntryPoint).href);
@@ -929968,9 +930005,10 @@ function filterMigrations(params2) {
929968
930005
  const aVersion = import_semver16.default.parse(a10.version);
929969
930006
  const bVersion = import_semver16.default.parse(b19.version);
929970
930007
  if (aVersion == null || bVersion == null) {
929971
- throw new Error(
929972
- `Internal error: Invalid migration version found during sort. Version A: ${a10.version}, Version B: ${b19.version}. This should not happen as invalid versions are filtered out.`
929973
- );
930008
+ throw new CliError({
930009
+ message: `Internal error: Invalid migration version found during sort. Version A: ${a10.version}, Version B: ${b19.version}. This should not happen as invalid versions are filtered out.`,
930010
+ code: CliError.Code.InternalError
930011
+ });
929974
930012
  }
929975
930013
  return import_semver16.default.compare(aVersion, bVersion);
929976
930014
  });
@@ -929988,15 +930026,16 @@ function runMigrations(params2) {
929988
930026
  appliedVersions.push(migration23.version);
929989
930027
  } catch (error50) {
929990
930028
  const errorMessage = extractErrorMessage(error50);
929991
- throw new Error(
929992
- `Failed to apply migration for version ${migration23.version}.
930029
+ throw new CliError({
930030
+ message: `Failed to apply migration for version ${migration23.version}.
929993
930031
 
929994
930032
  Reason: ${errorMessage}
929995
930033
 
929996
930034
  This migration was attempting to update your generator configuration. The upgrade has been halted to prevent partial or invalid changes.
929997
930035
 
929998
- Please report this issue at: https://github.com/fern-api/fern/issues`
929999
- );
930036
+ Please report this issue at: https://github.com/fern-api/fern/issues`,
930037
+ code: CliError.Code.InternalError
930038
+ });
930000
930039
  }
930001
930040
  }
930002
930041
  return {
@@ -930016,13 +930055,14 @@ function isValidGeneratorConfig(config5) {
930016
930055
  async function loadAndRunMigrations(params2) {
930017
930056
  const { generatorName, from: from4, to: to8, config: config5, logger: logger4 } = params2;
930018
930057
  if (!isValidGeneratorConfig(config5)) {
930019
- throw new Error(
930020
- `Invalid generator configuration for ${generatorName}.
930058
+ throw new CliError({
930059
+ message: `Invalid generator configuration for ${generatorName}.
930021
930060
 
930022
930061
  The generator configuration must be an object with either a 'name' property or an 'image' property, but the current configuration does not match this structure. This may indicate a malformed generators.yml file.
930023
930062
 
930024
- Please check your generators.yml file and ensure the generator is properly configured.`
930025
- );
930063
+ Please check your generators.yml file and ensure the generator is properly configured.`,
930064
+ code: CliError.Code.InternalError
930065
+ });
930026
930066
  }
930027
930067
  const typedConfig = config5;
930028
930068
  const migrationModule = await loadMigrationModule({ generatorName, logger: logger4 });
@@ -930087,7 +930127,9 @@ async function loadAndUpdateGenerators({
930087
930127
  };
930088
930128
  }
930089
930129
  if (!import_yaml6.default.isMap(generatorGroups)) {
930090
- context3.failAndThrow(`Expected 'groups' to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`);
930130
+ context3.failAndThrow(`Expected 'groups' to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`, void 0, {
930131
+ code: CliError.Code.ParseError
930132
+ });
930091
930133
  return {
930092
930134
  updatedConfiguration: void 0,
930093
930135
  skippedMajorUpgrades: [],
@@ -930106,7 +930148,9 @@ async function loadAndUpdateGenerators({
930106
930148
  const group = groupBlock.value;
930107
930149
  if (!import_yaml6.default.isMap(group)) {
930108
930150
  context3.failAndThrow(
930109
- `Expected group ${groupName} to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`
930151
+ `Expected group ${groupName} to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`,
930152
+ void 0,
930153
+ { code: CliError.Code.ConfigError }
930110
930154
  );
930111
930155
  continue;
930112
930156
  }
@@ -930117,7 +930161,9 @@ async function loadAndUpdateGenerators({
930117
930161
  const generators = group.get("generators");
930118
930162
  if (!import_yaml6.default.isSeq(generators)) {
930119
930163
  context3.failAndThrow(
930120
- `Expected group ${groupName} to have a 'generators' key in ${import_path79.default.relative(process.cwd(), filepath)}`
930164
+ `Expected group ${groupName} to have a 'generators' key in ${import_path79.default.relative(process.cwd(), filepath)}`,
930165
+ void 0,
930166
+ { code: CliError.Code.ConfigError }
930121
930167
  );
930122
930168
  continue;
930123
930169
  }
@@ -930125,7 +930171,9 @@ async function loadAndUpdateGenerators({
930125
930171
  for (const generator of generators.items) {
930126
930172
  if (!import_yaml6.default.isMap(generator)) {
930127
930173
  context3.failAndThrow(
930128
- `Expected generator in group ${groupName} to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`
930174
+ `Expected generator in group ${groupName} to be a map in ${import_path79.default.relative(process.cwd(), filepath)}`,
930175
+ void 0,
930176
+ { code: CliError.Code.VersionError }
930129
930177
  );
930130
930178
  }
930131
930179
  if (generator.get("image") != null) {
@@ -930659,7 +930707,9 @@ function addGeneratorCommands(cli, cliContext) {
930659
930707
  if (generator == null) {
930660
930708
  const maybeApiFilter = argv.api ? ` for API ${argv.api}` : "";
930661
930709
  cliContext.failAndThrow(
930662
- `Generator ${argv.generator}, in group ${argv.group}${maybeApiFilter} was not found.`
930710
+ `Generator ${argv.generator}, in group ${argv.group}${maybeApiFilter} was not found.`,
930711
+ void 0,
930712
+ { code: CliError.Code.ConfigError }
930663
930713
  );
930664
930714
  }
930665
930715
  const generatorMetadata = {};
@@ -930703,7 +930753,8 @@ function addGeneratorCommands(cli, cliContext) {
930703
930753
  } catch (error50) {
930704
930754
  cliContext.failAndThrow(
930705
930755
  `Could not write file to the specified location: ${argv.output}`,
930706
- error50
930756
+ error50,
930757
+ { code: CliError.Code.ConfigError }
930707
930758
  );
930708
930759
  }
930709
930760
  }
@@ -930780,7 +930831,9 @@ async function diff({
930780
930831
  const bump = bumpOrUndefined ?? "patch";
930781
930832
  const nextVersion = import_semver18.default.inc(fromVersion, bump);
930782
930833
  if (!nextVersion) {
930783
- context3.failWithoutThrowing(`Invalid current version: ${fromVersion}`);
930834
+ context3.failWithoutThrowing(`Invalid current version: ${fromVersion}`, void 0, {
930835
+ code: CliError.Code.VersionError
930836
+ });
930784
930837
  throw new TaskAbortSignal();
930785
930838
  }
930786
930839
  return { bump, nextVersion, errors: errors4 };
@@ -930792,13 +930845,27 @@ async function readIr({
930792
930845
  }) {
930793
930846
  const absoluteFilepath = AbsoluteFilePath2.of(resolve6(cwd(), filepath));
930794
930847
  if (!await doesPathExist(absoluteFilepath, "file")) {
930795
- context3.failWithoutThrowing(`File not found: ${absoluteFilepath}`);
930848
+ context3.failWithoutThrowing(`File not found: ${absoluteFilepath}`, void 0, {
930849
+ code: CliError.Code.ConfigError
930850
+ });
930851
+ throw new TaskAbortSignal();
930852
+ }
930853
+ let ir15;
930854
+ try {
930855
+ ir15 = await streamObjectFromFile(absoluteFilepath);
930856
+ } catch (error50) {
930857
+ context3.failWithoutThrowing(
930858
+ `Failed to parse IR file ${absoluteFilepath}: ${error50 instanceof Error ? error50.message : String(error50)}`,
930859
+ error50,
930860
+ { code: CliError.Code.ParseError }
930861
+ );
930796
930862
  throw new TaskAbortSignal();
930797
930863
  }
930798
- const ir15 = await streamObjectFromFile(absoluteFilepath);
930799
930864
  const parsed = serialization_exports2.IntermediateRepresentation.parse(ir15);
930800
930865
  if (!parsed.ok) {
930801
- context3.failWithoutThrowing(`Invalid --${flagName}; expected a filepath containing a valid IR`);
930866
+ context3.failWithoutThrowing(`Invalid --${flagName}; expected a filepath containing a valid IR`, void 0, {
930867
+ code: CliError.Code.ParseError
930868
+ });
930802
930869
  throw new TaskAbortSignal();
930803
930870
  }
930804
930871
  return parsed.value;
@@ -930864,7 +930931,9 @@ function diffGeneratorVersions(context3, generatorVersions) {
930864
930931
  errors: errors4
930865
930932
  };
930866
930933
  } catch (error50) {
930867
- context3.failWithoutThrowing(`Error diffing generator versions ${from4} and ${to8}: ${error50}`);
930934
+ context3.failWithoutThrowing(`Error diffing generator versions ${from4} and ${to8}: ${error50}`, void 0, {
930935
+ code: CliError.Code.InternalError
930936
+ });
930868
930937
  throw new TaskAbortSignal();
930869
930938
  }
930870
930939
  }
@@ -930894,7 +930963,7 @@ async function collectDocsWorkspaceViolations({
930894
930963
  }) {
930895
930964
  if (workspace.config.settings?.substituteEnvVars) {
930896
930965
  workspace.config = replaceEnvVariables(workspace.config, {
930897
- onError: (e6) => context3.failAndThrow(e6)
930966
+ onError: (e6) => context3.failAndThrow(e6, void 0, { code: CliError.Code.ValidationError })
930898
930967
  });
930899
930968
  }
930900
930969
  const startTime = performance.now();
@@ -930929,7 +930998,7 @@ async function validateDocsWorkspaceWithoutExiting({
930929
930998
  }) {
930930
930999
  if (workspace.config.settings?.substituteEnvVars) {
930931
931000
  workspace.config = replaceEnvVariables(workspace.config, {
930932
- onError: (e6) => context3.failAndThrow(e6)
931001
+ onError: (e6) => context3.failAndThrow(e6, void 0, { code: CliError.Code.ValidationError })
930933
931002
  });
930934
931003
  }
930935
931004
  const startTime = performance.now();
@@ -930974,7 +931043,7 @@ async function validateDocsWorkspaceAndLogIssues({
930974
931043
  excludeRules
930975
931044
  });
930976
931045
  if (hasErrors) {
930977
- context3.failAndThrow();
931046
+ context3.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
930978
931047
  }
930979
931048
  }
930980
931049
 
@@ -931108,7 +931177,10 @@ async function getSlugForFiles({
931108
931177
  });
931109
931178
  if (!response.ok) {
931110
931179
  const errorText = await response.text();
931111
- throw new Error(`Failed to get slugs for files: ${response.status} ${response.statusText} - ${errorText}`);
931180
+ throw new CliError({
931181
+ message: `Failed to get slugs for files: ${response.status} ${response.statusText} - ${errorText}`,
931182
+ code: CliError.Code.InternalError
931183
+ });
931112
931184
  }
931113
931185
  return await response.json();
931114
931186
  }
@@ -931357,11 +931429,11 @@ async function generateComparisons({
931357
931429
  }
931358
931430
  function getProductionUrlInfo(docsConfig) {
931359
931431
  if (docsConfig.instances == null || docsConfig.instances.length === 0) {
931360
- throw new Error("No docs instances configured in docs.yml");
931432
+ throw new CliError({ message: "No docs instances configured in docs.yml", code: CliError.Code.InternalError });
931361
931433
  }
931362
931434
  const firstInstance = docsConfig.instances[0];
931363
931435
  if (firstInstance == null) {
931364
- throw new Error("No docs instances configured in docs.yml");
931436
+ throw new CliError({ message: "No docs instances configured in docs.yml", code: CliError.Code.InternalError });
931365
931437
  }
931366
931438
  const instanceUrl = firstInstance["custom-domain"] ?? firstInstance.url;
931367
931439
  let normalizedUrl = instanceUrl;
@@ -931386,14 +931458,18 @@ async function docsDiff({
931386
931458
  }) {
931387
931459
  const docsWorkspace = project.docsWorkspaces;
931388
931460
  if (docsWorkspace == null) {
931389
- cliContext.failAndThrow("No docs workspace found. Make sure you have a docs.yml file.");
931461
+ cliContext.failAndThrow("No docs workspace found. Make sure you have a docs.yml file.", void 0, {
931462
+ code: CliError.Code.ConfigError
931463
+ });
931390
931464
  return { diffs: [] };
931391
931465
  }
931392
931466
  const token = await cliContext.runTask(async (context3) => {
931393
931467
  return askToLogin(context3);
931394
931468
  });
931395
931469
  if (token == null) {
931396
- cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.");
931470
+ cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.", void 0, {
931471
+ code: CliError.Code.AuthError
931472
+ });
931397
931473
  return { diffs: [] };
931398
931474
  }
931399
931475
  const fernToken = process.env.FERN_TOKEN ?? token.value;
@@ -935838,7 +935914,7 @@ function createLibraryDocsClient({ token }) {
935838
935914
  });
935839
935915
  if (!response.ok) {
935840
935916
  const text9 = await response.text().catch(() => "");
935841
- throw new Error(`HTTP ${response.status}: ${text9}`);
935917
+ throw new CliError({ message: `HTTP ${response.status}: ${text9}`, code: CliError.Code.NetworkError });
935842
935918
  }
935843
935919
  return await response.json();
935844
935920
  }
@@ -935862,21 +935938,27 @@ var POLL_TIMEOUT_MS = 3 * 60 * 1e3;
935862
935938
  async function generateLibraryDocs({ project, cliContext, library }) {
935863
935939
  const docsWorkspace = project.docsWorkspaces;
935864
935940
  if (docsWorkspace == null) {
935865
- cliContext.failAndThrow("No docs workspace found. Make sure you have a docs.yml file.");
935941
+ cliContext.failAndThrow("No docs workspace found. Make sure you have a docs.yml file.", void 0, {
935942
+ code: CliError.Code.ConfigError
935943
+ });
935866
935944
  return;
935867
935945
  }
935868
935946
  const rawConfig = docsWorkspace.config;
935869
935947
  const libraries = rawConfig.libraries;
935870
935948
  if (libraries == null || Object.keys(libraries).length === 0) {
935871
935949
  cliContext.failAndThrow(
935872
- "No libraries configured in docs.yml. Add a `libraries` section to configure library documentation."
935950
+ "No libraries configured in docs.yml. Add a `libraries` section to configure library documentation.",
935951
+ void 0,
935952
+ { code: CliError.Code.ConfigError }
935873
935953
  );
935874
935954
  return;
935875
935955
  }
935876
935956
  const librariesToGenerate = library != null ? { [library]: libraries[library] } : libraries;
935877
935957
  if (library != null && libraries[library] == null) {
935878
935958
  cliContext.failAndThrow(
935879
- `Library '${library}' not found in docs.yml. Available libraries: ${Object.keys(libraries).join(", ")}`
935959
+ `Library '${library}' not found in docs.yml. Available libraries: ${Object.keys(libraries).join(", ")}`,
935960
+ void 0,
935961
+ { code: CliError.Code.ConfigError }
935880
935962
  );
935881
935963
  return;
935882
935964
  }
@@ -935884,7 +935966,9 @@ async function generateLibraryDocs({ project, cliContext, library }) {
935884
935966
  return askToLogin(context3);
935885
935967
  });
935886
935968
  if (token == null) {
935887
- cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.");
935969
+ cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.", void 0, {
935970
+ code: CliError.Code.AuthError
935971
+ });
935888
935972
  return;
935889
935973
  }
935890
935974
  const orgId = project.config.organization;
@@ -935896,7 +935980,9 @@ async function generateLibraryDocs({ project, cliContext, library }) {
935896
935980
  }
935897
935981
  if (!isGitLibraryInput2(config5.input)) {
935898
935982
  context3.failAndThrow(
935899
- `Library '${name2}' uses 'path' input which is not yet supported. Please use 'git' input.`
935983
+ `Library '${name2}' uses 'path' input which is not yet supported. Please use 'git' input.`,
935984
+ void 0,
935985
+ { code: CliError.Code.ConfigError }
935900
935986
  );
935901
935987
  return false;
935902
935988
  }
@@ -935929,7 +936015,9 @@ async function generateSingleLibrary({
935929
936015
  return context3.runInteractiveTask({ name: name2 }, async (interactiveTaskContext) => {
935930
936016
  if (config5.config?.doxyfile != null && config5.lang !== "cpp") {
935931
936017
  return interactiveTaskContext.failAndThrow(
935932
- `Library '${name2}': 'doxyfile' config is only valid for lang: cpp`
936018
+ `Library '${name2}': 'doxyfile' config is only valid for lang: cpp`,
936019
+ void 0,
936020
+ { code: CliError.Code.ConfigError }
935933
936021
  );
935934
936022
  }
935935
936023
  let doxyfileContent;
@@ -935939,13 +936027,19 @@ async function generateSingleLibrary({
935939
936027
  doxyfileContent = await (0, import_promises133.readFile)(doxyfilePath, "utf-8");
935940
936028
  } catch {
935941
936029
  return interactiveTaskContext.failAndThrow(
935942
- `Library '${name2}': Could not read Doxyfile at '${config5.config.doxyfile}' (resolved to ${doxyfilePath})`
936030
+ `Library '${name2}': Could not read Doxyfile at '${config5.config.doxyfile}' (resolved to ${doxyfilePath})`,
936031
+ void 0,
936032
+ { code: CliError.Code.ConfigError }
935943
936033
  );
935944
936034
  }
935945
936035
  }
935946
936036
  const language = config5.lang === "python" ? "PYTHON" : config5.lang === "cpp" ? "CPP" : void 0;
935947
936037
  if (language == null) {
935948
- return interactiveTaskContext.failAndThrow(`Library '${name2}': unsupported language '${config5.lang}'`);
936038
+ return interactiveTaskContext.failAndThrow(
936039
+ `Library '${name2}': unsupported language '${config5.lang}'`,
936040
+ void 0,
936041
+ { code: CliError.Code.ConfigError }
936042
+ );
935949
936043
  }
935950
936044
  const client3 = createLibraryDocsClient({ token: token.value });
935951
936045
  interactiveTaskContext.logger.debug(`Starting generation for library '${name2}' from ${gitInput.git}`);
@@ -935985,7 +936079,11 @@ To include in your docs navigation, add to docs.yml:
935985
936079
  });
935986
936080
  interactiveTaskContext.logger.debug(`Generated ${generateResult.pageCount} pages at ${resolvedOutputPath}`);
935987
936081
  } else {
935988
- return interactiveTaskContext.failAndThrow(`Library '${name2}': unsupported language '${config5.lang}'`);
936082
+ return interactiveTaskContext.failAndThrow(
936083
+ `Library '${name2}': unsupported language '${config5.lang}'`,
936084
+ void 0,
936085
+ { code: CliError.Code.ConfigError }
936086
+ );
935989
936087
  }
935990
936088
  });
935991
936089
  }
@@ -936007,7 +936105,9 @@ async function startGeneration(client3, context3, opts) {
936007
936105
  return result.jobId;
936008
936106
  } catch (error50) {
936009
936107
  return context3.failAndThrow(
936010
- `Failed to start generation for library '${opts.name}': ${extractErrorMessage(error50)}`
936108
+ `Failed to start generation for library '${opts.name}': ${extractErrorMessage(error50)}`,
936109
+ error50,
936110
+ { code: CliError.Code.NetworkError }
936011
936111
  );
936012
936112
  }
936013
936113
  }
@@ -936020,7 +936120,9 @@ async function pollForCompletion(client3, jobId, libraryName, context3) {
936020
936120
  status = await client3.getLibraryDocsGenerationStatus({ jobId });
936021
936121
  } catch (error50) {
936022
936122
  return context3.failAndThrow(
936023
- `Failed to check generation status for library '${libraryName}': ${extractErrorMessage(error50)}`
936123
+ `Failed to check generation status for library '${libraryName}': ${extractErrorMessage(error50)}`,
936124
+ error50,
936125
+ { code: CliError.Code.NetworkError }
936024
936126
  );
936025
936127
  }
936026
936128
  switch (status.status) {
@@ -936035,15 +936137,23 @@ async function pollForCompletion(client3, jobId, libraryName, context3) {
936035
936137
  return;
936036
936138
  case "FAILED":
936037
936139
  return context3.failAndThrow(
936038
- `Generation failed for library '${libraryName}': ${status.error?.message ?? "Unknown error"} (${status.error?.code ?? "UNKNOWN"})`
936140
+ `Generation failed for library '${libraryName}': ${status.error?.message ?? "Unknown error"} (${status.error?.code ?? "UNKNOWN"})`,
936141
+ void 0,
936142
+ { code: CliError.Code.InternalError }
936039
936143
  );
936040
936144
  default:
936041
936145
  return context3.failAndThrow(
936042
- `Unexpected generation status for library '${libraryName}': ${status.status}`
936146
+ `Unexpected generation status for library '${libraryName}': ${status.status}`,
936147
+ void 0,
936148
+ { code: CliError.Code.InternalError }
936043
936149
  );
936044
936150
  }
936045
936151
  }
936046
- return context3.failAndThrow(`Generation timed out for library '${libraryName}' after ${POLL_TIMEOUT_MS / 1e3}s`);
936152
+ return context3.failAndThrow(
936153
+ `Generation timed out for library '${libraryName}' after ${POLL_TIMEOUT_MS / 1e3}s`,
936154
+ void 0,
936155
+ { code: CliError.Code.NetworkError }
936156
+ );
936047
936157
  }
936048
936158
  async function downloadIr(client3, jobId, libraryName, language, context3) {
936049
936159
  let resultUrl;
@@ -936052,29 +936162,39 @@ async function downloadIr(client3, jobId, libraryName, language, context3) {
936052
936162
  resultUrl = result.resultUrl;
936053
936163
  } catch (error50) {
936054
936164
  return context3.failAndThrow(
936055
- `Failed to fetch generation result for library '${libraryName}': ${extractErrorMessage(error50)}`
936165
+ `Failed to fetch generation result for library '${libraryName}': ${extractErrorMessage(error50)}`,
936166
+ error50,
936167
+ { code: CliError.Code.NetworkError }
936056
936168
  );
936057
936169
  }
936058
936170
  context3.logger.debug(`Fetching IR from ${resultUrl}`);
936059
936171
  const irFetchResponse = await fetch(resultUrl);
936060
936172
  if (!irFetchResponse.ok) {
936061
936173
  return context3.failAndThrow(
936062
- `Failed to download IR for library '${libraryName}': HTTP ${irFetchResponse.status}`
936174
+ `Failed to download IR for library '${libraryName}': HTTP ${irFetchResponse.status}`,
936175
+ void 0,
936176
+ { code: CliError.Code.NetworkError }
936063
936177
  );
936064
936178
  }
936065
936179
  const irWrapper = await irFetchResponse.json();
936066
936180
  const ir15 = irWrapper.ir;
936067
936181
  if (ir15 == null) {
936068
- return context3.failAndThrow(`IR is empty for library '${libraryName}'`);
936182
+ return context3.failAndThrow(`IR is empty for library '${libraryName}'`, void 0, {
936183
+ code: CliError.Code.InternalError
936184
+ });
936069
936185
  }
936070
936186
  if (language === "CPP") {
936071
936187
  if (ir15.rootNamespace == null) {
936072
- return context3.failAndThrow(`IR has no rootNamespace for C++ library '${libraryName}'`);
936188
+ return context3.failAndThrow(`IR has no rootNamespace for C++ library '${libraryName}'`, void 0, {
936189
+ code: CliError.Code.InternalError
936190
+ });
936073
936191
  }
936074
936192
  context3.logger.debug(`Downloaded C++ IR for '${libraryName}'`);
936075
936193
  } else {
936076
936194
  if (ir15.rootModule == null) {
936077
- return context3.failAndThrow(`IR has no rootModule for library '${libraryName}'`);
936195
+ return context3.failAndThrow(`IR has no rootModule for library '${libraryName}'`, void 0, {
936196
+ code: CliError.Code.InternalError
936197
+ });
936078
936198
  }
936079
936199
  context3.logger.debug(`Downloaded IR with ${Object.keys(ir15.rootModule).length} top-level keys`);
936080
936200
  }
@@ -936105,7 +936225,9 @@ async function deleteDocsPreview({
936105
936225
  `Invalid preview URL: ${previewUrl}
936106
936226
  Only preview sites can be deleted with this command.
936107
936227
  Preview URLs follow the pattern: {org}-preview-{hash}.docs.buildwithfern.com
936108
- Example: acme-preview-abc123.docs.buildwithfern.com`
936228
+ Example: acme-preview-abc123.docs.buildwithfern.com`,
936229
+ void 0,
936230
+ { code: CliError.Code.ConfigError }
936109
936231
  );
936110
936232
  return;
936111
936233
  }
@@ -936113,7 +936235,9 @@ Example: acme-preview-abc123.docs.buildwithfern.com`
936113
936235
  return askToLogin(context3);
936114
936236
  });
936115
936237
  if (token == null) {
936116
- cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.");
936238
+ cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.", void 0, {
936239
+ code: CliError.Code.AuthError
936240
+ });
936117
936241
  return;
936118
936242
  }
936119
936243
  await cliContext.runTask(async (context3) => {
@@ -936128,12 +936252,18 @@ Example: acme-preview-abc123.docs.buildwithfern.com`
936128
936252
  switch (deleteResponse.error.error) {
936129
936253
  case "UnauthorizedError":
936130
936254
  return context3.failAndThrow(
936131
- "You do not have permissions to delete this preview site. Reach out to support@buildwithfern.com"
936255
+ "You do not have permissions to delete this preview site. Reach out to support@buildwithfern.com",
936256
+ void 0,
936257
+ { code: CliError.Code.NetworkError }
936132
936258
  );
936133
936259
  case "DocsNotFoundError":
936134
- return context3.failAndThrow(`Preview site not found: ${previewUrl}`);
936260
+ return context3.failAndThrow(`Preview site not found: ${previewUrl}`, void 0, {
936261
+ code: CliError.Code.ConfigError
936262
+ });
936135
936263
  default:
936136
- return context3.failAndThrow(`Failed to delete preview site: ${previewUrl}`, deleteResponse.error);
936264
+ return context3.failAndThrow(`Failed to delete preview site: ${previewUrl}`, deleteResponse.error, {
936265
+ code: CliError.Code.NetworkError
936266
+ });
936137
936267
  }
936138
936268
  }
936139
936269
  });
@@ -936149,7 +936279,9 @@ async function listDocsPreview({
936149
936279
  return askToLogin(context3);
936150
936280
  });
936151
936281
  if (token == null) {
936152
- cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.");
936282
+ cliContext.failAndThrow("Failed to authenticate. Please run 'fern login' first.", void 0, {
936283
+ code: CliError.Code.AuthError
936284
+ });
936153
936285
  return;
936154
936286
  }
936155
936287
  await cliContext.runTask(async (context3) => {
@@ -936164,14 +936296,17 @@ async function listDocsPreview({
936164
936296
  switch (listResponse.error.error) {
936165
936297
  case "UnauthorizedError":
936166
936298
  return context3.failAndThrow(
936167
- "Unauthorized to list preview deployments. Please run 'fern login' to refresh your credentials, or set the FERN_TOKEN environment variable."
936299
+ "Unauthorized to list preview deployments. Please run 'fern login' to refresh your credentials, or set the FERN_TOKEN environment variable.",
936300
+ void 0,
936301
+ { code: CliError.Code.NetworkError }
936168
936302
  );
936169
936303
  default: {
936170
936304
  const errorContent = listResponse.error.content != null && typeof listResponse.error.content === "object" && "body" in listResponse.error.content ? listResponse.error.content.body : listResponse.error.content;
936171
936305
  context3.logger.debug(`Error fetching preview deployments: ${JSON.stringify(errorContent)}`);
936172
936306
  return context3.failAndThrow(
936173
936307
  "Failed to fetch preview deployments. Please ensure you are logged in with 'fern login' or have FERN_TOKEN set, then try again.",
936174
- listResponse.error
936308
+ listResponse.error,
936309
+ { code: CliError.Code.NetworkError }
936175
936310
  );
936176
936311
  }
936177
936312
  }
@@ -936935,11 +937070,15 @@ async function downgrade({
936935
937070
  targetVersion
936936
937071
  }) {
936937
937072
  if (!targetVersion) {
936938
- return cliContext.failAndThrow("Please specify a version to downgrade to using --version");
937073
+ return cliContext.failAndThrow("Please specify a version to downgrade to using --version", void 0, {
937074
+ code: CliError.Code.ConfigError
937075
+ });
936939
937076
  }
936940
937077
  const fernDirectory = await getFernDirectory();
936941
937078
  if (fernDirectory == null) {
936942
- return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`);
937079
+ return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`, void 0, {
937080
+ code: CliError.Code.ConfigError
937081
+ });
936943
937082
  }
936944
937083
  const projectConfig = await cliContext.runTask(
936945
937084
  (context3) => loadProjectConfig({ directory: fernDirectory, context: context3 })
@@ -937017,7 +937156,10 @@ function convertType4(typeDeclaration2, ir15) {
937017
937156
  return convertUndiscriminatedUnion2({ undiscriminatedUnionDeclaration, docs });
937018
937157
  },
937019
937158
  _other: () => {
937020
- throw new Error("Encountered unknown type: " + shape.type);
937159
+ throw new CliError({
937160
+ message: "Encountered unknown type: " + shape.type,
937161
+ code: CliError.Code.InternalError
937162
+ });
937021
937163
  }
937022
937164
  });
937023
937165
  return {
@@ -937086,7 +937228,10 @@ function convertUnion({
937086
937228
  required: [getWireValue(unionTypeDeclaration.discriminant)]
937087
937229
  }),
937088
937230
  _other: () => {
937089
- throw new Error("Unknown SingleUnionTypeProperties: " + singleUnionType.shape.propertiesType);
937231
+ throw new CliError({
937232
+ message: "Unknown SingleUnionTypeProperties: " + singleUnionType.shape.propertiesType,
937233
+ code: CliError.Code.InternalError
937234
+ });
937090
937235
  }
937091
937236
  });
937092
937237
  });
@@ -937137,7 +937282,10 @@ function convertTypeReference4(typeReference2) {
937137
937282
  return {};
937138
937283
  },
937139
937284
  _other: () => {
937140
- throw new Error("Encountered unknown typeReference: " + typeReference2.type);
937285
+ throw new CliError({
937286
+ message: "Encountered unknown typeReference: " + typeReference2.type,
937287
+ code: CliError.Code.InternalError
937288
+ });
937141
937289
  }
937142
937290
  });
937143
937291
  }
@@ -937222,7 +937370,10 @@ function convertPrimitiveType3(primitiveType2) {
937222
937370
  };
937223
937371
  },
937224
937372
  _other: () => {
937225
- throw new Error("Encountered unknown primitiveType: " + primitiveType2.v1);
937373
+ throw new CliError({
937374
+ message: "Encountered unknown primitiveType: " + primitiveType2.v1,
937375
+ code: CliError.Code.InternalError
937376
+ });
937226
937377
  }
937227
937378
  }) ?? {};
937228
937379
  }
@@ -937312,7 +937463,10 @@ function convertPrimitiveType3(primitiveType2) {
937312
937463
  };
937313
937464
  },
937314
937465
  _other: () => {
937315
- throw new Error("Encountered unknown primitiveType: " + primitiveType2.v2);
937466
+ throw new CliError({
937467
+ message: "Encountered unknown primitiveType: " + primitiveType2.v2,
937468
+ code: CliError.Code.InternalError
937469
+ });
937316
937470
  }
937317
937471
  });
937318
937472
  }
@@ -937372,7 +937526,10 @@ function convertContainerType3(containerType) {
937372
937526
  });
937373
937527
  },
937374
937528
  _other: () => {
937375
- throw new Error("Encountered unknown containerType: " + containerType.type);
937529
+ throw new CliError({
937530
+ message: "Encountered unknown containerType: " + containerType.type,
937531
+ code: CliError.Code.InternalError
937532
+ });
937376
937533
  }
937377
937534
  });
937378
937535
  }
@@ -937491,7 +937648,10 @@ function convertServices2({
937491
937648
  });
937492
937649
  const pathsObject = paths[fullPath] ??= {};
937493
937650
  if (pathsObject[convertedHttpMethod] != null) {
937494
- throw new Error(`Duplicate ${convertedHttpMethod} endpoint at ${fullPath}`);
937651
+ throw new CliError({
937652
+ message: `Duplicate ${convertedHttpMethod} endpoint at ${fullPath}`,
937653
+ code: CliError.Code.ConfigError
937654
+ });
937495
937655
  }
937496
937656
  pathsObject[convertedHttpMethod] = operationObject;
937497
937657
  });
@@ -937576,12 +937736,15 @@ function convertHttpEndpoint4({
937576
937736
  if (httpEndpoint.baseUrl != null) {
937577
937737
  const baseUrlId = httpEndpoint.baseUrl;
937578
937738
  if (environments2?.environments.type !== "multipleBaseUrls") {
937579
- throw new Error("baseUrl is defined environments are not multipleBaseUrls");
937739
+ throw new CliError({
937740
+ message: "baseUrl is defined environments are not multipleBaseUrls",
937741
+ code: CliError.Code.InternalError
937742
+ });
937580
937743
  }
937581
937744
  operationObject.servers = environments2.environments.environments.map((environment2) => {
937582
937745
  const url3 = environment2.urls[baseUrlId];
937583
937746
  if (url3 == null) {
937584
- throw new Error("No URL defined for " + baseUrlId);
937747
+ throw new CliError({ message: "No URL defined for " + baseUrlId, code: CliError.Code.InternalError });
937585
937748
  }
937586
937749
  const server = { url: url3 };
937587
937750
  if (environment2.docs != null) {
@@ -937627,7 +937790,10 @@ function convertHttpMethod3(httpMethod) {
937627
937790
  return import_openapi_types3.OpenAPIV3.HttpMethods.HEAD;
937628
937791
  },
937629
937792
  _other: () => {
937630
- throw new Error("Encountered unknown http method: " + httpMethod);
937793
+ throw new CliError({
937794
+ message: "Encountered unknown http method: " + httpMethod,
937795
+ code: CliError.Code.InternalError
937796
+ });
937631
937797
  }
937632
937798
  });
937633
937799
  }
@@ -937719,7 +937885,10 @@ function convertRequestBody4({
937719
937885
  };
937720
937886
  },
937721
937887
  _other: () => {
937722
- throw new Error("Unknown FileUploadRequestProperty: " + property23.type);
937888
+ throw new CliError({
937889
+ message: "Unknown FileUploadRequestProperty: " + property23.type,
937890
+ code: CliError.Code.InternalError
937891
+ });
937723
937892
  }
937724
937893
  });
937725
937894
  return {
@@ -937747,7 +937916,10 @@ function convertRequestBody4({
937747
937916
  };
937748
937917
  },
937749
937918
  _other: () => {
937750
- throw new Error("Unknown HttpRequestBody type: " + httpRequest2.type);
937919
+ throw new CliError({
937920
+ message: "Unknown HttpRequestBody type: " + httpRequest2.type,
937921
+ code: CliError.Code.InternalError
937922
+ });
937751
937923
  }
937752
937924
  });
937753
937925
  }
@@ -937847,9 +938019,10 @@ function convertResponse3({
937847
938019
  for (const responseError of responseErrors) {
937848
938020
  const errorDeclaration = errorsByName[getErrorTypeNameKey(responseError.error)];
937849
938021
  if (errorDeclaration == null) {
937850
- throw new Error(
937851
- "Encountered undefined error declaration: " + getOriginalName(responseError.error.name)
937852
- );
938022
+ throw new CliError({
938023
+ message: "Encountered undefined error declaration: " + getOriginalName(responseError.error.name),
938024
+ code: CliError.Code.ResolutionError
938025
+ });
937853
938026
  }
937854
938027
  const responseForStatusCode = {
937855
938028
  description: responseError.docs ?? ""
@@ -937931,7 +938104,10 @@ function convertResponse3({
937931
938104
  }
937932
938105
  },
937933
938106
  _other: () => {
937934
- throw new Error("Unknown error discrimination strategy: " + errorDiscriminationStrategy.type);
938107
+ throw new CliError({
938108
+ message: "Unknown error discrimination strategy: " + errorDiscriminationStrategy.type,
938109
+ code: CliError.Code.InternalError
938110
+ });
937935
938111
  }
937936
938112
  });
937937
938113
  return responseByStatusCode;
@@ -937965,7 +938141,10 @@ function getErrorInfoByStatusCode({
937965
938141
  for (const responseError of responseErrors) {
937966
938142
  const errorDeclaration = errorsByName[getErrorTypeNameKey(responseError.error)];
937967
938143
  if (errorDeclaration == null) {
937968
- throw new Error("Encountered undefined error declaration: " + getOriginalName(responseError.error.name));
938144
+ throw new CliError({
938145
+ message: "Encountered undefined error declaration: " + getOriginalName(responseError.error.name),
938146
+ code: CliError.Code.ResolutionError
938147
+ });
937969
938148
  }
937970
938149
  const statusCode = errorDeclaration.statusCode;
937971
938150
  const statusCodeErrorInfo = errorInfoByStatusCode[statusCode];
@@ -938106,7 +938285,10 @@ function isTypeReferenceRequired({
938106
938285
  const key2 = getDeclaredTypeNameKey(typeReference2);
938107
938286
  const typeDeclaration2 = typesByName[key2];
938108
938287
  if (typeDeclaration2 == null) {
938109
- throw new Error("Encountered non-existent type: " + getOriginalName(typeReference2.name));
938288
+ throw new CliError({
938289
+ message: "Encountered non-existent type: " + getOriginalName(typeReference2.name),
938290
+ code: CliError.Code.ResolutionError
938291
+ });
938110
938292
  }
938111
938293
  if (typeDeclaration2.shape.type === "alias") {
938112
938294
  return isTypeReferenceRequired({ typeReference: typeDeclaration2.shape.aliasOf, typesByName });
@@ -938136,7 +938318,10 @@ function constructEndpointSecurity(apiAuth) {
938136
938318
  return [];
938137
938319
  },
938138
938320
  _other: () => {
938139
- throw new Error("Unknown auth scheme requirement: " + apiAuth.requirement);
938321
+ throw new CliError({
938322
+ message: "Unknown auth scheme requirement: " + apiAuth.requirement,
938323
+ code: CliError.Code.InternalError
938324
+ });
938140
938325
  }
938141
938326
  });
938142
938327
  }
@@ -938163,7 +938348,10 @@ function constructSecuritySchemes(apiAuth) {
938163
938348
  }),
938164
938349
  inferred: () => void 0,
938165
938350
  _other: () => {
938166
- throw new Error("Unknown auth scheme: " + scheme.type);
938351
+ throw new CliError({
938352
+ message: "Unknown auth scheme: " + scheme.type,
938353
+ code: CliError.Code.InternalError
938354
+ });
938167
938355
  }
938168
938356
  });
938169
938357
  if (oasScheme) {
@@ -938180,7 +938368,10 @@ function getNameForAuthScheme(authScheme) {
938180
938368
  oauth: () => "BearerAuth",
938181
938369
  header: (header) => `${getPascalCaseUnsafe(header.name)}Auth`,
938182
938370
  _other: () => {
938183
- throw new Error("Unknown auth scheme: " + authScheme.type);
938371
+ throw new CliError({
938372
+ message: "Unknown auth scheme: " + authScheme.type,
938373
+ code: CliError.Code.InternalError
938374
+ });
938184
938375
  }
938185
938376
  });
938186
938377
  }
@@ -938499,7 +938690,7 @@ async function generateWorkspace({
938499
938690
  const suggestedCommand = `fern ${currentArgs} --${GROUP_CLI_OPTION} ${name2}`;
938500
938691
  return ` \u203A ${source_default.bold(name2.padEnd(longestGroupName))} ${source_default.dim(suggestedCommand)}`;
938501
938692
  }).join("\n");
938502
- return context3.failAndThrow(message);
938693
+ return context3.failAndThrow(message, void 0, { code: CliError.Code.NetworkError });
938503
938694
  }
938504
938695
  const resolvedGroupNames = resolveGroupAlias(
938505
938696
  groupNameOrDefault,
@@ -938509,7 +938700,7 @@ async function generateWorkspace({
938509
938700
  );
938510
938701
  const { ai: ai7, replay } = workspace.generatorsConfiguration;
938511
938702
  if (!useLocalDocker && !token) {
938512
- return context3.failAndThrow("Please run fern login");
938703
+ return context3.failAndThrow("Please run fern login", void 0, { code: CliError.Code.AuthError });
938513
938704
  }
938514
938705
  await Promise.all(
938515
938706
  resolvedGroupNames.map(async (resolvedGroupName) => {
@@ -938517,7 +938708,9 @@ async function generateWorkspace({
938517
938708
  (otherGroup) => otherGroup.groupName === resolvedGroupName
938518
938709
  );
938519
938710
  if (group == null) {
938520
- return context3.failAndThrow(`Group '${resolvedGroupName}' does not exist.`);
938711
+ return context3.failAndThrow(`Group '${resolvedGroupName}' does not exist.`, void 0, {
938712
+ code: CliError.Code.ConfigError
938713
+ });
938521
938714
  }
938522
938715
  const filterResult = filterGenerators({
938523
938716
  generators: group.generators,
@@ -938526,7 +938719,7 @@ async function generateWorkspace({
938526
938719
  groupName: resolvedGroupName
938527
938720
  });
938528
938721
  if (!filterResult.ok) {
938529
- return context3.failAndThrow(filterResult.error);
938722
+ return context3.failAndThrow(filterResult.error, void 0, { code: CliError.Code.ConfigError });
938530
938723
  }
938531
938724
  group = { ...group, generators: filterResult.generators };
938532
938725
  if (lfsOverride != null) {
@@ -938595,7 +938788,9 @@ function resolveGroupAlias(groupNameOrAlias, groupAliases, availableGroups, cont
938595
938788
  for (const groupName of aliasGroups) {
938596
938789
  if (!availableGroups.includes(groupName)) {
938597
938790
  context3.failAndThrow(
938598
- `Group alias '${groupNameOrAlias}' references non-existent group '${groupName}'. Available groups: ${availableGroups.join(", ")}`
938791
+ `Group alias '${groupNameOrAlias}' references non-existent group '${groupName}'. Available groups: ${availableGroups.join(", ")}`,
938792
+ void 0,
938793
+ { code: CliError.Code.NetworkError }
938599
938794
  );
938600
938795
  }
938601
938796
  }
@@ -938607,7 +938802,9 @@ function resolveGroupAlias(groupNameOrAlias, groupAliases, availableGroups, cont
938607
938802
  const availableAliases = Object.keys(groupAliases);
938608
938803
  const suggestions = [...availableGroups, ...availableAliases];
938609
938804
  context3.failAndThrow(
938610
- `'${groupNameOrAlias}' is not a valid group or alias. Available groups: ${availableGroups.join(", ")}` + (availableAliases.length > 0 ? `. Available aliases: ${availableAliases.join(", ")}` : "")
938805
+ `'${groupNameOrAlias}' is not a valid group or alias. Available groups: ${availableGroups.join(", ")}` + (availableAliases.length > 0 ? `. Available aliases: ${availableAliases.join(", ")}` : ""),
938806
+ void 0,
938807
+ { code: CliError.Code.NetworkError }
938611
938808
  );
938612
938809
  return [];
938613
938810
  }
@@ -938742,7 +938939,7 @@ async function generateAPIWorkspaces({
938742
938939
  force
938743
938940
  );
938744
938941
  if (!shouldProceed) {
938745
- cliContext.failAndThrow("Generation cancelled");
938942
+ cliContext.failAndThrow("Generation cancelled", void 0, { code: CliError.Code.ConfigError });
938746
938943
  }
938747
938944
  }
938748
938945
  }
@@ -938921,7 +939118,10 @@ function buildPreviewDomain({ orgId, previewId }) {
938921
939118
  const availableSpace = SUBDOMAIN_LIMIT - prefix2.length;
938922
939119
  const minIdLength = 8;
938923
939120
  if (availableSpace < minIdLength) {
938924
- throw new Error(`Organization name "${orgId}" is too long to generate a valid preview URL`);
939121
+ throw new CliError({
939122
+ message: `Organization name "${orgId}" is too long to generate a valid preview URL`,
939123
+ code: CliError.Code.InternalError
939124
+ });
938925
939125
  }
938926
939126
  const truncatedId = sanitizedId.slice(0, availableSpace).replace(/-+$/, "");
938927
939127
  return `${prefix2}${truncatedId}.${DOMAIN_SUFFIX}`;
@@ -938941,7 +939141,9 @@ async function generateDocsWorkspace({
938941
939141
  }) {
938942
939142
  const docsWorkspace = project.docsWorkspaces;
938943
939143
  if (docsWorkspace == null) {
938944
- cliContext.failAndThrow("No docs.yml file found. Please make sure your project has one.");
939144
+ cliContext.failAndThrow("No docs.yml file found. Please make sure your project has one.", void 0, {
939145
+ code: CliError.Code.ConfigError
939146
+ });
938945
939147
  return;
938946
939148
  }
938947
939149
  const hasFdrOriginOverride = !!process.env["FERN_FDR_ORIGIN"] || !!process.env["OVERRIDE_FDR_ORIGIN"];
@@ -938963,7 +939165,9 @@ ${source_default.yellow("?")} Are you sure you want to continue?`,
938963
939165
  const fernToken = await getToken2();
938964
939166
  if (!fernToken) {
938965
939167
  cliContext.failAndThrow(
938966
- "No token found. Please set the FERN_TOKEN environment variable or run `fern login`."
939168
+ "No token found. Please set the FERN_TOKEN environment variable or run `fern login`.",
939169
+ void 0,
939170
+ { code: CliError.Code.AuthError }
938967
939171
  );
938968
939172
  return;
938969
939173
  }
@@ -939021,7 +939225,9 @@ ${source_default.yellow("?")} Are you sure you want to continue?`,
939021
939225
  context3.logger.error(`${error50.relativeFilepath}: ${error50.message}`);
939022
939226
  }
939023
939227
  context3.failAndThrow(
939024
- `OpenAPI spec validation failed with ${errors4.length} error${errors4.length !== 1 ? "s" : ""}. Fix the errors above before generating docs.`
939228
+ `OpenAPI spec validation failed with ${errors4.length} error${errors4.length !== 1 ? "s" : ""}. Fix the errors above before generating docs.`,
939229
+ void 0,
939230
+ { code: CliError.Code.ValidationError }
939025
939231
  );
939026
939232
  }
939027
939233
  }
@@ -939123,7 +939329,10 @@ async function generateDynamicIrForWorkspaces({
939123
939329
  disableDynamicExamples
939124
939330
  });
939125
939331
  if (intermediateRepresentation.dynamic == null) {
939126
- throw new Error("Internal error; dynamic IR was not generated");
939332
+ throw new CliError({
939333
+ message: "Internal error; dynamic IR was not generated",
939334
+ code: CliError.Code.InternalError
939335
+ });
939127
939336
  }
939128
939337
  const irOutputFilePath = import_path83.default.resolve(irFilepath);
939129
939338
  await streamObjectToFile(AbsoluteFilePath2.of(irOutputFilePath), intermediateRepresentation.dynamic);
@@ -939334,10 +939543,14 @@ async function compareOpenAPISpecs({
939334
939543
  }) {
939335
939544
  await cliContext.runTask(async (context3) => {
939336
939545
  if (!await doesPathExist(originalPath)) {
939337
- return context3.failAndThrow(`Original file does not exist: ${originalPath}`);
939546
+ return context3.failAndThrow(`Original file does not exist: ${originalPath}`, void 0, {
939547
+ code: CliError.Code.ConfigError
939548
+ });
939338
939549
  }
939339
939550
  if (!await doesPathExist(modifiedPath)) {
939340
- return context3.failAndThrow(`Modified file does not exist: ${modifiedPath}`);
939551
+ return context3.failAndThrow(`Modified file does not exist: ${modifiedPath}`, void 0, {
939552
+ code: CliError.Code.ConfigError
939553
+ });
939341
939554
  }
939342
939555
  context3.logger.info(`Comparing ${originalPath} with ${modifiedPath}`);
939343
939556
  const original = await loadSpec2(originalPath, context3);
@@ -939374,7 +939587,9 @@ async function loadSpec2(filepath, context3) {
939374
939587
  try {
939375
939588
  return jsYaml.load(contents);
939376
939589
  } catch (err) {
939377
- return context3.failAndThrow(`Failed to parse file as JSON or YAML: ${filepath}`);
939590
+ return context3.failAndThrow(`Failed to parse file as JSON or YAML: ${filepath}`, void 0, {
939591
+ code: CliError.Code.ParseError
939592
+ });
939378
939593
  }
939379
939594
  }
939380
939595
  }
@@ -939501,7 +939716,9 @@ async function readExistingOverrides(overridesFilepath, context3) {
939501
939716
  parsedOverrides = jsYaml.load(contents, { json: true });
939502
939717
  }
939503
939718
  } catch (err) {
939504
- return context3.failAndThrow(`Failed to read OpenAPI overrides from file ${overridesFilepath}`);
939719
+ return context3.failAndThrow(`Failed to read OpenAPI overrides from file ${overridesFilepath}`, void 0, {
939720
+ code: CliError.Code.ConfigError
939721
+ });
939505
939722
  }
939506
939723
  return parsedOverrides;
939507
939724
  }
@@ -939615,7 +939832,9 @@ async function installDependencies({ cliContext }) {
939615
939832
  const failed = results.filter((r23) => !r23.success);
939616
939833
  if (failed.length > 0) {
939617
939834
  context3.failAndThrow(
939618
- `Failed to install: ${failed.map((r23) => r23.name).join(", ")}. Check network connectivity and try again.`
939835
+ `Failed to install: ${failed.map((r23) => r23.name).join(", ")}. Check network connectivity and try again.`,
939836
+ void 0,
939837
+ { code: CliError.Code.EnvironmentError }
939619
939838
  );
939620
939839
  }
939621
939840
  context3.logger.info("All dependencies installed successfully.");
@@ -940054,10 +940273,14 @@ async function mergeOpenAPIWithOverrides({
940054
940273
  }) {
940055
940274
  await cliContext.runTask(async (context3) => {
940056
940275
  if (!await doesPathExist(openapiPath)) {
940057
- return context3.failAndThrow(`OpenAPI spec file does not exist: ${openapiPath}`);
940276
+ return context3.failAndThrow(`OpenAPI spec file does not exist: ${openapiPath}`, void 0, {
940277
+ code: CliError.Code.ConfigError
940278
+ });
940058
940279
  }
940059
940280
  if (!await doesPathExist(overridesPath)) {
940060
- return context3.failAndThrow(`Overrides file does not exist: ${overridesPath}`);
940281
+ return context3.failAndThrow(`Overrides file does not exist: ${overridesPath}`, void 0, {
940282
+ code: CliError.Code.ConfigError
940283
+ });
940061
940284
  }
940062
940285
  context3.logger.info(`Merging ${overridesPath} into ${openapiPath}`);
940063
940286
  const openapi = await loadYamlOrJson(openapiPath, context3);
@@ -940077,7 +940300,9 @@ async function loadYamlOrJson(filepath, context3) {
940077
940300
  try {
940078
940301
  return jsYaml.load(contents);
940079
940302
  } catch (err) {
940080
- return context3.failAndThrow(`Failed to parse file as JSON or YAML: ${filepath}`);
940303
+ return context3.failAndThrow(`Failed to parse file as JSON or YAML: ${filepath}`, void 0, {
940304
+ code: CliError.Code.ParseError
940305
+ });
940081
940306
  }
940082
940307
  }
940083
940308
  }
@@ -940666,7 +940891,9 @@ async function mockServer({
940666
940891
  command: "fern mock"
940667
940892
  });
940668
940893
  if (project.apiWorkspaces.length !== 1 || project.apiWorkspaces[0] == null) {
940669
- return cliContext.failAndThrow(`No API specified. Use the --${API_CLI_OPTION} option.`);
940894
+ return cliContext.failAndThrow(`No API specified. Use the --${API_CLI_OPTION} option.`, void 0, {
940895
+ code: CliError.Code.ConfigError
940896
+ });
940670
940897
  }
940671
940898
  const workspace = project.apiWorkspaces[0];
940672
940899
  await cliContext.runTaskForWorkspace(workspace, async (context3) => {
@@ -940724,7 +940951,9 @@ async function registerWorkspacesV1({
940724
940951
  project.apiWorkspaces.map(async (workspace) => {
940725
940952
  await cliContext.runTaskForWorkspace(workspace, async (context3) => {
940726
940953
  if (workspace instanceof OSSWorkspace) {
940727
- context3.failWithoutThrowing("Registering from OpenAPI not currently supported.");
940954
+ context3.failWithoutThrowing("Registering from OpenAPI not currently supported.", void 0, {
940955
+ code: CliError.Code.ConfigError
940956
+ });
940728
940957
  return;
940729
940958
  }
940730
940959
  const resolvedWorkspace = await workspace.toFernWorkspace({ context: context3 });
@@ -940737,10 +940966,12 @@ async function registerWorkspacesV1({
940737
940966
  if (!registerApiResponse.ok) {
940738
940967
  registerApiResponse.error._visit({
940739
940968
  versionAlreadyExists: () => {
940740
- context3.failAndThrow(`Version ${version7 ?? ""} is already registered`);
940969
+ context3.failAndThrow(`Version ${version7 ?? ""} is already registered`, void 0, {
940970
+ code: CliError.Code.VersionError
940971
+ });
940741
940972
  },
940742
940973
  _other: (value) => {
940743
- context3.failAndThrow("Failed to register", value);
940974
+ context3.failAndThrow("Failed to register", value, { code: CliError.Code.NetworkError });
940744
940975
  }
940745
940976
  });
940746
940977
  return;
@@ -940810,7 +941041,7 @@ var execAsync = (0, import_util70.promisify)(import_child_process10.exec);
940810
941041
  async function getClientRegistry(context3, project) {
940811
941042
  const workspace = project.apiWorkspaces[0];
940812
941043
  if (workspace == null) {
940813
- context3.failAndThrow("No API workspaces found in the project.");
941044
+ context3.failAndThrow("No API workspaces found in the project.", void 0, { code: CliError.Code.ConfigError });
940814
941045
  }
940815
941046
  const generatorsConfig = await loadGeneratorsConfiguration({
940816
941047
  absolutePathToWorkspace: workspace.absoluteFilePath,
@@ -940818,11 +941049,17 @@ async function getClientRegistry(context3, project) {
940818
941049
  context: context3
940819
941050
  });
940820
941051
  if (generatorsConfig == null) {
940821
- context3.failAndThrow("Could not find generators.yml in the workspace. Is this a valid fern project?");
941052
+ context3.failAndThrow(
941053
+ "Could not find generators.yml in the workspace. Is this a valid fern project?",
941054
+ void 0,
941055
+ { code: CliError.Code.ConfigError }
941056
+ );
940822
941057
  }
940823
941058
  if (generatorsConfig.ai == null) {
940824
941059
  context3.failAndThrow(
940825
- "No AI service configuration found in generators.yml. Please add an 'ai' section with provider and model."
941060
+ "No AI service configuration found in generators.yml. Please add an 'ai' section with provider and model.",
941061
+ void 0,
941062
+ { code: CliError.Code.ConfigError }
940826
941063
  );
940827
941064
  }
940828
941065
  context3.logger.debug(`Using AI service: ${generatorsConfig.ai.provider} with model ${generatorsConfig.ai.model}`);
@@ -940840,11 +941077,11 @@ async function sdkDiffCommand({
940840
941077
  From: ${fromPath}
940841
941078
  To: ${toPath5}`);
940842
941079
  if (!await doesPathExist(fromPath, "directory")) {
940843
- context3.failWithoutThrowing(`Directory not found: ${fromPath}`);
941080
+ context3.failWithoutThrowing(`Directory not found: ${fromPath}`, void 0, { code: CliError.Code.ConfigError });
940844
941081
  throw new TaskAbortSignal();
940845
941082
  }
940846
941083
  if (!await doesPathExist(toPath5, "directory")) {
940847
- context3.failWithoutThrowing(`Directory not found: ${toPath5}`);
941084
+ context3.failWithoutThrowing(`Directory not found: ${toPath5}`, void 0, { code: CliError.Code.ConfigError });
940848
941085
  throw new TaskAbortSignal();
940849
941086
  }
940850
941087
  const clientRegistry = await getClientRegistry(context3, project);
@@ -940866,7 +941103,9 @@ async function sdkDiffCommand({
940866
941103
  const diffBytes = Buffer.byteLength(gitDiff, "utf-8");
940867
941104
  if (diffBytes > MAX_RAW_DIFF_BYTES) {
940868
941105
  return context3.failAndThrow(
940869
- `Diff too large for analysis (${(diffBytes / 1e6).toFixed(1)}MB, limit ${MAX_RAW_DIFF_BYTES / 1e6}MB). Try excluding generated files or splitting the comparison.`
941106
+ `Diff too large for analysis (${(diffBytes / 1e6).toFixed(1)}MB, limit ${MAX_RAW_DIFF_BYTES / 1e6}MB). Try excluding generated files or splitting the comparison.`,
941107
+ void 0,
941108
+ { code: CliError.Code.ConfigError }
940870
941109
  );
940871
941110
  }
940872
941111
  const chunks = diffBytes > MAX_AI_DIFF_BYTES ? service.chunkDiff(gitDiff, MAX_AI_DIFF_BYTES) : [gitDiff];
@@ -940931,7 +941170,7 @@ async function sdkDiffCommand({
940931
941170
  const rawEntries = allChangelogEntries.map((e6) => e6.startsWith("- ") ? e6 : `- ${e6}`).join("\n");
940932
941171
  try {
940933
941172
  context3.logger.debug(`Consolidating ${allChangelogEntries.length} changelog entries via AI rollup`);
940934
- const rollup = await bamlClient.ConsolidateChangelog(rawEntries, bestBump, "unknown");
941173
+ const rollup = await bamlClient.ConsolidateChangelog(rawEntries, bestBump, "unknown", "", "");
940935
941174
  changelogEntry = rollup.consolidated_changelog?.trim() || rawEntries;
940936
941175
  versionBumpReason = rollup.version_bump_reason?.trim() || "";
940937
941176
  } catch (rollupError) {
@@ -940953,7 +941192,9 @@ async function sdkDiffCommand({
940953
941192
  } catch (error50) {
940954
941193
  const errorMessage = extractErrorMessage(error50);
940955
941194
  context3.failWithoutThrowing(
940956
- `Failed to analyze SDK diff. Diff stats: ${gitDiff.length.toLocaleString()} chars, ${diffSizeKB}KB, ${fileCount} files changed. ` + (cappedChunks.length > 1 ? `The diff was split into ${cappedChunks.length} chunks but analysis still failed. ` : "") + `Error: ${errorMessage}`
941195
+ `Failed to analyze SDK diff. Diff stats: ${gitDiff.length.toLocaleString()} chars, ${diffSizeKB}KB, ${fileCount} files changed. ` + (cappedChunks.length > 1 ? `The diff was split into ${cappedChunks.length} chunks but analysis still failed. ` : "") + `Error: ${errorMessage}`,
941196
+ void 0,
941197
+ { code: CliError.Code.NetworkError }
940957
941198
  );
940958
941199
  throw new TaskAbortSignal();
940959
941200
  }
@@ -940974,7 +941215,9 @@ async function generateDiff({
940974
941215
  if (typeof error50 === "object" && error50 != null && "code" in error50 && error50.code === 1 && "stdout" in error50 && typeof error50.stdout === "string") {
940975
941216
  return error50.stdout;
940976
941217
  }
940977
- return context3.failAndThrow(`Failed to generate diff: ${extractErrorMessage(error50)}`);
941218
+ return context3.failAndThrow(`Failed to generate diff: ${extractErrorMessage(error50)}`, void 0, {
941219
+ code: CliError.Code.InternalError
941220
+ });
940978
941221
  }
940979
941222
  }
940980
941223
 
@@ -941160,7 +941403,9 @@ async function sdkPreview({
941160
941403
  return askToLogin(context3);
941161
941404
  });
941162
941405
  if (token == null) {
941163
- return cliContext.failAndThrow("Authentication required. Run 'fern login' or set FERN_TOKEN.");
941406
+ return cliContext.failAndThrow("Authentication required. Run 'fern login' or set FERN_TOKEN.", void 0, {
941407
+ code: CliError.Code.AuthError
941408
+ });
941164
941409
  }
941165
941410
  const project = await loadProjectAndRegisterWorkspacesWithContext(cliContext, {
941166
941411
  commandLineApiWorkspace: apiName,
@@ -941212,19 +941457,25 @@ async function sdkPreview({
941212
941457
  const groupNameOrDefault = groupName ?? workspace.generatorsConfiguration.defaultGroup;
941213
941458
  if (groupNameOrDefault == null) {
941214
941459
  return cliContext.failAndThrow(
941215
- `No group specified. Use the --${GROUP_CLI_OPTION} option, or set "${DEFAULT_GROUP_GENERATORS_CONFIG_KEY}" in ${GENERATORS_CONFIGURATION_FILENAME}`
941460
+ `No group specified. Use the --${GROUP_CLI_OPTION} option, or set "${DEFAULT_GROUP_GENERATORS_CONFIG_KEY}" in ${GENERATORS_CONFIGURATION_FILENAME}`,
941461
+ void 0,
941462
+ { code: CliError.Code.ConfigError }
941216
941463
  );
941217
941464
  }
941218
941465
  const group = workspace.generatorsConfiguration.groups.find((g19) => g19.groupName === groupNameOrDefault);
941219
941466
  if (group == null) {
941220
941467
  return cliContext.failAndThrow(
941221
- `Group '${groupNameOrDefault}' does not exist in ${GENERATORS_CONFIGURATION_FILENAME}`
941468
+ `Group '${groupNameOrDefault}' does not exist in ${GENERATORS_CONFIGURATION_FILENAME}`,
941469
+ void 0,
941470
+ { code: CliError.Code.ConfigError }
941222
941471
  );
941223
941472
  }
941224
941473
  const generators = generatorFilter != null ? group.generators.filter((g19) => g19.name === generatorFilter) : group.generators;
941225
941474
  if (generatorFilter != null && generators.length === 0) {
941226
941475
  return cliContext.failAndThrow(
941227
- `Generator '${generatorFilter}' not found in group '${groupNameOrDefault}' in ${GENERATORS_CONFIGURATION_FILENAME}`
941476
+ `Generator '${generatorFilter}' not found in group '${groupNameOrDefault}' in ${GENERATORS_CONFIGURATION_FILENAME}`,
941477
+ void 0,
941478
+ { code: CliError.Code.ConfigError }
941228
941479
  );
941229
941480
  }
941230
941481
  const npmGenerators = generators.filter((g19) => isNpmGenerator(g19.name));
@@ -941236,14 +941487,18 @@ async function sdkPreview({
941236
941487
  }
941237
941488
  if (npmGenerators.length === 0) {
941238
941489
  return cliContext.failAndThrow(
941239
- `No supported generators found in group '${groupNameOrDefault}'. SDK preview currently only supports TypeScript/npm generators.`
941490
+ `No supported generators found in group '${groupNameOrDefault}'. SDK preview currently only supports TypeScript/npm generators.`,
941491
+ void 0,
941492
+ { code: CliError.Code.ConfigError }
941240
941493
  );
941241
941494
  }
941242
941495
  for (const generator of npmGenerators) {
941243
941496
  const originalPackageName = getPackageNameFromGeneratorConfig(generator);
941244
941497
  if (originalPackageName == null) {
941245
941498
  return cliContext.failAndThrow(
941246
- `Could not determine package name for generator '${generator.name}'. Ensure 'output.package-name' is set in ${GENERATORS_CONFIGURATION_FILENAME}.`
941499
+ `Could not determine package name for generator '${generator.name}'. Ensure 'output.package-name' is set in ${GENERATORS_CONFIGURATION_FILENAME}.`,
941500
+ void 0,
941501
+ { code: CliError.Code.ConfigError }
941247
941502
  );
941248
941503
  }
941249
941504
  const previewPackageName = toPreviewPackageName(originalPackageName, project.config.organization);
@@ -941572,7 +941827,7 @@ Resolved to: ${installationMethod.resolvedPath}`;
941572
941827
  }
941573
941828
  errorMessage += "\n\nPlease manually update using your package manager (npm, pnpm, yarn, bun, or brew).";
941574
941829
  errorMessage += "\nFor more diagnostic information, run with: FERN_LOG_LEVEL=debug fern self-update";
941575
- return cliContext.failAndThrow(errorMessage);
941830
+ return cliContext.failAndThrow(errorMessage, void 0, { code: CliError.Code.EnvironmentError });
941576
941831
  }
941577
941832
  cliContext.logger.info(`Detected installation method: ${source_default.cyan(installationMethod.type)}`);
941578
941833
  if (installationMethod.detectedPath != null) {
@@ -941584,7 +941839,9 @@ Resolved to: ${installationMethod.resolvedPath}`;
941584
941839
  const updateCommand = getUpdateCommand(installationMethod, version7);
941585
941840
  if (updateCommand.length === 0) {
941586
941841
  return cliContext.failAndThrow(
941587
- `Unable to construct update command for installation method: ${installationMethod.type}`
941842
+ `Unable to construct update command for installation method: ${installationMethod.type}`,
941843
+ void 0,
941844
+ { code: CliError.Code.EnvironmentError }
941588
941845
  );
941589
941846
  }
941590
941847
  if (installationMethod.type === "brew" && version7 != null) {
@@ -941603,7 +941860,7 @@ Resolved to: ${installationMethod.resolvedPath}`;
941603
941860
  cliContext.logger.info(`Running: ${source_default.dim(commandString)}`);
941604
941861
  const [command3, ...args] = updateCommand;
941605
941862
  if (command3 == null) {
941606
- return cliContext.failAndThrow("Invalid update command");
941863
+ return cliContext.failAndThrow("Invalid update command", void 0, { code: CliError.Code.InternalError });
941607
941864
  }
941608
941865
  const { failed, stderr } = await loggingExeca(cliContext.logger, command3, args, {
941609
941866
  doNotPipeOutput: false,
@@ -941611,7 +941868,9 @@ Resolved to: ${installationMethod.resolvedPath}`;
941611
941868
  });
941612
941869
  if (failed) {
941613
941870
  cliContext.logger.error(`Failed to update Fern CLI: ${stderr}`);
941614
- return cliContext.failAndThrow("Update failed. Please try updating manually.");
941871
+ return cliContext.failAndThrow("Update failed. Please try updating manually.", void 0, {
941872
+ code: CliError.Code.EnvironmentError
941873
+ });
941615
941874
  }
941616
941875
  cliContext.logger.info(source_default.green("\u2713 Fern CLI updated successfully!"));
941617
941876
  }
@@ -941628,10 +941887,14 @@ async function testOutput({
941628
941887
  command: "fern test"
941629
941888
  });
941630
941889
  if (testCommand == null) {
941631
- return cliContext.failAndThrow("No test command specified. Use the --command option.");
941890
+ return cliContext.failAndThrow("No test command specified. Use the --command option.", void 0, {
941891
+ code: CliError.Code.ConfigError
941892
+ });
941632
941893
  }
941633
941894
  if (project.apiWorkspaces.length !== 1 || project.apiWorkspaces[0] == null) {
941634
- return cliContext.failAndThrow(`No API specified. Use the --${API_CLI_OPTION} option.`);
941895
+ return cliContext.failAndThrow(`No API specified. Use the --${API_CLI_OPTION} option.`, void 0, {
941896
+ code: CliError.Code.ConfigError
941897
+ });
941635
941898
  }
941636
941899
  const workspace = project.apiWorkspaces[0];
941637
941900
  await cliContext.runTaskForWorkspace(workspace, async (context3) => {
@@ -941676,7 +941939,7 @@ async function testOutput({
941676
941939
  mockServer2.stop();
941677
941940
  context3.logger.error("Tests failed, Fern mock server stopping.");
941678
941941
  context3.logger.error("View test output above.");
941679
- cliContext.failAndThrow();
941942
+ cliContext.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
941680
941943
  }
941681
941944
  }
941682
941945
  mockServer2.stop();
@@ -941703,15 +941966,25 @@ async function generateToken({
941703
941966
  }
941704
941967
  response.error._visit({
941705
941968
  organizationNotFoundError: () => taskContext.failAndThrow(
941706
- `Failed to create token because the organization ${orgId} was not found. Please reach out to support@buildwithfern.com`
941969
+ `Failed to create token because the organization ${orgId} was not found. Please reach out to support@buildwithfern.com`,
941970
+ void 0,
941971
+ { code: CliError.Code.AuthError }
941707
941972
  ),
941708
941973
  unauthorizedError: () => taskContext.failAndThrow(
941709
- `Failed to create token because you are not in the ${orgId} organization. Please reach out to support@buildwithfern.com`
941974
+ `Failed to create token because you are not in the ${orgId} organization. Please reach out to support@buildwithfern.com`,
941975
+ void 0,
941976
+ { code: CliError.Code.AuthError }
941710
941977
  ),
941711
941978
  missingOrgPermissionsError: () => taskContext.failAndThrow(
941712
- `Failed to create token because you do not have the required permissions in the ${orgId} organization. Please reach out to support@buildwithfern.com`
941979
+ `Failed to create token because you do not have the required permissions in the ${orgId} organization. Please reach out to support@buildwithfern.com`,
941980
+ void 0,
941981
+ { code: CliError.Code.AuthError }
941713
941982
  ),
941714
- _other: () => taskContext.failAndThrow("Failed to create token. Please reach out to support@buildwithfern.com")
941983
+ _other: () => taskContext.failAndThrow(
941984
+ "Failed to create token. Please reach out to support@buildwithfern.com",
941985
+ void 0,
941986
+ { code: CliError.Code.AuthError }
941987
+ )
941715
941988
  });
941716
941989
  }
941717
941990
 
@@ -941766,7 +942039,10 @@ function isIntrospectionResult(data2) {
941766
942039
  }
941767
942040
  function extractIntrospectionData(data2) {
941768
942041
  if (!data2 || typeof data2 !== "object") {
941769
- throw new Error("Data does not contain valid GraphQL introspection result");
942042
+ throw new CliError({
942043
+ message: "Data does not contain valid GraphQL introspection result",
942044
+ code: CliError.Code.InternalError
942045
+ });
941770
942046
  }
941771
942047
  if ("__schema" in data2 && data2.__schema) {
941772
942048
  return data2;
@@ -941774,7 +942050,10 @@ function extractIntrospectionData(data2) {
941774
942050
  if ("data" in data2 && data2.data && typeof data2.data === "object" && "__schema" in data2.data) {
941775
942051
  return data2.data;
941776
942052
  }
941777
- throw new Error("Data does not contain valid GraphQL introspection result");
942053
+ throw new CliError({
942054
+ message: "Data does not contain valid GraphQL introspection result",
942055
+ code: CliError.Code.InternalError
942056
+ });
941778
942057
  }
941779
942058
  async function tryGraphQLIntrospection(url3, logger4) {
941780
942059
  try {
@@ -941901,7 +942180,7 @@ Attempt 2 (GET direct fetch): ${getResult.error}
941901
942180
  To update the schema from its defined origin, please ensure the origin either:
941902
942181
  1. Accepts GraphQL introspection queries via POST, or
941903
942182
  2. Returns introspection results directly via GET`;
941904
- throw new Error(errorMessage);
942183
+ throw new CliError({ message: errorMessage, code: CliError.Code.InternalError });
941905
942184
  }
941906
942185
  async function updateApiSpec({
941907
942186
  cliContext,
@@ -945135,7 +945414,7 @@ async function rerunFernCliAtVersion({
945135
945414
  if (throwOnError) {
945136
945415
  throw new RerunCliError({ version: version7, stdout, stderr });
945137
945416
  }
945138
- cliContext.failWithoutThrowing();
945417
+ cliContext.failWithoutThrowing(void 0, void 0, { code: CliError.Code.InternalError });
945139
945418
  }
945140
945419
  }
945141
945420
 
@@ -945279,7 +945558,9 @@ function validateVersionAhead({
945279
945558
  const versionAhead = isVersionAhead(targetVersion, currentVersion);
945280
945559
  if (!versionAhead) {
945281
945560
  cliContext.failAndThrow(
945282
- `Cannot upgrade because target version (${targetVersion}) is not ahead of existing version ${currentVersion}`
945561
+ `Cannot upgrade because target version (${targetVersion}) is not ahead of existing version ${currentVersion}`,
945562
+ void 0,
945563
+ { code: CliError.Code.VersionError }
945283
945564
  );
945284
945565
  }
945285
945566
  }
@@ -945334,7 +945615,9 @@ async function upgrade({
945334
945615
  }
945335
945616
  const fernDirectory2 = await getFernDirectory();
945336
945617
  if (fernDirectory2 == null) {
945337
- return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`);
945618
+ return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`, void 0, {
945619
+ code: CliError.Code.ConfigError
945620
+ });
945338
945621
  }
945339
945622
  const projectConfig2 = await cliContext.runTask(
945340
945623
  (context3) => loadProjectConfig({ directory: fernDirectory2, context: context3 })
@@ -945368,7 +945651,9 @@ async function upgrade({
945368
945651
  if (cliContext.environment.packageVersion === resolvedTargetVersion || isLocalDev) {
945369
945652
  const fernDirectory2 = await getFernDirectory();
945370
945653
  if (fernDirectory2 == null) {
945371
- return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`);
945654
+ return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`, void 0, {
945655
+ code: CliError.Code.ConfigError
945656
+ });
945372
945657
  }
945373
945658
  const projectConfig2 = await cliContext.runTask(
945374
945659
  (context3) => loadProjectConfig({ directory: fernDirectory2, context: context3 })
@@ -945410,7 +945695,9 @@ async function upgrade({
945410
945695
  });
945411
945696
  const fernDirectory = await getFernDirectory();
945412
945697
  if (fernDirectory == null) {
945413
- return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`);
945698
+ return cliContext.failAndThrow(`Directory "${FERN_DIRECTORY}" not found.`, void 0, {
945699
+ code: CliError.Code.ConfigError
945700
+ });
945414
945701
  }
945415
945702
  const projectConfig = await cliContext.runTask(
945416
945703
  (context3) => loadProjectConfig({ directory: fernDirectory, context: context3 })
@@ -945449,7 +945736,9 @@ async function upgrade({
945449
945736
  const isVersionNotFound = errorOutput.includes("ETARGET") || errorOutput.includes("E404") || errorOutput.includes("404 Not Found") || errorOutput.includes("No matching version found") || errorOutput.includes("version not found");
945450
945737
  if (isVersionNotFound) {
945451
945738
  return cliContext.failAndThrow(
945452
- `Failed to upgrade to ${resolvedTargetVersion} because it does not exist. See https://www.npmjs.com/package/${cliContext.environment.packageName}?activeTab=versions.`
945739
+ `Failed to upgrade to ${resolvedTargetVersion} because it does not exist. See https://www.npmjs.com/package/${cliContext.environment.packageName}?activeTab=versions.`,
945740
+ void 0,
945741
+ { code: CliError.Code.ConfigError }
945453
945742
  );
945454
945743
  }
945455
945744
  }
@@ -945465,7 +945754,7 @@ async function validateDocsBrokenLinks({
945465
945754
  }) {
945466
945755
  const docsWorkspace = project.docsWorkspaces;
945467
945756
  if (docsWorkspace == null) {
945468
- cliContext.failAndThrow("No docs workspace found");
945757
+ cliContext.failAndThrow("No docs workspace found", void 0, { code: CliError.Code.ConfigError });
945469
945758
  return;
945470
945759
  }
945471
945760
  await cliContext.runTaskForWorkspace(docsWorkspace, async (context3) => {
@@ -945488,7 +945777,7 @@ async function validateDocsBrokenLinks({
945488
945777
  elapsedMillis
945489
945778
  });
945490
945779
  if (violations.length > 0 && errorOnBrokenLinks) {
945491
- context3.failAndThrow();
945780
+ context3.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
945492
945781
  }
945493
945782
  });
945494
945783
  }
@@ -945970,7 +946259,7 @@ async function validateWorkspaces({
945970
946259
  if (!apiYmlExists) {
945971
946260
  await cliContext.runTask(async (context3) => {
945972
946261
  context3.logger.error(`Missing file: ${ROOT_API_FILENAME}`);
945973
- return context3.failAndThrow();
946262
+ return context3.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
945974
946263
  });
945975
946264
  return;
945976
946265
  }
@@ -946011,7 +946300,7 @@ async function validateWorkspaces({
946011
946300
  );
946012
946301
  }
946013
946302
  if (hasErrors || hasAnyErrors) {
946014
- cliContext.failAndThrow();
946303
+ cliContext.failAndThrow(void 0, void 0, { code: CliError.Code.ValidationError });
946015
946304
  }
946016
946305
  }
946017
946306
 
@@ -946229,7 +946518,10 @@ async function translateText({
946229
946518
  cliContext.logger.error(
946230
946519
  "Authentication required. Please run 'fern login' or set the FERN_TOKEN environment variable."
946231
946520
  );
946232
- throw new Error("Authentication required for translation service");
946521
+ throw new CliError({
946522
+ message: "Authentication required for translation service",
946523
+ code: CliError.Code.AuthError
946524
+ });
946233
946525
  }
946234
946526
  const config5 = {
946235
946527
  maxRetries: retryConfig.maxRetries ?? DEFAULT_MAX_RETRIES3,
@@ -946266,7 +946558,7 @@ async function translateText({
946266
946558
  errorDetail = await response.text();
946267
946559
  }
946268
946560
  if (response.status === 403) {
946269
- throw new Error(`403: ${errorDetail}`);
946561
+ throw new CliError({ message: `403: ${errorDetail}`, code: CliError.Code.AuthError });
946270
946562
  }
946271
946563
  const error50 = new Error(`HTTP ${response.status}: ${errorDetail}`);
946272
946564
  if (!isRetriableError(error50, response)) {
@@ -946946,7 +947238,10 @@ async function writeTranslationForProject({
946946
947238
  const translationsDirectory = join8(fernDirectory, RelativeFilePath2.of("translations"));
946947
947239
  const sourceLanguage = languages[0];
946948
947240
  if (!sourceLanguage) {
946949
- throw new Error("Unexpected error - first element of languages array is invalid");
947241
+ throw new CliError({
947242
+ message: "Unexpected error - first element of languages array is invalid",
947243
+ code: CliError.Code.InternalError
947244
+ });
946950
947245
  }
946951
947246
  if (!(0, import_fs38.existsSync)(translationsDirectory)) {
946952
947247
  context3.logger.debug(`Creating translations directory at: ${translationsDirectory}`);
@@ -947259,19 +947554,23 @@ async function resolveGroupGithubConfig(cliContext, groupName, apiWorkspace) {
947259
947554
  });
947260
947555
  const workspace = project.apiWorkspaces[0];
947261
947556
  if (workspace == null) {
947262
- return cliContext.failAndThrow("No API workspace found.");
947557
+ return cliContext.failAndThrow("No API workspace found.", void 0, { code: CliError.Code.ConfigError });
947263
947558
  }
947264
947559
  const generatorsConfig = workspace.generatorsConfiguration;
947265
947560
  if (generatorsConfig == null) {
947266
- return cliContext.failAndThrow("No generators.yml found in workspace.");
947561
+ return cliContext.failAndThrow("No generators.yml found in workspace.", void 0, {
947562
+ code: CliError.Code.ConfigError
947563
+ });
947267
947564
  }
947268
947565
  const group = generatorsConfig.groups.find((g19) => g19.groupName === groupName);
947269
947566
  if (group == null) {
947270
947567
  const available = generatorsConfig.groups.map((g19) => g19.groupName).join(", ");
947271
- return cliContext.failAndThrow(`Group "${groupName}" not found. Available groups: ${available}`);
947568
+ return cliContext.failAndThrow(`Group "${groupName}" not found. Available groups: ${available}`, void 0, {
947569
+ code: CliError.Code.ConfigError
947570
+ });
947272
947571
  }
947273
947572
  const resolveEnv = (value) => replaceEnvVariables(value, {
947274
- onError: (message) => cliContext.failAndThrow(message)
947573
+ onError: (message) => cliContext.failAndThrow(message, void 0, { code: CliError.Code.ConfigError })
947275
947574
  });
947276
947575
  const generatorWithSelfhosted = group.generators.find(
947277
947576
  (g19) => g19.raw?.github != null && isGithubSelfhosted(g19.raw.github)
@@ -947302,7 +947601,9 @@ async function resolveGroupGithubConfig(cliContext, groupName, apiWorkspace) {
947302
947601
  branch: "branch" in githubConfig ? githubConfig.branch : void 0
947303
947602
  };
947304
947603
  }
947305
- return cliContext.failAndThrow(`No generator in group "${groupName}" has a github configuration.`);
947604
+ return cliContext.failAndThrow(`No generator in group "${groupName}" has a github configuration.`, void 0, {
947605
+ code: CliError.Code.ConfigError
947606
+ });
947306
947607
  }
947307
947608
 
947308
947609
  // src/runtime.ts
@@ -947432,7 +947733,7 @@ async function tryRunCli(cliContext) {
947432
947733
  cliContext.logger.info(cliContext.environment.packageVersion);
947433
947734
  } else {
947434
947735
  cli.showHelp();
947435
- cliContext.failAndThrow();
947736
+ cliContext.failAndThrow(void 0, void 0, { code: CliError.Code.ConfigError });
947436
947737
  }
947437
947738
  }
947438
947739
  ).option("log-level", {
@@ -947558,14 +947859,22 @@ function addInitCommand2(cli, cliContext) {
947558
947859
  }
947559
947860
  }
947560
947861
  if (argv.api != null && argv.docs != null) {
947561
- return cliContext.failWithoutThrowing("Cannot specify both --api and --docs. Please choose one.");
947862
+ return cliContext.failWithoutThrowing(
947863
+ "Cannot specify both --api and --docs. Please choose one.",
947864
+ void 0,
947865
+ { code: CliError.Code.ConfigError }
947866
+ );
947562
947867
  } else if (argv.readme != null && argv.mintlify != null) {
947563
947868
  return cliContext.failWithoutThrowing(
947564
- "Cannot specify both --readme and --mintlify. Please choose one."
947869
+ "Cannot specify both --readme and --mintlify. Please choose one.",
947870
+ void 0,
947871
+ { code: CliError.Code.ConfigError }
947565
947872
  );
947566
947873
  } else if (argv.openapi != null && argv["fern-definition"] === true) {
947567
947874
  return cliContext.failWithoutThrowing(
947568
- "Cannot specify both --openapi and --fern-definition. Please choose one."
947875
+ "Cannot specify both --openapi and --fern-definition. Please choose one.",
947876
+ void 0,
947877
+ { code: CliError.Code.ConfigError }
947569
947878
  );
947570
947879
  } else if (argv.readme != null) {
947571
947880
  await cliContext.runTask(async (context3) => {
@@ -947599,7 +947908,9 @@ function addInitCommand2(cli, cliContext) {
947599
947908
  if (isURL(argv.openapi)) {
947600
947909
  const result = await loadOpenAPIFromUrl({ url: argv.openapi, logger: cliContext.logger });
947601
947910
  if (result.status === LoadOpenAPIStatus.Failure) {
947602
- cliContext.failAndThrow(result.errorMessage);
947911
+ cliContext.failAndThrow(result.errorMessage, void 0, {
947912
+ code: CliError.Code.NetworkError
947913
+ });
947603
947914
  }
947604
947915
  const tmpFilepath = result.filePath;
947605
947916
  absoluteOpenApiPath = AbsoluteFilePath2.of(tmpFilepath);
@@ -947608,7 +947919,9 @@ function addInitCommand2(cli, cliContext) {
947608
947919
  }
947609
947920
  const pathExists2 = await doesPathExist(absoluteOpenApiPath);
947610
947921
  if (!pathExists2) {
947611
- cliContext.failAndThrow(`${absoluteOpenApiPath} does not exist`);
947922
+ cliContext.failAndThrow(`${absoluteOpenApiPath} does not exist`, void 0, {
947923
+ code: CliError.Code.ConfigError
947924
+ });
947612
947925
  }
947613
947926
  }
947614
947927
  await cliContext.runTask(async (context3) => {
@@ -947652,9 +947965,10 @@ function addDiffCommand(cli, cliContext) {
947652
947965
  description: "Whether to suppress output written to stderr"
947653
947966
  }).middleware((argv) => {
947654
947967
  if (!haveSameNullishness(argv.fromGeneratorVersion, argv.toGeneratorVersion)) {
947655
- throw new Error(
947656
- "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided"
947657
- );
947968
+ throw new CliError({
947969
+ message: "Both --from-generator-version and --to-generator-version must be provided together, or neither should be provided",
947970
+ code: CliError.Code.ValidationError
947971
+ });
947658
947972
  }
947659
947973
  }),
947660
947974
  async (argv) => {
@@ -947905,50 +948219,84 @@ function addGenerateCommand2(cli, cliContext) {
947905
948219
  }),
947906
948220
  async (argv) => {
947907
948221
  if (argv.api != null && argv.docs != null) {
947908
- return cliContext.failWithoutThrowing("Cannot specify both --api and --docs. Please choose one.");
948222
+ return cliContext.failWithoutThrowing(
948223
+ "Cannot specify both --api and --docs. Please choose one.",
948224
+ void 0,
948225
+ { code: CliError.Code.ConfigError }
948226
+ );
947909
948227
  }
947910
948228
  if (argv.id != null && !argv.preview) {
947911
- return cliContext.failWithoutThrowing("The --id flag can only be used with --preview.");
948229
+ return cliContext.failWithoutThrowing("The --id flag can only be used with --preview.", void 0, {
948230
+ code: CliError.Code.ConfigError
948231
+ });
947912
948232
  }
947913
948233
  if (argv.id != null && argv.docs == null) {
947914
- return cliContext.failWithoutThrowing("The --id flag can only be used with --docs.");
948234
+ return cliContext.failWithoutThrowing("The --id flag can only be used with --docs.", void 0, {
948235
+ code: CliError.Code.ConfigError
948236
+ });
947915
948237
  }
947916
948238
  if (argv.skipUpload && !argv.preview) {
947917
- return cliContext.failWithoutThrowing("The --skip-upload flag can only be used with --preview.");
948239
+ return cliContext.failWithoutThrowing(
948240
+ "The --skip-upload flag can only be used with --preview.",
948241
+ void 0,
948242
+ { code: CliError.Code.ConfigError }
948243
+ );
947918
948244
  }
947919
948245
  if (argv.skipUpload && argv.docs == null) {
947920
- return cliContext.failWithoutThrowing("The --skip-upload flag can only be used with --docs.");
948246
+ return cliContext.failWithoutThrowing(
948247
+ "The --skip-upload flag can only be used with --docs.",
948248
+ void 0,
948249
+ { code: CliError.Code.ConfigError }
948250
+ );
947921
948251
  }
947922
948252
  if (argv.fernignore != null && (argv.local || argv.runner != null)) {
947923
948253
  return cliContext.failWithoutThrowing(
947924
- "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
948254
+ "The --fernignore flag is not supported with local generation (--local or --runner). It can only be used with remote generation.",
948255
+ void 0,
948256
+ { code: CliError.Code.ConfigError }
947925
948257
  );
947926
948258
  }
947927
948259
  if (argv["skip-fernignore"] && argv.fernignore != null) {
947928
948260
  return cliContext.failWithoutThrowing(
947929
- "The --skip-fernignore and --fernignore flags cannot be used together."
948261
+ "The --skip-fernignore and --fernignore flags cannot be used together.",
948262
+ void 0,
948263
+ { code: CliError.Code.ConfigError }
947930
948264
  );
947931
948265
  }
947932
948266
  if (argv["dynamic-ir-only"] && (argv.local || argv.runner != null)) {
947933
948267
  return cliContext.failWithoutThrowing(
947934
- "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation."
948268
+ "The --dynamic-ir-only flag is not supported with local generation (--local or --runner). It can only be used with remote generation.",
948269
+ void 0,
948270
+ { code: CliError.Code.ConfigError }
947935
948271
  );
947936
948272
  }
947937
948273
  if (argv["dynamic-ir-only"] && argv.version == null) {
947938
948274
  return cliContext.failWithoutThrowing(
947939
- "The --dynamic-ir-only flag requires a version to be specified with --version."
948275
+ "The --dynamic-ir-only flag requires a version to be specified with --version.",
948276
+ void 0,
948277
+ { code: CliError.Code.ConfigError }
947940
948278
  );
947941
948279
  }
947942
948280
  if (argv["dynamic-ir-only"] && argv.docs != null) {
947943
948281
  return cliContext.failWithoutThrowing(
947944
- "The --dynamic-ir-only flag can only be used for API generation, not docs generation."
948282
+ "The --dynamic-ir-only flag can only be used for API generation, not docs generation.",
948283
+ void 0,
948284
+ { code: CliError.Code.ConfigError }
947945
948285
  );
947946
948286
  }
947947
948287
  if (argv.output != null && !argv.preview) {
947948
- return cliContext.failWithoutThrowing("The --output flag currently only works with --preview.");
948288
+ return cliContext.failWithoutThrowing(
948289
+ "The --output flag currently only works with --preview.",
948290
+ void 0,
948291
+ { code: CliError.Code.ConfigError }
948292
+ );
947949
948293
  }
947950
948294
  if (argv.output != null && argv.docs != null) {
947951
- return cliContext.failWithoutThrowing("The --output flag is not supported for docs generation.");
948295
+ return cliContext.failWithoutThrowing(
948296
+ "The --output flag is not supported for docs generation.",
948297
+ void 0,
948298
+ { code: CliError.Code.ConfigError }
948299
+ );
947952
948300
  }
947953
948301
  const correctedGeneratorFilter = argv.generator != null ? warnAndCorrectIncorrectDockerOrg(argv.generator, cliContext) : void 0;
947954
948302
  const { generatorName, generatorIndex } = parseGeneratorArg(correctedGeneratorFilter);
@@ -948880,17 +949228,26 @@ function addDocsDevCommand(cli, cliContext) {
948880
949228
  );
948881
949229
  }
948882
949230
  let port;
948883
- if (argv.port != null) {
948884
- port = argv.port;
948885
- } else {
948886
- port = await getPorts({ port: [3e3, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010] });
948887
- }
948888
949231
  let backendPort;
948889
- if (argv.backendPort != null) {
948890
- backendPort = argv.backendPort;
948891
- } else {
948892
- backendPort = await getPorts({
948893
- port: [3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011]
949232
+ try {
949233
+ if (argv.port != null) {
949234
+ port = argv.port;
949235
+ } else {
949236
+ port = await getPorts({
949237
+ port: [3e3, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010]
949238
+ });
949239
+ }
949240
+ if (argv.backendPort != null) {
949241
+ backendPort = argv.backendPort;
949242
+ } else {
949243
+ backendPort = await getPorts({
949244
+ port: [3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011]
949245
+ });
949246
+ }
949247
+ } catch (error50) {
949248
+ throw new CliError({
949249
+ message: `Failed to find an available port: ${error50 instanceof Error ? error50.message : String(error50)}`,
949250
+ code: CliError.Code.EnvironmentError
948894
949251
  });
948895
949252
  }
948896
949253
  const bundlePath = argv.bundlePath;
@@ -948943,7 +949300,7 @@ function addDocsMdCheckCommand(cli, cliContext) {
948943
949300
  defaultToAllApiWorkspaces: true
948944
949301
  });
948945
949302
  if (project.docsWorkspaces == null) {
948946
- cliContext.failAndThrow("No docs workspace found");
949303
+ cliContext.failAndThrow("No docs workspace found", void 0, { code: CliError.Code.ConfigError });
948947
949304
  }
948948
949305
  const docsWorkspace = project.docsWorkspaces;
948949
949306
  let hasErrors = false;
@@ -948958,7 +949315,7 @@ function addDocsMdCheckCommand(cli, cliContext) {
948958
949315
  }
948959
949316
  });
948960
949317
  if (hasErrors) {
948961
- cliContext.failWithoutThrowing();
949318
+ cliContext.failWithoutThrowing(void 0, void 0, { code: CliError.Code.ValidationError });
948962
949319
  }
948963
949320
  }
948964
949321
  );
@@ -949317,7 +949674,7 @@ function addBetaCommand(cli, cliContext) {
949317
949674
  await runCliV2(v2Args);
949318
949675
  } catch (error50) {
949319
949676
  cliContext.logger.error("CLI v2 failed:", String(error50));
949320
- cliContext.failWithoutThrowing();
949677
+ cliContext.failWithoutThrowing(void 0, error50, { code: CliError.Code.InternalError });
949321
949678
  }
949322
949679
  }
949323
949680
  );
@@ -949442,7 +949799,11 @@ function addReplayInitCommand(cli, cliContext) {
949442
949799
  }
949443
949800
  if (githubRepo == null) {
949444
949801
  return cliContext.failAndThrow(
949445
- "Missing required github config. Either use --group to read from generators.yml, or provide --github directly."
949802
+ "Missing required github config. Either use --group to read from generators.yml, or provide --github directly.",
949803
+ void 0,
949804
+ {
949805
+ code: CliError.Code.ConfigError
949806
+ }
949446
949807
  );
949447
949808
  }
949448
949809
  if (token == null) {
@@ -949478,7 +949839,9 @@ function addReplayInitCommand(cli, cliContext) {
949478
949839
  return;
949479
949840
  }
949480
949841
  if (result.lockfileContent == null) {
949481
- return cliContext.failAndThrow("Bootstrap succeeded but lockfile content is missing.");
949842
+ return cliContext.failAndThrow("Bootstrap succeeded but lockfile content is missing.", void 0, {
949843
+ code: CliError.Code.InternalError
949844
+ });
949482
949845
  }
949483
949846
  const fernToken = await cliContext.runTask((context3) => askToLogin(context3));
949484
949847
  const { owner, repo } = parseOwnerRepo(githubRepo);
@@ -949500,18 +949863,24 @@ function addReplayInitCommand(cli, cliContext) {
949500
949863
  if (!response.ok) {
949501
949864
  if (response.status === 404) {
949502
949865
  return cliContext.failAndThrow(
949503
- "The Fern GitHub App is not installed on this repository. Install it at https://github.com/apps/fern-api to enable server-side PR creation."
949866
+ "The Fern GitHub App is not installed on this repository. Install it at https://github.com/apps/fern-api to enable server-side PR creation.",
949867
+ void 0,
949868
+ { code: CliError.Code.ConfigError }
949504
949869
  );
949505
949870
  }
949506
949871
  const body = await response.text();
949507
- return cliContext.failAndThrow(`Failed to create PR via Fern: ${body}`);
949872
+ return cliContext.failAndThrow(`Failed to create PR via Fern: ${body}`, void 0, {
949873
+ code: CliError.Code.NetworkError
949874
+ });
949508
949875
  }
949509
949876
  const data2 = await response.json();
949510
949877
  cliContext.logger.info(`
949511
949878
  PR created: ${data2.prUrl}`);
949512
949879
  cliContext.logger.info("Merge the PR to enable Replay for this repository.");
949513
949880
  } catch (error50) {
949514
- cliContext.failAndThrow(`Failed to initialize Replay: ${extractErrorMessage(error50)}`);
949881
+ cliContext.failAndThrow(`Failed to initialize Replay: ${extractErrorMessage(error50)}`, error50, {
949882
+ code: CliError.Code.NetworkError
949883
+ });
949515
949884
  }
949516
949885
  }
949517
949886
  );
@@ -949574,12 +949943,18 @@ Resolve the conflicts in your editor, then run \`fern replay resolve\` again to
949574
949943
  }
949575
949944
  cliContext.logger.warn(`Resolve them first, then run \`fern replay resolve\` again.`);
949576
949945
  } else {
949577
- cliContext.failAndThrow(`Resolve failed: ${result.reason ?? "unknown error"}`);
949946
+ cliContext.failAndThrow(
949947
+ `Resolve failed: ${result.reason ?? "unknown error"}`,
949948
+ void 0,
949949
+ { code: CliError.Code.InternalError }
949950
+ );
949578
949951
  }
949579
949952
  }
949580
949953
  }
949581
949954
  } catch (error50) {
949582
- cliContext.failAndThrow(`Failed to resolve: ${extractErrorMessage(error50)}`);
949955
+ cliContext.failAndThrow(`Failed to resolve: ${extractErrorMessage(error50)}`, error50, {
949956
+ code: CliError.Code.InternalError
949957
+ });
949583
949958
  }
949584
949959
  }
949585
949960
  );
@@ -949795,7 +950170,10 @@ function parseOwnerRepo(githubRepo) {
949795
950170
  const owner = parts[parts.length - 2];
949796
950171
  const repo = parts[parts.length - 1];
949797
950172
  if (owner == null || repo == null) {
949798
- throw new Error(`Could not parse owner/repo from: ${githubRepo}`);
950173
+ throw new CliError({
950174
+ message: `Could not parse owner/repo from: ${githubRepo}`,
950175
+ code: CliError.Code.ParseError
950176
+ });
949799
950177
  }
949800
950178
  return { owner, repo };
949801
950179
  }