diff --git a/CLAUDE.md b/CLAUDE.md index 88a9992088ed..a9a9ed1a3d2d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -393,6 +393,8 @@ After writing the ADR, number it by finding the highest existing `docs/adr/NNNN- ## Troubleshooting +For Sentry `buildwithfern` / `cli` false-positive triage, see [`automation/sentry-triage/AGENT.md`](automation/sentry-triage/AGENT.md), [`automation/sentry-triage/DESIGN_CHOICES.md`](automation/sentry-triage/DESIGN_CHOICES.md), and [`automation/sentry-triage/ledger.json`](automation/sentry-triage/ledger.json). + ### Quick Fixes by Issue Type - **Generator failures**: Check `docker ps` → Rebuild image → Check container logs - **IR compilation**: `pnpm fern check` → Check circular refs → Review migrations diff --git a/automation/sentry-triage/AGENT.md b/automation/sentry-triage/AGENT.md new file mode 100644 index 000000000000..30e3672fe707 --- /dev/null +++ b/automation/sentry-triage/AGENT.md @@ -0,0 +1,108 @@ +# Sentry CLI false-positive triage — agent instructions + +Read **`DESIGN_CHOICES.md`** before proposing code changes; it holds short, accumulated fix patterns. After human review changes the accepted approach, update **`DESIGN_CHOICES.md`** with **1–3 new bullets** (short phrases only) when the lesson is reusable. + +## Scope + +- Sentry org: `buildwithfern` +- Sentry project: `cli` +- Use the repo-baked Sentry CLI: `pnpm exec sentry-cli` (do not rely on a global `sentry` binary). +- Default: unresolved only — `pnpm exec sentry-cli issue list … --query "is:unresolved"` unless the task says to re-validate resolved issues. + +## Run shape + +- **One PR per solution group.** Group Sentry issues by the code change that fixes them: if one change solves multiple `shortId`s, ship those together in one PR; unrelated fixes must be separate PRs. +- **Do not create one catch-all PR for a whole run.** A run may produce multiple PRs, but each PR must correspond to exactly one solution group. +- **Defer** opening PRs until grouping and investigation are far enough along that you are not guessing which `shortId`s share a fix. + +## Fetch (Sentry CLI) + +```bash +pnpm exec sentry-cli issue list buildwithfern/cli \ + --json --fields shortId,title,status,lastSeen \ + --limit 100 --query "is:unresolved" + +pnpm exec sentry-cli issue view buildwithfern/cli/ --json +``` + +Prefer `--json` and `--fields` to keep payloads small. + +## Ledger-first and query-first + +1. Collect `shortId` from list output. +2. Do **not** load all of `automation/sentry-triage/ledger.json` into context as it grows. +3. Targeted lookup with `jq`: + +```bash +jq --argjson ids '["CLI-2W","CLI-2V"]' ' + .issues + | to_entries + | map(select(.key as $id | $ids | index($id))) + | map({ + shortId: .key, + disposition: .value.disposition, + duplicateOf: .value.duplicateOf, + problemSignature: .value.problemSignature, + prOrIssue: .value.prOrIssue + }) +' automation/sentry-triage/ledger.json +``` + +4. **Same `shortId` only:** if this Sentry issue’s `shortId` already exists in the ledger with disposition `shipped`, `ignored`, `duplicate`, or `keep_sentry`, **skip** re-triaging that row (`keep_sentry` means do not suppress—do not reclassify as a false positive). This is **not** “similar title so skip”; it is exact `shortId` match. +5. **Re-process** `pending_review` until set to a terminal disposition. +6. `pnpm exec sentry-cli issue view` in full only for unknown or `pending_review` rows (and tight clustering follow-ups). +7. **Similar past cases (inspiration only):** for a `shortId` **not** in the ledger (or still in play), you may stream `problemSignature` + `shortId` (e.g. `jq -r '.issues | to_entries[] | "\(.key)\t\(.value.problemSignature)"' automation/sentry-triage/ledger.json`) and keyword-search using the **new** issue’s title/exception (MDX, YAML, errno, container, `generators.yml`, etc.) to find **prior fixes to learn from**. **Do not** treat a text match as proof the new issue is already solved: always confirm with current Sentry payload, stack, and code paths. A recurrence or regression still needs a normal investigation and disposition. + +## Ledger shape (`issues`) + +| Field | Required | Meaning | +|-------|----------|---------| +| `title` | yes | Short Sentry title. | +| `problemSignature` | yes | **1–3 short sentences:** symptom + feature surface so **future** triage can grep the ledger for **similar** past cases as **hints** (how we fixed before)—not as proof the new issue is closed. For `duplicate`, copy the canonical row’s `problemSignature` so search still hits this `shortId`. | +| `disposition` | yes | See table below. | +| `rationale` | yes | Why this disposition. | +| `fixSummary` | yes | What changed, or `—` for `duplicate` / `ignored` when not applicable. | +| `prOrIssue` | yes | PR URL, issue link, or note. | +| `lastAnalyzed` | yes | ISO date. | +| `duplicateOf` | if `duplicate` | Canonical ledger `shortId` whose `fixSummary` / PR is the source of truth. | + +## Ledger disposition meanings + +| Value | Meaning | +|-------|---------| +| `shipped` | Fix merged; events should stop after release or issue resolved in Sentry. | +| `ignored` | No code change; rationale recorded. | +| `keep_sentry` | Real bug; stays reportable until a product fix. | +| `duplicate` | Same **Sentry** issue family as another ledger row: `duplicateOf` points at the canonical `shortId` (one fix narrative). **Skip** re-triage for **that** `shortId` only—same as `shipped` for workload. This is unrelated to “looks like” similarity for **new** `shortId`s; those still get full analysis. | +| `pending_review` | Needs decision; resolve on next pass. | + +**Why keep `duplicate`?** Sentry often opens **multiple issues** for one underlying fix. One row stays `shipped` with the full story; the rest become `duplicate` + `duplicateOf` so the next run does not re-investigate **those same ledger shortIds** and the ledger stays small. If you prefer, you can mark every follower `shipped` instead—`duplicate` is only ergonomics. + +## Code and PR rules + +- Follow **`DESIGN_CHOICES.md`** and nearby throw sites in this repo. +- Branch: use `FedeZara/fix/sentry--` for each solution group (for example, `FedeZara/fix/sentry-cli-30-cli-3g-docs-yaml-parse`). Include at most three `shortId`s in the branch name. +- PR title: include the solved `shortId`s in the title. If there are more than three, list only the first three and summarize the family (for example, `fix(cli): classify CLI-30 CLI-3G CLI-Q docs YAML parse errors`). +- Changelog: `packages/cli/cli/changes/unreleased/` when the CLI behavior or reporting changes. +- PR description: explicitly list **each Sentry error solved** by the PR, including its `shortId` (for example, `CLI-2W`) and a short fix note. + +## Phases (single parent agent) + +Optional read-only explore subagents for search only; parent owns edits and the PR. + +1. **Parent** — read this file + `DESIGN_CHOICES.md`; `jq` ledger for current `shortId`s; no PR until grouping is sound. +2. **Fetch** — `pnpm exec sentry-cli issue list` / `pnpm exec sentry-cli issue view` as above. +3. **Ledger filter** — for each **current** `shortId`, if the ledger row exists and disposition is terminal (`shipped`, `ignored`, `duplicate`, `keep_sentry`), skip that issue; keep unknown `shortId`s + `pending_review`. Similar `problemSignature` matches elsewhere do **not** skip an unknown `shortId`. +4. **Group** — by the concrete solution, not just by similar titles. Same code path / same root cause / same patch → one solution-group PR. Different patches → different PRs. +5. **Investigate** — nearest catch/throw; align with `DESIGN_CHOICES.md`. +6. **Fix** — open one PR per solution group; each PR description lists every solved Sentry error with `shortId`; changelog when needed; `keep_sentry` for confirmed real bugs. +7. **Record** — update `ledger.json` in the **same** PR as the code (and `DESIGN_CHOICES.md` when a reusable pattern is confirmed). + +## Record updates after human review + +When the task is to align records with **final** human decisions (no product code unless asked): + +- Load `ledger.json` only (or the specific `issues.` entries you are changing). +- Update ledger fields consistently (including `duplicateOf` if you change which row is canonical, and **`problemSignature`** if humans clarify how this issue should be found next time). +- **Update `DESIGN_CHOICES.md`** when the correction is a reusable pattern: add or replace **short** bullets only—no long narratives. +- Do **not** re-fetch Sentry unless the task requires verification. diff --git a/automation/sentry-triage/DESIGN_CHOICES.md b/automation/sentry-triage/DESIGN_CHOICES.md new file mode 100644 index 000000000000..776af35d7de6 --- /dev/null +++ b/automation/sentry-triage/DESIGN_CHOICES.md @@ -0,0 +1,20 @@ +# Triage design choices (compact) + +One line per item. Append or edit **short** bullets when human review confirms a pattern; do not paste long prose. Principles here; **implementation lives in code and PRs**, not in this file. + +## Choices + +- User/environment syscalls (errno-style): classify at the **central** error-mapping layer **only** when the signal is a clear, code-level errno—not guessed from message text. +- Do **not** route “looks like X” string heuristics through that central layer; keep heuristics out or extremely narrow. +- Do **not** add central `isXError` classifiers except existing schema-validation / Node-version checks; parse/config/user errors should be explicit `CliError` codes at the boundary. +- User-authored content (docs, specs, config files): surface failures as **user-facing** parse/config/validation errors **at the boundary** where input enters the CLI—not as generic internal errors. +- Conversion or ingest steps on user input (format upgrades, parsers): failures should read as **user input problems**, with useful context when available. +- User configuration (versions, paths, generator references): wrong or invalid values → **config or validation** semantics, not internal errors. +- True product defects: **keep_sentry** in the ledger; do not hide them behind reclassification. +- Long-running or multi-step work: avoid **double reporting** (one failure should not become both a task failure and a top-level internal error). +- External service/job failures: surface as **non-reportable** service/network failures unless the CLI itself caused the defect. +- Subprocess / tool re-exec failures: prefer **abort or controlled failure** over a misleading internal error. +- Local tool failures from user worktrees/config (git, buf, sed): classify at the **tool boundary** as user/environment errors. +- Auth/AI/provider setup failures: classify at the **auth/config boundary**, not as generic internal errors. +- Pipe/TTY noise when users chain Unix tools: swallow or classify at the **I/O boundary** so it never looks like an app bug. +- If runtime minification or bundling can break **name-based** error checks, make classification rely on something **stable** (e.g. explicit names or codes), not fragile `constructor.name` alone. diff --git a/automation/sentry-triage/README.md b/automation/sentry-triage/README.md new file mode 100644 index 000000000000..c2afa466797d --- /dev/null +++ b/automation/sentry-triage/README.md @@ -0,0 +1,3 @@ +# automation/sentry-triage + +Agent triage instructions: **[`AGENT.md`](AGENT.md)**. Fix patterns (short bullets, updated after review): **[`DESIGN_CHOICES.md`](DESIGN_CHOICES.md)**. State: **`ledger.json`**. diff --git a/automation/sentry-triage/ledger.json b/automation/sentry-triage/ledger.json new file mode 100644 index 000000000000..750564e1bf1f --- /dev/null +++ b/automation/sentry-triage/ledger.json @@ -0,0 +1,954 @@ +{ + "schemaVersion": 3, + "project": "buildwithfern/cli", + "updatedAt": "2026-05-05", + "issues": { + "CLI-2W": { + "title": "59:2: Unexpected character `!` before name", + "disposition": "shipped", + "rationale": "User-authored MDX/acorn parse error surfaced as InternalError; should be ParseError at parseImagePaths call sites.", + "fixSummary": "Wrap parseImagePaths in DocsDefinitionResolver and previewDocs with CliError(ParseError).", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-04-28", + "problemSignature": "Docs or preview path: MDX/acorn parse error (often bad `!` or JSX) while resolving doc image paths; showed as InternalError." + }, + "CLI-2V": { + "title": "MDX / docs image path parse failure", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2W; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-04-28", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error (often bad `!` or JSX) while resolving doc image paths; showed as InternalError." + }, + "CLI-2X": { + "title": "Filesystem / errno false positive", + "disposition": "shipped", + "rationale": "User/env errno (e.g. ENOENT) misclassified as InternalError.", + "fixSummary": "ErrnoException mapping in resolveErrorCode; USER_ENVIRONMENT_ERRNOS / NETWORK_ERRNOS.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-1X": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-2F": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-1S": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-2C": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-1J": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-1V": { + "title": "Filesystem / errno false positive", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2X; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-1W": { + "title": "Filesystem / errno / EPIPE-style false positive", + "disposition": "shipped", + "rationale": "User/env or pipe closure; EPIPE listener on TtyAwareLogger plus errno mapping.", + "fixSummary": "PR 15283: process.stdout/stderr error listener + errno mapping.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "EPIPE or broken pipe when user pipes CLI stdout/stderr to tools like head/jq; errno-style noise reaching error reporter." + }, + "CLI-2E": { + "title": "YAML parse in OpenAPI load", + "disposition": "shipped", + "rationale": "YAMLException from user spec misclassified as InternalError.", + "fixSummary": "Wrap yaml.load in loadOpenAPI; CliError(ParseError) with file/line/column.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Invalid YAML while loading a user OpenAPI spec (yaml.load path); parser exception treated as InternalError." + }, + "CLI-2A": { + "title": "YAML parse in OpenAPI load", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Invalid YAML while loading a user OpenAPI spec (yaml.load path); parser exception treated as InternalError." + }, + "CLI-24": { + "title": "YAML parse in OpenAPI load", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2E; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2E", + "problemSignature": "Invalid YAML while loading a user OpenAPI spec (yaml.load path); parser exception treated as InternalError." + }, + "CLI-1F": { + "title": "YAML parse in OpenAPI load", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2E; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2E", + "problemSignature": "Invalid YAML while loading a user OpenAPI spec (yaml.load path); parser exception treated as InternalError." + }, + "CLI-13": { + "title": "swagger2openapi conversion failure", + "disposition": "shipped", + "rationale": "User OpenAPI v2 spec conversion failure should be ParseError.", + "fixSummary": "convertOpenAPIV2ToV3 wraps swagger2openapi as CliError(ParseError).", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "User OpenAPI v2 document fails swagger2openapi conversion to v3; conversion error treated as InternalError." + }, + "CLI-10": { + "title": "Container aggregate / sdk generate", + "disposition": "shipped", + "rationale": "ContainerError + aggregate InternalError double-report; use TaskAbortSignal.", + "fixSummary": "ContainerError non-reportable; sdk generate uses TaskAbortSignal instead of aggregate CliError.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-19": { + "title": "Container aggregate / docs publish", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-10; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-2G": { + "title": "Container / task failure reporting", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-10; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-26": { + "title": "Container / task failure reporting", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-10; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-20": { + "title": "Container / task failure reporting", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-10; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-11": { + "title": "Generator not found (generators.yml)", + "disposition": "shipped", + "rationale": "User references unknown generator image; should be ConfigError not InternalError.", + "fixSummary": "Upgrade helper reclassifies to ConfigError.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "generators.yml references a generator image or version that is not found in FDR/registry; surfaced as InternalError instead of config error." + }, + "CLI-1H": { + "title": "Organization create validation / network", + "disposition": "shipped", + "rationale": "ValidationError/NetworkError passed explicitly instead of InternalError.", + "fixSummary": "createOrganizationIfDoesNotExist explicit codes.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Organization create flow: validation or network failures bubbled up as InternalError instead of explicit validation/network CLI errors." + }, + "CLI-J": { + "title": "Rerun CLI at version failure", + "disposition": "shipped", + "rationale": "Spurious InternalError on rerun failure; TaskAbortSignal.", + "fixSummary": "rerunFernCliAtVersion uses TaskAbortSignal.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "CLI rerun-at-version path failed and reported misleading InternalError instead of controlled task abort." + }, + "CLI-2Z": { + "title": "Schema validation / minified class names", + "disposition": "shipped", + "rationale": "isSchemaValidationError could not match minified constructor names.", + "fixSummary": "Set this.name on JsonError, ParseError, GeneratorError constructors.", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Schema validation path: minified build broke constructor-name-based detection so parse/schema errors looked like InternalError." + }, + "CLI-E": { + "title": "Schema validation / minified class names", + "disposition": "duplicate", + "rationale": "Same fix narrative as CLI-2Z; one PR covered both.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "duplicateOf": "CLI-2Z", + "problemSignature": "Schema validation path: minified build broke constructor-name-based detection so parse/schema errors looked like InternalError." + }, + "CLI-2H": { + "title": "Local + GitHub project config resolution", + "disposition": "shipped", + "rationale": "User config / workspace path edge case misclassified as InternalError.", + "fixSummary": "Workspace / project config resolution and path handling (see PR #15283 changelog and follow-up #15484 if refined).", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-04-21", + "problemSignature": "Project load with local vs remote (e.g. GitHub) workspace or config paths: user path/config edge misclassified as InternalError." + }, + "CLI-3Q": { + "title": "ENOENT loading docs page", + "disposition": "duplicate", + "rationale": "Same user/environment errno classification as CLI-2X; current code maps ENOENT to EnvironmentError.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-3A": { + "title": "EINTR interrupted syscall in uv_cwd", + "disposition": "shipped", + "rationale": "EINTR is a clear errno-style environment signal, not a Fern product bug.", + "fixSummary": "Add EINTR to USER_ENVIRONMENT_ERRNOS so resolveErrorCode maps it to EnvironmentError.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Filesystem or syscall errno from user environment (EINTR interrupted syscall) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-H": { + "title": "ExitPromptError after SIGINT", + "disposition": "shipped", + "rationale": "Prompt SIGINT is a user abort; current CliContext prompt wrappers convert ExitPromptError to TaskAbortSignal before reporting.", + "fixSummary": "Handle ExitPromptError at prompt boundaries and abort without Sentry reporting.", + "prOrIssue": "Already handled in current code; ledger corrected in this PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Interactive prompt cancellation via SIGINT surfaced as Sentry InternalError instead of a non-reportable user abort." + }, + "CLI-3P": { + "title": "Global theme fetch returned HTTP 403", + "disposition": "shipped", + "rationale": "Global theme lookup failures are auth/config/network conditions, not internal CLI defects.", + "fixSummary": "Pass ConfigError/NetworkError codes from stitchGlobalTheme failAndThrow sites.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Docs global-theme fetch or asset download failure reported through failAndThrow without a non-reportable config/network code." + }, + "CLI-31": { + "title": "Failed to parse version: 0.x", + "disposition": "shipped", + "rationale": "Invalid version strings should be reported with explicit VersionError codes at callers/boundaries, not central name-based classification.", + "fixSummary": "Wrap dependency CLI version parsing with VersionError; existing generator-version callers already wrap invalid versions explicitly.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid generator or CLI version string (e.g. 0.x, 1.x, *) reached Sentry as plain Error instead of VersionError." + }, + "CLI-2P": { + "title": "Failed to parse version: 1.x", + "disposition": "duplicate", + "rationale": "Same invalid-version classification as CLI-31.", + "fixSummary": "—", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-31", + "problemSignature": "Invalid generator or CLI version string (e.g. 0.x, 1.x, *) reached Sentry as plain Error instead of VersionError." + }, + "CLI-2B": { + "title": "Failed to compare versions: Failed to parse version: 0.x", + "disposition": "duplicate", + "rationale": "Same invalid-version classification as CLI-31.", + "fixSummary": "—", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-31", + "problemSignature": "Invalid generator or CLI version string (e.g. 0.x, 1.x, *) reached Sentry as plain Error instead of VersionError." + }, + "CLI-1Z": { + "title": "Failed to parse version: *", + "disposition": "duplicate", + "rationale": "Same invalid-version classification as CLI-31.", + "fixSummary": "—", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-31", + "problemSignature": "Invalid generator or CLI version string (e.g. 0.x, 1.x, *) reached Sentry as plain Error instead of VersionError." + }, + "CLI-14": { + "title": "Generator version incompatible with CLI v4", + "disposition": "duplicate", + "rationale": "Same version/config family as CLI-31; current migration code throws VersionError for this path.", + "fixSummary": "—", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-31", + "problemSignature": "Invalid or incompatible generator version reached Sentry instead of VersionError/config guidance." + }, + "CLI-2M": { + "title": "listen EADDRINUSE :::3001", + "disposition": "duplicate", + "rationale": "EADDRINUSE is already covered by the errno environment mapping.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission, port in use) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-2S": { + "title": "listen EADDRINUSE :::3003", + "disposition": "duplicate", + "rationale": "EADDRINUSE is already covered by the errno environment mapping.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission, port in use) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-Z": { + "title": "ENOSPC no space left on device", + "disposition": "duplicate", + "rationale": "ENOSPC is already covered by the errno environment mapping.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2X", + "problemSignature": "Filesystem or syscall errno from user environment (e.g. missing file, permission, disk full) surfaced as InternalError instead of environment-style CLI error." + }, + "CLI-3N": { + "title": "MDX unexpected backslash", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-3M": { + "title": "MDX acorn parse expression", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-3K": { + "title": "MDX acorn parse expression", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-3H": { + "title": "MDX unexpected quote in attribute name", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-37": { + "title": "MDX expected closing Tab tag", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-38": { + "title": "MDX acorn parse expression", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-35": { + "title": "MDX unexpected closing slash", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-33": { + "title": "MDX unexpected asterisk", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-32": { + "title": "MDX expected closing br tag", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-2R": { + "title": "MDX import/export parse failure", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-2Q": { + "title": "MDX acorn parse expression", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-2N": { + "title": "MDX unexpected exclamation", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-29": { + "title": "MDX unexpected exclamation", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-28": { + "title": "MDX unexpected number", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-23": { + "title": "MDX unexpected exclamation", + "disposition": "duplicate", + "rationale": "Same docs MDX/acorn parse family as CLI-2W.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15484", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2W", + "problemSignature": "Docs or preview path: MDX/acorn parse error while resolving user-authored docs content; showed as InternalError." + }, + "CLI-30": { + "title": "YAML multiline key parse failure", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-3G": { + "title": "YAML duplicated mapping key", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-Q": { + "title": "YAML duplicated mapping key", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-1T": { + "title": "YAML duplicated mapping key", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-1E": { + "title": "YAML duplicated mapping key", + "disposition": "duplicate", + "rationale": "Same invalid user YAML parse family as CLI-2E.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2E", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-G": { + "title": "YAML bad indentation", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-P": { + "title": "YAML bad indentation", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-N": { + "title": "YAML bad sequence indentation", + "disposition": "shipped", + "rationale": "Docs/workspace YAML parse failure was still able to bubble as InternalError from the docs.yml boundary.", + "fixSummary": "Wrap docs.yml yaml.load in loadRawDocsConfiguration as CliError(ParseError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid YAML while loading user-authored config or OpenAPI spec; parser exception treated as InternalError." + }, + "CLI-12": { + "title": "swagger2openapi unresolved reference", + "disposition": "duplicate", + "rationale": "Same OpenAPI v2 conversion failure family as CLI-13.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-13", + "problemSignature": "User OpenAPI v2 document fails swagger2openapi conversion to v3; conversion error treated as InternalError." + }, + "CLI-36": { + "title": "docs navigation schema validation failure", + "disposition": "duplicate", + "rationale": "Same schema validation/minified error-name family as CLI-2Z.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2Z", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-F": { + "title": "Unexpected key package-name", + "disposition": "duplicate", + "rationale": "Same schema validation/minified error-name family as CLI-2Z.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2Z", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-8": { + "title": "docs.yml navbar-links schema validation failure", + "disposition": "duplicate", + "rationale": "Same schema validation/minified error-name family as CLI-2Z.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2Z", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-25": { + "title": "Invalid fern.config.json JSON", + "disposition": "duplicate", + "rationale": "Current loadProjectConfig wraps JSON.parse as ParseError; same non-reportable parse/config class as CLI-2Z.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2Z", + "problemSignature": "Schema or configuration parse path for user-authored fern.config.json looked like InternalError instead of parse/config error." + }, + "CLI-17": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-1G": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-15": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-1D": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-1C": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-1B": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-1A": { + "title": "Expected list received object", + "disposition": "shipped", + "rationale": "IR SDK schema errors lacked stable names, so schema validation failures could still look like InternalError after minification/bundling.", + "fixSummary": "Set stable ParseError/JsonError names in IR SDK schema errors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Schema or configuration validation path for user-authored docs/config looked like InternalError instead of validation/config error." + }, + "CLI-2Y": { + "title": "No fern directory found with --id", + "disposition": "shipped", + "rationale": "Current delete preview flow passes ValidationError for this user invocation problem.", + "fixSummary": "Existing deleteDocsPreview path uses CliError.Code.ValidationError.", + "prOrIssue": "Already on main", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Docs preview delete --id outside a Fern project failed as InternalError instead of ValidationError guidance." + }, + "CLI-2K": { + "title": "No fern directory found with --id", + "disposition": "duplicate", + "rationale": "Same validation path as CLI-2Y.", + "fixSummary": "—", + "prOrIssue": "Already on main", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-2Y", + "problemSignature": "Docs preview delete --id outside a Fern project failed as InternalError instead of ValidationError guidance." + }, + "CLI-1R": { + "title": "Container execution failed code 1", + "disposition": "duplicate", + "rationale": "Same container/task double-reporting family as CLI-10.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-1P": { + "title": "Container execution failed code 1", + "disposition": "duplicate", + "rationale": "Same container/task double-reporting family as CLI-10.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-1N": { + "title": "Container execution failed code 1", + "disposition": "duplicate", + "rationale": "Same container/task double-reporting family as CLI-10.", + "fixSummary": "—", + "prOrIssue": "https://github.com/fern-api/fern/pull/15283", + "lastAnalyzed": "2026-05-04", + "duplicateOf": "CLI-10", + "problemSignature": "sdk generate or docs publish with Docker/container tasks: task failures double-reported as aggregate InternalError / ContainerError noise." + }, + "CLI-3E": { + "title": "Internal response property conversion error", + "disposition": "keep_sentry", + "rationale": "IR conversion invariant failure in getObjectPropertyFromResolvedType; this looks like a product bug rather than false-positive noise.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "IR conversion invariant failure while resolving response object properties; true product defect until converter behavior is fixed." + }, + "CLI-3F": { + "title": "Failed to locate type", + "disposition": "keep_sentry", + "rationale": "Type resolution failed inside IR generation; needs product-level investigation instead of suppression.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "IR generation failed to locate a referenced Fern type; possible reference/resolution product bug until validated." + }, + "CLI-3D": { + "title": "Mintlify import navigation is not iterable", + "disposition": "keep_sentry", + "rationale": "Importer TypeError indicates missing validation or compatibility handling in Mintlify import code.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Mintlify docs import TypeError while reading navigation; true importer robustness bug until fixed." + }, + "CLI-3B": { + "title": "Null overlay in applyOverlays", + "disposition": "keep_sentry", + "rationale": "Null overlay TypeError indicates missing validation in workspace overlay handling.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Workspace overlay loading TypeError on null overlay; true validation/product bug until fixed." + }, + "CLI-1Q": { + "title": "formatDocs replace is not a function", + "disposition": "keep_sentry", + "rationale": "formatDocs expected a string and received another shape; needs product validation or conversion fix.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "IR docs formatting TypeError because docs value was not a string; true product/data-shape bug until fixed." + }, + "CLI-27": { + "title": "Invalid URL in app preview server", + "disposition": "keep_sentry", + "rationale": "Preview server should validate or normalize the URL source; leave reportable until fixed.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Docs app preview server TypeError Invalid URL; possible product/config boundary bug until fixed." + }, + "CLI-Y": { + "title": "Generic empty Error in development", + "disposition": "ignored", + "rationale": "Only visible event is development environment with empty Error value grouped at telemetry reporter; no product signature to fix or suppress safely.", + "fixSummary": "—", + "prOrIssue": "Ignored after event-level review", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Development-only empty Error grouped at reportError/capture path with no actionable product signature." + }, + "CLI-1Y": { + "title": "Missing translations directory validation", + "disposition": "shipped", + "rationale": "Missing translations directory is user docs configuration and was reported without a non-reportable code.", + "fixSummary": "Pass ValidationError when translation locale directories are missing.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Docs translations configuration references a locale whose translations directory is missing; should be validation/config semantics, not InternalError." + }, + "CLI-3C": { + "title": "Replay resolve failed no-lockfile", + "disposition": "shipped", + "rationale": "Replay resolve no-lockfile is user/worktree state, not an internal CLI defect.", + "fixSummary": "Map fallback replay resolve failures to UserError in both CLI implementations.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Replay resolve failed with no-lockfile or other user/worktree state and was explicitly reported as InternalError." + }, + "CLI-39": { + "title": "Failed to parse GitHub repository", + "disposition": "shipped", + "rationale": "Invalid GitHub repository strings in generators.yml are configuration errors and should be wrapped where generators.yml is converted.", + "fixSummary": "Wrap parseRepository failures in convertGeneratorsConfiguration as CliError(ConfigError); parseRepository still throws a plain Error.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-04", + "problemSignature": "Invalid GitHub repository config string (missing owner/repo or empty path part) surfaced as InternalError instead of ConfigError." + }, + "CLI-1K": { + "title": "GitHub pull request base branch invalid", + "disposition": "shipped", + "rationale": "Remote generation task failures are generator/container task failures, not CLI internal defects.", + "fixSummary": "RemoteTaskHandler maps failed remote tasks to non-reportable ContainerError in current code.", + "prOrIssue": "Already handled in current code; ledger corrected in this PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Remote generation task failed because downstream generator/GitHub output rejected user configuration; should be non-reportable task/container failure." + }, + "CLI-3J": { + "title": "Windows temp OpenAPI filepath is not relative", + "disposition": "keep_sentry", + "rationale": "Absolute/Windows path reached a relative-path invariant; needs path normalization or boundary validation fix.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "OpenAPI or workspace path conversion received an absolute path where a relative path was required; path boundary bug until fixed." + }, + "CLI-18": { + "title": "Absolute OpenAPI filepath is not relative", + "disposition": "keep_sentry", + "rationale": "Absolute path reached a relative-path invariant; needs path normalization or boundary validation fix.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "OpenAPI or workspace path conversion received an absolute path where a relative path was required; path boundary bug until fixed." + }, + "CLI-34": { + "title": "Python package path not found", + "disposition": "shipped", + "rationale": "Library docs generation failed in the external library-docs service; the CLI should not report service job failures as internal defects.", + "fixSummary": "Map failed library-docs generation statuses to NetworkError instead of InternalError.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Library docs generation failed in an external service job; should be non-reportable service/network semantics." + }, + "CLI-2J": { + "title": "Failed to load generator migrations", + "disposition": "shipped", + "rationale": "Migration loading failed because the user's local migration cache/npm environment could not create its cache directory.", + "fixSummary": "Wrap migration package install/load failures as CliError(EnvironmentError) while preserving true CliErrors.", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Generator migrations failed to load due local npm/cache/environment error; should be environment semantics." + }, + "CLI-2D": { + "title": "git rm -rf command failed", + "disposition": "shipped", + "rationale": "Generated-output cleanup failed because the user's git worktree/submodule state rejected git rm.", + "fixSummary": "Wrap local generated-output git command failures as CliError(UserError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Git subprocess failure during generated output cleanup reported as InternalError; should be user/worktree semantics." + }, + "CLI-22": { + "title": "Auth0 SSO connection returned HTTP 400", + "disposition": "shipped", + "rationale": "SSO connection resolution 400 is an auth/login boundary failure, not an internal CLI defect.", + "fixSummary": "Map Auth0 SSO resolve HTTP 400 responses to CliError(AuthError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Auth0 login/SSO request returned HTTP 400 and surfaced as AxiosError; should be auth semantics." + }, + "CLI-D": { + "title": "Invalid BAML provider bedrock", + "disposition": "shipped", + "rationale": "Unsupported BAML provider comes from user AI configuration in generators.yml.", + "fixSummary": "Wrap BAML client setup failures at the local-generation AI config boundary as CliError(ConfigError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "AI configuration selected an unsupported BAML provider and surfaced as InternalError; should be config semantics." + }, + "CLI-21": { + "title": "User post-generation sed command failed", + "disposition": "shipped", + "rationale": "Placeholder replacement failed in generated files because the local sed command could not process user output bytes.", + "fixSummary": "Wrap auto-version placeholder replacement subprocess failures as CliError(UserError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "Auto-version placeholder replacement subprocess failed on generated/user files; should be user semantics." + }, + "CLI-1M": { + "title": "buf generate command failed", + "disposition": "shipped", + "rationale": "buf/protobuf generation is an external local tool boundary; command failures should be user-facing, not internal.", + "fixSummary": "Run buf commands with controlled exit-code handling and map failures to CliError(UserError).", + "prOrIssue": "This PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "buf/protobuf subprocess failed during generation and was reported as InternalError; should be user/tool semantics." + }, + "CLI-K": { + "title": "Package fern-api could not be found", + "disposition": "keep_sentry", + "rationale": "Package manager bootstrap failure needs environment/package-boundary handling; not enough evidence for a safe suppression.", + "fixSummary": "—", + "prOrIssue": "Keep in Sentry until product fix", + "lastAnalyzed": "2026-05-04", + "problemSignature": "CLI package lookup/bootstrap failed because package could not be found; environment/package boundary needs investigation." + }, + "CLI-C": { + "title": "stream-json parser expected comma", + "disposition": "shipped", + "rationale": "The stream-json parser failure occurs while reading user-provided IR for diff; current code wraps it as ParseError at that boundary.", + "fixSummary": "diff command catches streamObjectFromFile failures and reports CliError(ParseError).", + "prOrIssue": "Already handled in current code; ledger corrected in this PR", + "lastAnalyzed": "2026-05-05", + "problemSignature": "stream-json parser failed on malformed user-provided IR input; should be parse semantics at diff boundary." + } + } +} diff --git a/generators/python/sdk/changes/5.12.9/bump-generator-cli-0.9.28.yml b/generators/python/sdk/changes/5.12.9/bump-generator-cli-0.9.28.yml new file mode 100644 index 000000000000..857a084076ba --- /dev/null +++ b/generators/python/sdk/changes/5.12.9/bump-generator-cli-0.9.28.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Bump @fern-api/generator-cli to 0.9.28, which sets explicit author and + committer on API-created commits to the Fern bot identity. Fixes commit + attribution on GitHub Enterprise where PAT-based authentication previously + attributed commits to the PAT-owning service account instead of fern-api[bot]. + type: fix diff --git a/generators/python/sdk/versions.yml b/generators/python/sdk/versions.yml index f015caa0bfd5..b30a6ff67d82 100644 --- a/generators/python/sdk/versions.yml +++ b/generators/python/sdk/versions.yml @@ -1,4 +1,14 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 5.12.9 + changelogEntry: + - summary: | + Bump @fern-api/generator-cli to 0.9.28, which sets explicit author and + committer on API-created commits to the Fern bot identity. Fixes commit + attribution on GitHub Enterprise where PAT-based authentication previously + attributed commits to the PAT-owning service account instead of fern-api[bot]. + type: fix + createdAt: "2026-05-15" + irVersion: 66 - version: 5.12.8 changelogEntry: - summary: | diff --git a/packages/cli/cli-v2/src/commands/replay/resolve/command.ts b/packages/cli/cli-v2/src/commands/replay/resolve/command.ts index fcda61dbafe7..45e6887b2b85 100644 --- a/packages/cli/cli-v2/src/commands/replay/resolve/command.ts +++ b/packages/cli/cli-v2/src/commands/replay/resolve/command.ts @@ -55,7 +55,7 @@ export class ResolveCommand { } else { throw new CliError({ message: `Resolve failed: ${result.reason ?? "unknown error"}`, - code: CliError.Code.InternalError + code: CliError.Code.UserError }); } } diff --git a/packages/cli/cli/changes/unreleased/fix-sentry-false-positive-classification.yml b/packages/cli/cli/changes/unreleased/fix-sentry-false-positive-classification.yml new file mode 100644 index 000000000000..1246743f2535 --- /dev/null +++ b/packages/cli/cli/changes/unreleased/fix-sentry-false-positive-classification.yml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Suppress additional Sentry false positives for interrupted syscalls, invalid versions, YAML parse failures, IR schema parse failures, invalid GitHub repository config, replay resolve failures, missing translation directories, and global theme fetch failures. + type: fix diff --git a/packages/cli/cli/src/cli.ts b/packages/cli/cli/src/cli.ts index bf846c822200..e53d216bb0ff 100644 --- a/packages/cli/cli/src/cli.ts +++ b/packages/cli/cli/src/cli.ts @@ -3375,7 +3375,7 @@ function addReplayResolveCommand(cli: Argv, cliContext: CliCon cliContext.failAndThrow( `Resolve failed: ${result.reason ?? "unknown error"}`, undefined, - { code: CliError.Code.InternalError } + { code: CliError.Code.UserError } ); } } diff --git a/packages/cli/cli/src/commands/docs-md-generate/generateLibraryDocs.ts b/packages/cli/cli/src/commands/docs-md-generate/generateLibraryDocs.ts index f5ea6f48b7bf..701dac419eac 100644 --- a/packages/cli/cli/src/commands/docs-md-generate/generateLibraryDocs.ts +++ b/packages/cli/cli/src/commands/docs-md-generate/generateLibraryDocs.ts @@ -368,7 +368,7 @@ async function pollForCompletion( return context.failAndThrow( `Generation failed for library '${libraryName}': ${status.error?.message ?? "Unknown error"} (${status.error?.code ?? "UNKNOWN"})`, undefined, - { code: CliError.Code.InternalError } + { code: CliError.Code.NetworkError } ); default: return context.failAndThrow( diff --git a/packages/cli/cli/src/commands/upgrade/migrations/loader.ts b/packages/cli/cli/src/commands/upgrade/migrations/loader.ts index 7003a5739575..dc5e735fa23d 100644 --- a/packages/cli/cli/src/commands/upgrade/migrations/loader.ts +++ b/packages/cli/cli/src/commands/upgrade/migrations/loader.ts @@ -279,9 +279,15 @@ export async function loadMigrationModule(params: { return undefined; } - // Any other error indicates a problem loading migrations that should halt the upgrade - const userFriendlyError = new Error( - `Failed to load generator migrations for ${generatorName}.\n\n` + + if (error instanceof CliError) { + throw error; + } + + // Any other error indicates a local/npm/cache problem loading migrations that should halt the upgrade. + const userFriendlyError = new CliError({ + code: CliError.Code.EnvironmentError, + message: + `Failed to load generator migrations for ${generatorName}.\n\n` + `Reason: ${errorMessage}\n\n` + `This error occurred while trying to install the migration package (${MIGRATION_PACKAGE_NAME}). ` + `Please check your internet connection and npm configuration, then try again.\n\n` + @@ -289,7 +295,7 @@ export async function loadMigrationModule(params: { ` 1. Check if npm is working: npm --version\n` + ` 2. Clear the migration cache: rm -rf ~/.fern/migration-cache\n` + ` 3. Try the upgrade again: fern generator upgrade` - ); + }); throw userFriendlyError; } } diff --git a/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts b/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts index 9762159a108b..26f09eee5857 100644 --- a/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts +++ b/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts @@ -2014,12 +2014,14 @@ async function loadTranslationPages({ if (!(await doesPathExist(langDir))) { context.failAndThrow( - `Translation directory for locale "${lang}" not found.`, - `Expected a directory at: ${langDir}\n` + + `Translation directory for locale "${lang}" not found.\n` + + `Expected a directory at: ${langDir}\n` + `Create the directory and add translated versions of your documentation pages.\n` + `The directory should mirror the same relative paths referenced in your docs.yml navigation.\n` + `Example: if your docs.yml references "pages/getting-started.mdx", add a translated\n` + - `version at "translations/${lang}/pages/getting-started.mdx".` + `version at "translations/${lang}/pages/getting-started.mdx".`, + undefined, + { code: CliError.Code.ValidationError } ); return; } diff --git a/packages/cli/configuration-loader/src/generators-yml/convertGeneratorsConfiguration.ts b/packages/cli/configuration-loader/src/generators-yml/convertGeneratorsConfiguration.ts index f829804b838c..99610b773261 100644 --- a/packages/cli/configuration-loader/src/generators-yml/convertGeneratorsConfiguration.ts +++ b/packages/cli/configuration-loader/src/generators-yml/convertGeneratorsConfiguration.ts @@ -815,8 +815,19 @@ async function convertOutputMode({ const downloadSnippets = generator.snippets != null && generator.snippets.path !== ""; if (generator.github) { const repoString = isGithubSelfhosted(generator.github) ? generator.github.uri : generator.github.repository; - const { owner, repo, remote } = parseRepository(repoString); + let owner: string; + let repo: string; + let remote: string; + try { + ({ owner, repo, remote } = parseRepository(repoString)); + } catch { + throw new CliError({ + message: `Invalid GitHub repository "${repoString}" in generators.yml. Expected a repository like "owner/repo", "github.com/owner/repo", or "https://github.com/owner/repo.git".`, + code: CliError.Code.ConfigError + }); + } const host = remote !== "github.com" ? remote : undefined; + const publishInfo = generator.output != null ? getGithubPublishInfo(generator.output, maybeGroupLevelMetadata, maybeTopLevelMetadata) diff --git a/packages/cli/docs-resolver/src/stitchGlobalTheme.ts b/packages/cli/docs-resolver/src/stitchGlobalTheme.ts index b1edc84bfaca..8a2319e842be 100644 --- a/packages/cli/docs-resolver/src/stitchGlobalTheme.ts +++ b/packages/cli/docs-resolver/src/stitchGlobalTheme.ts @@ -1,6 +1,6 @@ import { docsYml } from "@fern-api/configuration"; import { AbsoluteFilePath } from "@fern-api/fs-utils"; -import { TaskContext } from "@fern-api/task-context"; +import { CliError, TaskContext } from "@fern-api/task-context"; import { DocsWorkspace } from "@fern-api/workspace-loader"; import { writeFile } from "fs/promises"; @@ -331,11 +331,15 @@ export async function stitchGlobalTheme({ if (res.status === 404) { taskContext.failAndThrow( `Global theme "${themeName}" not found for org "${organization}". ` + - `Upload it first with: fern beta docs theme upload --name ${themeName}` + `Upload it first with: fern beta docs theme upload --name ${themeName}`, + undefined, + { code: CliError.Code.ConfigError } ); } if (!res.ok) { - taskContext.failAndThrow(`Failed to fetch global theme "${themeName}": HTTP ${res.status}`); + taskContext.failAndThrow(`Failed to fetch global theme "${themeName}": HTTP ${res.status}`, undefined, { + code: CliError.Code.ConfigError + }); } let parsed: unknown; @@ -344,7 +348,9 @@ export async function stitchGlobalTheme({ } catch { taskContext.failAndThrow( `Failed to fetch global theme "${themeName}": unexpected response from server` + - (rawText.length > 0 ? ` — ${rawText.slice(0, 200)}` : " (empty body)") + (rawText.length > 0 ? ` — ${rawText.slice(0, 200)}` : " (empty body)"), + undefined, + { code: CliError.Code.NetworkError } ); } @@ -357,23 +363,33 @@ export async function stitchGlobalTheme({ if (body.error.code === "NOT_FOUND") { taskContext.failAndThrow( `Global theme "${themeName}" not found for org "${organization}". ` + - `Upload it first with: fern beta docs theme upload --name ${themeName}` + `Upload it first with: fern beta docs theme upload --name ${themeName}`, + undefined, + { code: CliError.Code.ConfigError } ); } taskContext.failAndThrow( - `Failed to fetch global theme "${themeName}": ${body.error.message ?? body.error.code ?? "unknown error"}` + `Failed to fetch global theme "${themeName}": ${body.error.message ?? body.error.code ?? "unknown error"}`, + undefined, + { code: CliError.Code.ConfigError } ); } if (body.config == null) { - taskContext.failAndThrow(`Failed to fetch global theme "${themeName}": response missing "config" field`); + taskContext.failAndThrow( + `Failed to fetch global theme "${themeName}": response missing "config" field`, + undefined, + { code: CliError.Code.NetworkError } + ); return docsWorkspace; // unreachable — TS needs this for definite-assignment of themeConfig } themeConfig = body.config; } catch (err) { if (err instanceof Error && err.message.includes("fetch failed")) { - taskContext.failAndThrow(`Could not reach FDR at ${fdrOrigin} to fetch global theme "${themeName}"`); + taskContext.failAndThrow(`Could not reach FDR at ${fdrOrigin} to fetch global theme "${themeName}"`, err, { + code: CliError.Code.NetworkError + }); } throw err; } @@ -387,7 +403,9 @@ export async function stitchGlobalTheme({ resolvedConfig = await resolveThemeFileUrls(themeConfig, tmpDirPath); } catch (err) { const detail = err instanceof Error ? `: ${err.message}` : ""; - taskContext.failAndThrow(`Failed to download assets for global theme "${themeName}"${detail}`); + taskContext.failAndThrow(`Failed to download assets for global theme "${themeName}"${detail}`, err, { + code: CliError.Code.NetworkError + }); return docsWorkspace; // unreachable — TS needs this for definite-assignment of resolvedConfig } diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/imdb/type__Movie.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/imdb/type__Movie.json index e9502799e9ed..c728f1139536 100644 --- a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/imdb/type__Movie.json +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/imdb/type__Movie.json @@ -8,7 +8,8 @@ "type": "string" }, "rating": { - "type": "number" + "type": "number", + "description": "The rating scale is one to five stars" } }, "required": [ diff --git a/packages/cli/generation/local-generation/local-workspace-runner/src/LocalTaskHandler.ts b/packages/cli/generation/local-generation/local-workspace-runner/src/LocalTaskHandler.ts index 1debb25a3e05..0e735151f6be 100644 --- a/packages/cli/generation/local-generation/local-workspace-runner/src/LocalTaskHandler.ts +++ b/packages/cli/generation/local-generation/local-workspace-runner/src/LocalTaskHandler.ts @@ -721,7 +721,14 @@ export class LocalTaskHandler { this.context.logger.debug(`Using AI service: ${this.ai.provider} with model ${this.ai.model}`); const { configureBamlClient } = await loadBamlDependencies(); - return configureBamlClient(this.ai); + try { + return configureBamlClient(this.ai); + } catch (error) { + throw new CliError({ + message: `Invalid AI service configuration: ${extractErrorMessage(error)}`, + code: CliError.Code.ConfigError + }); + } } private addFernBranding(message: string): string { @@ -930,11 +937,18 @@ export class LocalTaskHandler { } private async runGitCommand(options: string[], cwd: AbsoluteFilePath): Promise { - const response = await loggingExeca(this.context.logger, "git", options, { - cwd, - doNotPipeOutput: true - }); - return response.stdout; + try { + const response = await loggingExeca(this.context.logger, "git", options, { + cwd, + doNotPipeOutput: true + }); + return response.stdout; + } catch (error) { + throw new CliError({ + message: `Git command failed in generated output directory: ${extractErrorMessage(error)}`, + code: CliError.Code.UserError + }); + } } private async runThrowawayGitCommand(options: string[], cwd: AbsoluteFilePath): Promise { diff --git a/packages/cli/login/src/auth0-login/resolveSsoConnection.ts b/packages/cli/login/src/auth0-login/resolveSsoConnection.ts index 760a569d994b..e0565e3723c2 100644 --- a/packages/cli/login/src/auth0-login/resolveSsoConnection.ts +++ b/packages/cli/login/src/auth0-login/resolveSsoConnection.ts @@ -18,11 +18,19 @@ export async function resolveSsoConnection({ } ); } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { - throw new CliError({ - message: `No SSO connection associated with email: ${email}`, - code: CliError.Code.AuthError - }); + if (axios.isAxiosError(error)) { + if (error.response?.status === 404) { + throw new CliError({ + message: `No SSO connection associated with email: ${email}`, + code: CliError.Code.AuthError + }); + } + if (error.response?.status === 400) { + throw new CliError({ + message: `Unable to resolve SSO connection for email: ${email}`, + code: CliError.Code.AuthError + }); + } } throw error; } diff --git a/packages/cli/task-context/src/CliError.ts b/packages/cli/task-context/src/CliError.ts index f835b017f0c8..983f6652cc38 100644 --- a/packages/cli/task-context/src/CliError.ts +++ b/packages/cli/task-context/src/CliError.ts @@ -104,6 +104,7 @@ const USER_ENVIRONMENT_ERRNOS: ReadonlySet = new Set([ "ENOENT", "EACCES", "EPERM", + "EINTR", "EISDIR", "ENOTDIR", "EEXIST", diff --git a/packages/cli/workspace/lazy-fern-workspace/src/protobuf/ProtobufOpenAPIGenerator.ts b/packages/cli/workspace/lazy-fern-workspace/src/protobuf/ProtobufOpenAPIGenerator.ts index 8641cc9fbd90..0d700479112a 100644 --- a/packages/cli/workspace/lazy-fern-workspace/src/protobuf/ProtobufOpenAPIGenerator.ts +++ b/packages/cli/workspace/lazy-fern-workspace/src/protobuf/ProtobufOpenAPIGenerator.ts @@ -130,9 +130,15 @@ export class ProtobufOpenAPIGenerator { logger: this.context.logger, stdout: "ignore", stderr: "pipe", + reject: false, ...(envOverride != null ? { env: { ...process.env, ...envOverride } } : {}) }); - await buf(["dep", "update"]); + const bufDepUpdateResult = await buf(["dep", "update"]); + if (bufDepUpdateResult.exitCode !== 0) { + this.context.failAndThrow(bufDepUpdateResult.stderr, undefined, { + code: CliError.Code.UserError + }); + } } } @@ -164,13 +170,14 @@ export class ProtobufOpenAPIGenerator { logger: this.context.logger, stdout: "ignore", stderr: "pipe", + reject: false, ...(preparedDir.envOverride != null ? { env: { ...process.env, ...preparedDir.envOverride } } : {}) }); const bufGenerateResult = await buf(["generate", target.toString()]); if (bufGenerateResult.exitCode !== 0) { this.context.failAndThrow(bufGenerateResult.stderr, undefined, { - code: CliError.Code.IrConversionError + code: CliError.Code.UserError }); } @@ -271,6 +278,7 @@ export class ProtobufOpenAPIGenerator { logger: this.context.logger, stdout: "ignore", stderr: "pipe", + reject: false, ...(envOverride != null ? { env: { ...process.env, ...envOverride } } : {}) }); @@ -296,7 +304,12 @@ export class ProtobufOpenAPIGenerator { } } else { // Run buf dep update to populate the cache (needed at build time) - await buf(["dep", "update"]); + const bufDepUpdateResult = await buf(["dep", "update"]); + if (bufDepUpdateResult.exitCode !== 0) { + this.context.failAndThrow(bufDepUpdateResult.stderr, undefined, { + code: CliError.Code.UserError + }); + } } // Read buf.lock contents for caching try { @@ -309,7 +322,7 @@ export class ProtobufOpenAPIGenerator { const bufGenerateResult = await buf(["generate", target.toString()]); if (bufGenerateResult.exitCode !== 0) { this.context.failAndThrow(bufGenerateResult.stderr, undefined, { - code: CliError.Code.IrConversionError + code: CliError.Code.UserError }); } if (cleanupBufLock) { diff --git a/packages/cli/workspace/lazy-fern-workspace/src/utils/loadDependency.ts b/packages/cli/workspace/lazy-fern-workspace/src/utils/loadDependency.ts index 3ad9149c9b3c..ec3306d6f273 100644 --- a/packages/cli/workspace/lazy-fern-workspace/src/utils/loadDependency.ts +++ b/packages/cli/workspace/lazy-fern-workspace/src/utils/loadDependency.ts @@ -1,7 +1,7 @@ import { FernDefinition, FernWorkspace } from "@fern-api/api-workspace-commons"; import { dependenciesYml } from "@fern-api/configuration-loader"; import { createFiddleService } from "@fern-api/core"; -import { assertNever, noop, visitObject } from "@fern-api/core-utils"; +import { assertNever, extractErrorMessage, noop, visitObject } from "@fern-api/core-utils"; import { RootApiFileSchema, YAML_SCHEMA_VERSION } from "@fern-api/fern-definition-schema"; import { AbsoluteFilePath, doesPathExist, join, RelativeFilePath } from "@fern-api/fs-utils"; import { parseVersion } from "@fern-api/semver-utils"; @@ -222,8 +222,21 @@ async function validateVersionedDependencyAndGetDefinition({ const parsedYamlVersionOfDependency = response.body.yamlSchemaVersion != null ? parseInt(response.body.yamlSchemaVersion) : undefined; - const parsedCliVersion = parseVersion(cliVersion); - const parsedCliVersionOfDependency = parseVersion(response.body.cliVersion); + let parsedCliVersion: ReturnType; + let parsedCliVersionOfDependency: ReturnType; + try { + parsedCliVersion = parseVersion(cliVersion); + parsedCliVersionOfDependency = parseVersion(response.body.cliVersion); + } catch (error) { + context.failWithoutThrowing( + `Failed to parse dependency CLI version: ${extractErrorMessage(error)}`, + undefined, + { + code: CliError.Code.VersionError + } + ); + return undefined; + } // ensure dependency is on the same YAML_SCHEMA_VERSION if (parsedYamlVersionOfDependency != null) { diff --git a/packages/cli/workspace/loader/src/loadDocsWorkspace.ts b/packages/cli/workspace/loader/src/loadDocsWorkspace.ts index 123cdf552347..92a9e61894a7 100644 --- a/packages/cli/workspace/loader/src/loadDocsWorkspace.ts +++ b/packages/cli/workspace/loader/src/loadDocsWorkspace.ts @@ -65,7 +65,18 @@ export async function loadRawDocsConfiguration({ context: TaskContext; }): Promise { const contentsStr = await readFile(absolutePathOfConfiguration); - const contentsJson = yaml.load(contentsStr.toString()); + let contentsJson: unknown; + try { + contentsJson = yaml.load(contentsStr.toString()); + } catch (error) { + if (!(error instanceof yaml.YAMLException)) { + throw error; + } + throw new CliError({ + message: `Failed to parse ${absolutePathOfConfiguration}: ${extractErrorMessage(error)}`, + code: CliError.Code.ParseError + }); + } // biome-ignore lint/suspicious/noExplicitAny: allow explicit any const result = validateAgainstJsonSchema(contentsJson, DocsYmlJsonSchema as any, { filePath: absolutePathOfConfiguration diff --git a/packages/commons/github/src/parseRepository.ts b/packages/commons/github/src/parseRepository.ts index aae0b7101dec..1f805510cbf8 100644 --- a/packages/commons/github/src/parseRepository.ts +++ b/packages/commons/github/src/parseRepository.ts @@ -20,10 +20,10 @@ export function parseRepository(githubRepository: string): RepositoryReference { const parts = githubRepository.split("/"); - if (parts.length === 2 && parts[0] != null && parts[1] != null) { + if (parts.length === 2 && isNonEmptyPart(parts[0]) && isNonEmptyPart(parts[1])) { // Format: owner/repo [owner, repo] = parts; - } else if (parts.length === 3 && parts[0] != null && parts[1] != null && parts[2] != null) { + } else if (parts.length === 3 && isNonEmptyPart(parts[0]) && isNonEmptyPart(parts[1]) && isNonEmptyPart(parts[2])) { // Format: github.com/owner/repo [remote, owner, repo] = parts; } else { @@ -33,6 +33,10 @@ export function parseRepository(githubRepository: string): RepositoryReference { return newRepositoryReference({ remote, owner, repo }); } +function isNonEmptyPart(part: string | undefined): part is string { + return part != null && part.length > 0; +} + function newRepositoryReference({ remote, owner, diff --git a/packages/generator-cli/src/autoversion/AutoVersioningService.ts b/packages/generator-cli/src/autoversion/AutoVersioningService.ts index b0ebcca9b615..2cfdd54d6020 100644 --- a/packages/generator-cli/src/autoversion/AutoVersioningService.ts +++ b/packages/generator-cli/src/autoversion/AutoVersioningService.ts @@ -1,5 +1,6 @@ +import { extractErrorMessage } from "@fern-api/core-utils"; import { loggingExeca } from "@fern-api/logging-execa"; -import { TaskContext } from "@fern-api/task-context"; +import { CliError, TaskContext } from "@fern-api/task-context"; import { existsSync } from "fs"; import { readdir, readFile, stat, writeFile } from "fs/promises"; import { extname, join } from "path"; @@ -856,10 +857,17 @@ export class AutoVersioningService { command = `find "${workingDirectory}" -type f -not -path "*/.git/*" -exec sed -i '' '${sedCommand}' {} +`; } - await loggingExeca(this.logger, "bash", ["-c", command], { - cwd: workingDirectory, - doNotPipeOutput: true - }); + try { + await loggingExeca(this.logger, "bash", ["-c", command], { + cwd: workingDirectory, + doNotPipeOutput: true + }); + } catch (error) { + throw new CliError({ + message: `Failed to replace placeholder version in generated files: ${extractErrorMessage(error)}`, + code: CliError.Code.UserError + }); + } this.logger.debug("Placeholder version replaced successfully"); } diff --git a/packages/generator-cli/versions.yml b/packages/generator-cli/versions.yml index c6fcaa56a59c..d53e7d136ebe 100644 --- a/packages/generator-cli/versions.yml +++ b/packages/generator-cli/versions.yml @@ -1,4 +1,15 @@ # yaml-language-server: $schema=../../versions-yml.schema.json +- changelogEntry: + - summary: | + Set explicit author and committer on API-created commits to the Fern bot + identity (`fern-api` / `115122769+fern-api[bot]@users.noreply.github.com`). + Previously, `octokit.git.createCommit()` defaulted to the authenticated user, + which for PAT-based authentication (e.g. GitHub Enterprise) attributed commits + to the PAT-owning service account instead of a stable bot identity. + type: fix + createdAt: "2026-05-06" + version: 0.9.28 + - changelogEntry: - summary: | Fix `createReplayBranch` crashing with `fatal: is not a valid object` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39e9d06ee030..c1c4902e3b74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,8 +37,8 @@ catalogs: specifier: 0.0.6-2ee1b7e28 version: 0.0.6-2ee1b7e28 '@fern-api/generator-cli': - specifier: 0.9.27 - version: 0.9.27 + specifier: 0.9.28 + version: 0.9.28 '@fern-api/venus-api-sdk': specifier: 0.22.34 version: 0.22.34 @@ -630,7 +630,7 @@ importers: version: link:packages/configs '@fern-api/generator-cli': specifier: 'catalog:' - version: 0.9.27 + version: 0.9.28 '@rolldown/binding-darwin-arm64': specifier: 'catalog:' version: 1.0.0 @@ -699,7 +699,7 @@ importers: version: link:../../packages/commons/fs-utils '@fern-api/generator-cli': specifier: 'catalog:' - version: 0.9.27 + version: 0.9.28 '@fern-api/ir-sdk': specifier: workspace:* version: link:../../packages/ir-sdk @@ -2466,7 +2466,7 @@ importers: version: link:../../../packages/commons/fs-utils '@fern-api/generator-cli': specifier: 'catalog:' - version: 0.9.27 + version: 0.9.28 '@fern-api/logger': specifier: workspace:* version: link:../../../packages/cli/logger @@ -9450,8 +9450,8 @@ packages: '@fern-api/fdr-sdk@1.2.4-f661387fb2': resolution: {integrity: sha512-wlk1lTCIZ7biND4vQf8jvhUw9P/rBQ5pXASCrumv8R96up0B3DY6yiY1C4VmFyHmp/kPhcjzc5T9TvHZZxFdrA==} - '@fern-api/generator-cli@0.9.27': - resolution: {integrity: sha512-01GBGwtXm5gZ06amH/V8Bb7sGSWiSBMQnG6hUyTbJK2qaXNUHygNGqOjOIF5XDwjXww6DZLLsJfEoEAzaUFflg==} + '@fern-api/generator-cli@0.9.28': + resolution: {integrity: sha512-XWotnNAkiMIIKFE4xujI3O31Cd0PDljogKqUytGgnJH+a74rtMtGrSGWG58ryfDBCoJtLsjS1Q/B9vUlkceAJQ==} hasBin: true '@fern-api/replay@0.15.0': @@ -16383,7 +16383,7 @@ snapshots: - encoding - typescript - '@fern-api/generator-cli@0.9.27': + '@fern-api/generator-cli@0.9.28': dependencies: '@boundaryml/baml': 0.219.0 '@fern-api/replay': 0.15.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 99e7f58d0fb5..4a2f64922528 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -68,7 +68,7 @@ catalog: "@bufbuild/protoplugin": 2.2.5 "@fern-api/fai-sdk": 0.0.6-2ee1b7e28 "@fern-api/fdr-sdk": 1.2.4-f661387fb2 - "@fern-api/generator-cli": 0.9.27 + "@fern-api/generator-cli": 0.9.28 "@fern-api/ui-core-utils": 0.129.4-b6c699ad2 "@fern-api/venus-api-sdk": 0.22.34 "@fern-fern/docs-config": 0.0.80 diff --git a/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock b/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock index 120677f1ba91..ad3d67d5a2c8 100644 --- a/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock +++ b/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock @@ -2248,77 +2248,77 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "tiktoken" -version = "0.12.0" +version = "0.13.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970"}, - {file = "tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16"}, - {file = "tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030"}, - {file = "tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134"}, - {file = "tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a"}, - {file = "tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892"}, - {file = "tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1"}, - {file = "tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb"}, - {file = "tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa"}, - {file = "tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc"}, - {file = "tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded"}, - {file = "tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd"}, - {file = "tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967"}, - {file = "tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def"}, - {file = "tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8"}, - {file = "tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b"}, - {file = "tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37"}, - {file = "tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad"}, - {file = "tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5"}, - {file = "tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3"}, - {file = "tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd"}, - {file = "tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3"}, - {file = "tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160"}, - {file = "tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa"}, - {file = "tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be"}, - {file = "tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a"}, - {file = "tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3"}, - {file = "tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697"}, - {file = "tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16"}, - {file = "tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a"}, - {file = "tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27"}, - {file = "tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb"}, - {file = "tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e"}, - {file = "tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25"}, - {file = "tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f"}, - {file = "tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646"}, - {file = "tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88"}, - {file = "tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff"}, - {file = "tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830"}, - {file = "tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b"}, - {file = "tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b"}, - {file = "tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3"}, - {file = "tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365"}, - {file = "tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e"}, - {file = "tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63"}, - {file = "tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0"}, - {file = "tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a"}, - {file = "tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0"}, - {file = "tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71"}, - {file = "tiktoken-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d51d75a5bffbf26f86554d28e78bfb921eae998edc2675650fd04c7e1f0cdc1e"}, - {file = "tiktoken-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:09eb4eae62ae7e4c62364d9ec3a57c62eea707ac9a2b2c5d6bd05de6724ea179"}, - {file = "tiktoken-0.12.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:df37684ace87d10895acb44b7f447d4700349b12197a526da0d4a4149fde074c"}, - {file = "tiktoken-0.12.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4c9614597ac94bb294544345ad8cf30dac2129c05e2db8dc53e082f355857af7"}, - {file = "tiktoken-0.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:20cf97135c9a50de0b157879c3c4accbb29116bcf001283d26e073ff3b345946"}, - {file = "tiktoken-0.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:15d875454bbaa3728be39880ddd11a5a2a9e548c29418b41e8fd8a767172b5ec"}, - {file = "tiktoken-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cff3688ba3c639ebe816f8d58ffbbb0aa7433e23e08ab1cade5d175fc973fb3"}, - {file = "tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931"}, + {file = "tiktoken-0.13.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:47b1df8d73390a24f94980c75158cdd5c56d256f16d55f30cb49c230caba9ba4"}, + {file = "tiktoken-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d40c6c5aab171dcd6eb8455bc567bde404bb9def60cdb8c1299cc782b242bb9"}, + {file = "tiktoken-0.13.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:9b842981fa91accdffd48ff6408a977b7a91c3fbda55d353c3c68114d5c9d69e"}, + {file = "tiktoken-0.13.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed5a30027cb4d8c7ca8b273d4766f3db3cf58fad9e9f3b1a68a351ffb54873d5"}, + {file = "tiktoken-0.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7ab10f4a21c2999846940113f6dbd72e0fa06a24119feddd74cc47e85818e06d"}, + {file = "tiktoken-0.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a2937ad042d49d50eac6e1ba07c5661d4bd3942a5b1e0c0d08475c4df83676e1"}, + {file = "tiktoken-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:44733b99bfd72b590cd0936b1c01b3b4dd73122db2d544bc1ceeb18a7678c910"}, + {file = "tiktoken-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7bfe1849caa65d1e1d9871817170ec497bbb7984e182012e1bdce72f66608cdb"}, + {file = "tiktoken-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:91c180fe255bd5a86d8316210d2833a1d4d33d026cd86a67812f4773743c8d26"}, + {file = "tiktoken-0.13.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:059c8ecf554eb5b41e6e054ba467b871b03277d267dee7244380aca4359747d4"}, + {file = "tiktoken-0.13.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:36217497eaffc158607a3b26f065300db2aefd43b115263f3b9688ce38146173"}, + {file = "tiktoken-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:303f7d91b4fce3baddbcde05c139091d4caa5026ac7214c1dc7ff7a71ee429ff"}, + {file = "tiktoken-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5d48843bee149630eb735a99e1f4a85b47308d21868ea63163f6e87768d3cfed"}, + {file = "tiktoken-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc1c44cd37b43fc46bae593129164f4f281e82ea116b57a85aa81bda57eafc94"}, + {file = "tiktoken-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32ac870a806cfb260a02d0cb70426aef02e038297f8ad50df5040bb5af360791"}, + {file = "tiktoken-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d9980f11429ed2d737c463bb1fb78cf330caa026adf002f714aced7849a687b"}, + {file = "tiktoken-0.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3f277ebea5edd7b8bf03c6f9431e1d67d517530115572b2dc1d465326e8f88c7"}, + {file = "tiktoken-0.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a116178fa7e1b4065bff05214360373a65cac22f965be7b3f73d00a0dbfe7649"}, + {file = "tiktoken-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c397ddda233208345b01bd30f2fca79ff730e55731d0108a603f9bc57f6af3b"}, + {file = "tiktoken-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95097e4f89b06403976e498abf61a0ee73a7497e73fb599cb211d8197a054d91"}, + {file = "tiktoken-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f2d16e7a7c783ad81f36e457d046d1f1c8af70b22aec8a13238efe531977c41"}, + {file = "tiktoken-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5df5d1507bd245f1ccad4a074698240021239e455eb0bb4ced4e3d7181872154"}, + {file = "tiktoken-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8fe806a50664e83a6ffd56cbd1e4f5dcc6cd32a3e7538f70dc38b1a271384545"}, + {file = "tiktoken-0.13.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:125bc05005e747f993a83dc67934249932d6e4209854452cd4c0b1d53fba3ba2"}, + {file = "tiktoken-0.13.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5e6358911cab4adee6712da27d65573496a4f68cf8a2b5fca6a4ad10fc5748cf"}, + {file = "tiktoken-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:975cbd78d085d75d26b59660e262736dcaed1e35f8f142cd6291025c01d25486"}, + {file = "tiktoken-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ab9bc99fa020a4c283424590ecd7f3afd70c1c281cb3fa3192a6c3af9f9615"}, + {file = "tiktoken-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:6b1615f0ff71953d19729ceb18865429c185b0a23c5353f1bbca34a394bf60f7"}, + {file = "tiktoken-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6eb4a5bfbc6426938026b1a334e898ac53541360d62d8c689870160cc80abd67"}, + {file = "tiktoken-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:43cee3e5400573b2046fbf092cc7a5bc30164f9e4c95ce20714da929df48737a"}, + {file = "tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7de52e3f566d19b3b11bd37eea552c6c305ad74081f736882bd44d148ed4c48d"}, + {file = "tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:51384448aa508e4df84c0f7c1dc3211c7f7b8096325660ee5fc82f3e11b381ce"}, + {file = "tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e28157350f7ebf35008dd8e9e0fdb621f976e4230c881099c85e8cf07eaa50e2"}, + {file = "tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:165cf1820ea4a354985c2490a5205d4cc74661c934aca79dd0368232fff94e0f"}, + {file = "tiktoken-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6c43a675ca14f6f2749ba7f12075d37456015a24b859f2517b9beb4ef30807ec"}, + {file = "tiktoken-0.13.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaaaef47c2406277181d2086484c317bf7fc433e2d5d03ff94f56b0dcec87471"}, + {file = "tiktoken-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ca8b310bd93b3772cb1b7922d915446864860f562bdfe4825c63a0aed3fb28cd"}, + {file = "tiktoken-0.13.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:32e0c12305105002c047b3bb1070b0dd9a73b0cb3b2856a8972b810e7a4f5881"}, + {file = "tiktoken-0.13.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:5ba5fd62507a932d1241346179e3b39bc7bf7408f03c272652d93b3bedf5db24"}, + {file = "tiktoken-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d108bc2d470fc53c8ecd24f2c0fd2b5f98c33e87cdb6aa2e9b8c5dced703d273"}, + {file = "tiktoken-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cb99cb5127449f58d0a2d5f5ccfb390d8dbdfd919c221246caaee29d8725ed51"}, + {file = "tiktoken-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:115c4f26ffa11caac8b54eea35c2ad38c612c20a48d35dd15d70a02ac6f51f58"}, + {file = "tiktoken-0.13.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:472527e9132952f2fbf77cd290658bacf003d4d5a3fabc18e5fbd407cbae4d9b"}, + {file = "tiktoken-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e2f67d27c9626cdd25fe33d9313c5cdb3d8d82da646b68d6eb8e7e9c20e6448"}, + {file = "tiktoken-0.13.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2b920b35805cd64585a37c3dc7ce65fba4d2d36016be01e1d7942482ca29093a"}, + {file = "tiktoken-0.13.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:493af3aa28a4aaf2e3d2600a2ee717252c9bf5ab38fff94eb5a02db5ab77e5ad"}, + {file = "tiktoken-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6644c9c2b5cf3916f5a3641d7d12fdb3f006a7b3d9ff6acdaec44e29ab1ff91e"}, + {file = "tiktoken-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5cb65b60b9408563676d874a3a4ee573370066f0dc4e29d84e82e989c6517424"}, + {file = "tiktoken-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:85b78cc3a2c3d48723ca751fa981f1fedccd54194ca0471b957364353a898b07"}, + {file = "tiktoken-0.13.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:35e1ea1e0631c04f551297284a1ab7e1f65a3c55a9a48728d5e0f66b4527c04a"}, + {file = "tiktoken-0.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a3b536c55802fe42f4b4644d2be4f04bf788506b48de0a0a658cb58f8bce232"}, + {file = "tiktoken-0.13.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b8ac2d6420ff05841a89ba5205c6d45f56c4f6843454f3c884b7eb1a2a8dddb2"}, + {file = "tiktoken-0.13.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:477c9a38e20d0ed248090509acf1e839ad3967a4f00b4b0f958210049f656dee"}, + {file = "tiktoken-0.13.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:da86f8c96ac1c235d7a3b3eebff1eacfdbcfb8ad792706943268d4d2938fbafe"}, + {file = "tiktoken-0.13.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9b8858b29804b3a0add25ce9e62fb00f89f621dc754d75d03ca419d17e8ddf67"}, + {file = "tiktoken-0.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:b967dfb9d0adf9a631953b1b40717684f04478270fc51bbccdd2f838d67a2f00"}, + {file = "tiktoken-0.13.0.tar.gz", hash = "sha256:c9435714c3a84c2319499de9a300c0e604449dd0799ff246458b3bb6a7f433c1"}, ] [package.dependencies] -regex = ">=2022.1.18" -requests = ">=2.26.0" +regex = "*" +requests = "*" [package.extras] -blobfile = ["blobfile (>=2)"] +blobfile = ["blobfile (>=3)"] [[package]] name = "toml"