From 5a1ba8a6adcc70db158d92cf1137e71271c3ac3e Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 16:52:01 +0000 Subject: [PATCH 1/4] build(deps): Bump @sentry/api to 1.52.0 1.52.0 tightens many response schemas: about 250 new `pattern`s, 140 new `enum`s and 125 typed objects in place of `additionalProperties: {}`. It also drops `uint64` formats and names the bound client type `PreparedClient` (sentry-api-schema#136). --- pnpm-lock.yaml | 16 ++++++++-------- pnpm-workspace.yaml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2673d8e26..211437c29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,8 +43,8 @@ catalogs: specifier: ^1.2.3 version: 1.2.3 '@sentry/api': - specifier: 1.51.0 - version: 1.51.0 + specifier: 1.52.0 + version: 1.52.0 '@sentry/cloudflare': specifier: 11.6.0 version: 11.6.0 @@ -513,7 +513,7 @@ importers: version: 2.1.5(hono@4.13.13) '@sentry/api': specifier: 'catalog:' - version: 1.51.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) + version: 1.52.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) '@sentry/core': specifier: 'catalog:' version: 11.6.0 @@ -865,7 +865,7 @@ importers: version: 2.4.0 '@sentry/api': specifier: 'catalog:' - version: 1.51.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) + version: 1.52.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) '@sentry/core': specifier: 'catalog:' version: 11.6.0 @@ -1048,7 +1048,7 @@ importers: dependencies: '@sentry/api': specifier: 'catalog:' - version: 1.51.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) + version: 1.52.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7) '@sentry/search-syntax': specifier: 'catalog:' version: 1.0.0 @@ -4275,8 +4275,8 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry/api@1.51.0': - resolution: {integrity: sha512-lp8nQxIKNcMR0WlwdLqvlAYY9zW7B4QFMxjl3dTWNM/o/2u+g6++hPnbXWkCPKQsJWTtQmv42Av1izlfaoFFGQ==} + '@sentry/api@1.52.0': + resolution: {integrity: sha512-xovKCa3h1WLbLvnz7ul6qYQz0qNVbn9qzQQ717Nq5Ehbv7PsHEwf1Dx0xph4HTY4U9H5m66CKhm5rexd6/Wsjg==} engines: {node: '>=22'} peerDependencies: typescript: '*' @@ -12112,7 +12112,7 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry/api@1.51.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7)': + '@sentry/api@1.52.0(typescript@5.9.3)(valibot@1.4.2(typescript@5.9.3))(zod@4.6.7)': dependencies: http-cache-semantics: 4.2.0 p-limit: 7.3.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 10ff6a807..40a638d03 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -51,7 +51,7 @@ catalog: "@modelcontextprotocol/server": 2.4.0 "@radix-ui/react-accordion": ^1.2.20 "@radix-ui/react-slot": ^1.2.3 - "@sentry/api": 1.51.0 + "@sentry/api": 1.52.0 "@sentry/cloudflare": 11.6.0 "@sentry/core": 11.6.0 "@sentry/node": 11.6.0 @@ -168,7 +168,7 @@ minimumReleaseAgeExclude: - "@oxlint/binding-win32-x64-msvc@1.87.0" - oxfmt@0.72.0 - oxlint@1.87.0 - - "@sentry/api@1.51.0" + - "@sentry/api@1.52.0" - miniflare@5.20261101.0-beta - wrangler@4.156.1 - "@sentry/symbolic@14.0.0-alpha.5" From d840f6b19198f8021eb6883adc3b384f50a8d866 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 17:03:50 +0000 Subject: [PATCH 2/4] fix(cli): Keep response validation working with @sentry/api 1.52.0 1.52.0 types several response fields that used to be open records. Three of them affect the CLI: - Trace meta: `transactionChildCountMap[].transaction.event_id` is now a required string, but Sentry returns null for spans that belong to no transaction (MCP-SERVER-EFR, #494). `replay view` would drop the trace counts for those traces. Accept null there. - Sentry App components: `schema` is now the UI element union Sentry checks apps against when they are saved. One installed app whose stored schema doesn't match it would fail the whole listing and block linking through every other app. Leave `schema` unchecked and keep validating only the selected app's link form. The test fixtures now use real UUIDs, which the new schema checks. - Issue releases: `firstRelease`/`lastRelease` can be a release with only `version`, so narrow before reading `shortVersion`. The output-schema field extractor also learns `strict_object`, which 1.52.0 now emits for objects with `additionalProperties: false`. --- .../cli/script/lib/output-schema-fields.ts | 1 + packages/cli/src/lib/api/issue-app-links.ts | 19 ++++++- packages/cli/src/lib/formatters/human.ts | 16 +++++- packages/cli/src/types/sentry.ts | 23 ++++++++- .../cli/test/lib/api/issue-app-links.test.ts | 45 +++++++++++++--- packages/cli/test/lib/api/traces.test.ts | 51 ++++++++++++++++++- .../test/lib/formatters/human.details.test.ts | 10 ++++ .../test/script/output-schema-fields.test.ts | 18 +++++++ 8 files changed, 171 insertions(+), 12 deletions(-) diff --git a/packages/cli/script/lib/output-schema-fields.ts b/packages/cli/script/lib/output-schema-fields.ts index c132f4761..4c0d920aa 100644 --- a/packages/cli/script/lib/output-schema-fields.ts +++ b/packages/cli/script/lib/output-schema-fields.ts @@ -53,6 +53,7 @@ const VALIBOT_TYPE_MAP: Record = { boolean: "boolean", object: "object", loose_object: "object", + strict_object: "object", array: "array", record: "object", null: "null", diff --git a/packages/cli/src/lib/api/issue-app-links.ts b/packages/cli/src/lib/api/issue-app-links.ts index 4e209ee18..6a62974eb 100644 --- a/packages/cli/src/lib/api/issue-app-links.ts +++ b/packages/cli/src/lib/api/issue-app-links.ts @@ -22,6 +22,7 @@ import { array, boolean, type InferOutput, + looseObject, nullish, number, object, @@ -31,6 +32,7 @@ import { string, tuple, union, + unknown, } from "valibot"; import { ApiError, ValidationError } from "../errors.js"; import { resolveOrgRegion } from "../region.js"; @@ -73,6 +75,21 @@ type Choice = InferOutput; type Field = InferOutput; type LinkForm = InferOutput; +/** + * Sentry App components, with each app's `schema` left unchecked. + * + * `@sentry/api` types `schema` as the UI element union Sentry checks apps + * against when they are saved. One installed app whose stored schema doesn't + * match it would fail the whole page and hide every other app's form, so only + * the selected app's link form is checked, against {@link LinkFormSchema}. + */ +const ComponentsSchema = array( + object({ + ...vListOrganizationSentryAppComponentsResponse.item.entries, + schema: looseObject({ link: optional(unknown()) }), + }), +); + /** Inputs for a read-only preflight of the app's existing-issue link action. */ export type ResolveAppIssueLinkOptions = { /** Organization containing the Sentry issue and app installation. */ @@ -296,7 +313,7 @@ async function getLinkForm( }); return unwrapPaginatedResult(result, "Failed to list app components"); }, - vListOrganizationSentryAppComponentsResponse, + ComponentsSchema, "listing Sentry App components", ); const matches = components.filter( diff --git a/packages/cli/src/lib/formatters/human.ts b/packages/cli/src/lib/formatters/human.ts index 13f27bd0c..a7ea432b6 100644 --- a/packages/cli/src/lib/formatters/human.ts +++ b/packages/cli/src/lib/formatters/human.ts @@ -797,6 +797,18 @@ function formatPriorityLabel(priority?: string | null): string { } } +/** + * The short version of an issue's first or last release. The API also + * documents a release with only `version`, which has no `shortVersion`. + */ +function releaseShortVersion( + release: SentryIssue["firstRelease"], +): string | undefined { + return release && "shortVersion" in release + ? release.shortVersion + : undefined; +} + /** * Format detailed issue information as rendered markdown. * @@ -850,8 +862,8 @@ export function formatIssueDetails(issue: SentryIssue): string { ]); } - const firstReleaseVersion = issue.firstRelease?.shortVersion; - const lastReleaseVersion = issue.lastRelease?.shortVersion; + const firstReleaseVersion = releaseShortVersion(issue.firstRelease); + const lastReleaseVersion = releaseShortVersion(issue.lastRelease); if (firstReleaseVersion || lastReleaseVersion) { const first = text(stringifyUnknown(firstReleaseVersion ?? "")); const last = text(stringifyUnknown(lastReleaseVersion ?? "")); diff --git a/packages/cli/src/types/sentry.ts b/packages/cli/src/types/sentry.ts index 504cf60f5..6c6497a9f 100644 --- a/packages/cli/src/types/sentry.ts +++ b/packages/cli/src/types/sentry.ts @@ -388,8 +388,27 @@ export type ReplayContext = { [key: string]: unknown; }; -/** High-level metadata returned by the organization trace-meta endpoint. */ -export const TraceMetaSchema = vOrganizationTraceMetaResponse; +const sdkTraceMeta = vOrganizationTraceMetaResponse.entries; +const sdkTransactionChildCount = + sdkTraceMeta.transactionChildCountMap.item.entries; + +/** + * High-level metadata returned by the organization trace-meta endpoint. + * + * Built from the `@sentry/api` schema. The spec says `transaction.event_id` is + * a string, but spans that belong to no transaction are counted under null. + */ +export const TraceMetaSchema = object({ + ...sdkTraceMeta, + transactionChildCountMap: array( + object({ + ...sdkTransactionChildCount, + "transaction.event_id": nullable( + sdkTransactionChildCount["transaction.event_id"], + ), + }), + ), +}); export type TraceMeta = InferOutput; diff --git a/packages/cli/test/lib/api/issue-app-links.test.ts b/packages/cli/test/lib/api/issue-app-links.test.ts index ff69ab9ec..df0099b53 100644 --- a/packages/cli/test/lib/api/issue-app-links.test.ts +++ b/packages/cli/test/lib/api/issue-app-links.test.ts @@ -34,10 +34,14 @@ const LINK: AppIssueLink = { webUrl: URL, }; const INSTALLATION = { - uuid: "install-uuid", + uuid: "4f1c2b7e-9a3d-4c8e-b6f2-0d5e8a7c1b39", status: "installed", organization: { slug: ORG }, - app: { uuid: "app-uuid", slug: "linear", sentryAppId: 12 }, + app: { + uuid: "a7d3e9c1-5b2f-4e6a-8c4d-2f1b9e0a6c57", + slug: "linear", + sentryAppId: 12, + }, }; const FORM = { uri: "/hooks/sentry/issues/link", @@ -46,10 +50,15 @@ const FORM = { ], }; const COMPONENT = { - uuid: "component-uuid", + uuid: "c2e8f4a6-1d7b-4a3c-9e5f-7b0d2c8a4e16", type: "issue-link", error: "", - sentryApp: { uuid: "app-uuid", slug: "linear", name: "Linear", avatars: [] }, + sentryApp: { + uuid: "a7d3e9c1-5b2f-4e6a-8c4d-2f1b9e0a6c57", + slug: "linear", + name: "Linear", + avatars: [], + }, installationUuid: INSTALLATION.uuid, schema: { link: FORM }, }; @@ -59,6 +68,7 @@ let calls: Request[]; let links: AppIssueLink[]; let choices: [string, string][]; let form: unknown; +let otherComponents: unknown[]; let installation: typeof INSTALLATION; let actionStatus: number; let actionLink: AppIssueLink; @@ -76,6 +86,7 @@ beforeEach(async () => { links = []; choices = [["linear-uuid", "ENG-42: Fix the crash"]]; form = FORM; + otherComponents = []; installation = INSTALLATION; actionStatus = 201; actionLink = LINK; @@ -90,7 +101,10 @@ beforeEach(async () => { return json([installation]); } if (path.endsWith("/sentry-app-components/")) { - return json([{ ...COMPONENT, schema: { link: form } }]); + return json([ + { ...COMPONENT, schema: { link: form } }, + ...otherComponents, + ]); } if (path.endsWith("/external-requests/")) { return json({ choices }); @@ -128,7 +142,7 @@ describe("app issue-link action", () => { request.url.includes("external-requests"), ); expect(search?.url).toContain( - "https://sentry.io/api/0/sentry-app-installations/install-uuid/", + `https://sentry.io/api/0/sentry-app-installations/${INSTALLATION.uuid}/`, ); expect(search?.url).toContain("query=ENG-42"); expect(search?.url).toContain("projectId=77"); @@ -401,6 +415,25 @@ describe("app issue-link action", () => { expect(writes()).toHaveLength(0); }); + test("ignores another app's component schema that the API spec doesn't describe", async () => { + otherComponents = [ + { + ...COMPONENT, + uuid: "5e0b7d2c-8f4a-4c1e-a3b6-9d2f7e1c0a48", + sentryApp: { + uuid: "6b1f8e3d-2c5a-4d7b-9e0f-3a8c1d6b2e74", + slug: "legacy-tracker", + name: "Legacy Tracker", + avatars: [], + }, + // No `create` form, and a link URI without the leading slash. + schema: { type: "issue-link", link: { uri: "link" } }, + }, + ]; + const prepared = await resolveAppIssueLink(OPTIONS); + expect(prepared.fields).toEqual({ issueId: "linear-uuid" }); + }); + test("does not allow user fields to override the action URI or target", async () => { await expect( resolveAppIssueLink({ ...OPTIONS, fields: { uri: "/create" } }), diff --git a/packages/cli/test/lib/api/traces.test.ts b/packages/cli/test/lib/api/traces.test.ts index 5636735bb..89b0c7463 100644 --- a/packages/cli/test/lib/api/traces.test.ts +++ b/packages/cli/test/lib/api/traces.test.ts @@ -1,5 +1,6 @@ /** - * Tests for the traces API helpers (getDetailedTrace, listTransactions, listSpans). + * Tests for the traces API helpers (getDetailedTrace, getTraceMeta, + * listTransactions, listSpans). * * Verifies URL construction, query parameter encoding, schema validation, * pagination cursor extraction, auto-pagination, and the 14d→90d empty-trace retry. @@ -10,6 +11,7 @@ import { fetchMultiSpanDetails, getDetailedTrace, getSpanDetails, + getTraceMeta, listSpans, listTransactions, } from "../../../src/lib/api/traces.js"; @@ -875,3 +877,50 @@ describe("getDetailedTrace", () => { } }); }); + +// --------------------------------------------------------------------------- +// getTraceMeta +// --------------------------------------------------------------------------- + +describe("getTraceMeta", () => { + useTestConfigDir("traces-meta-test-"); + + let originalFetch: typeof globalThis.fetch; + + beforeEach(() => { + originalFetch = globalThis.fetch; + }); + + afterEach(() => { + globalThis.fetch = originalFetch; + }); + + test("accepts spans counted under a null transaction.event_id", async () => { + const transactionChildCountMap = [ + { + "transaction.event_id": "0daf40dc453a429c8c57e4c215c4e82c", + "count()": 10, + }, + { "transaction.event_id": null, "count()": 15 }, + ]; + globalThis.fetch = mockFetch( + async () => + new Response( + JSON.stringify({ + errorsCount: 2, + logsCount: 3, + metricsCount: 0, + performanceIssuesCount: 1, + spansCount: 25, + transactionChildCountMap, + spansCountMap: { "http.client": 25 }, + }), + { status: 200, headers: { "Content-Type": "application/json" } }, + ), + ); + + const meta = await getTraceMeta("my-org", "abc123def456"); + + expect(meta.transactionChildCountMap).toEqual(transactionChildCountMap); + }); +}); diff --git a/packages/cli/test/lib/formatters/human.details.test.ts b/packages/cli/test/lib/formatters/human.details.test.ts index ad61d0d05..382dc2fc9 100644 --- a/packages/cli/test/lib/formatters/human.details.test.ts +++ b/packages/cli/test/lib/formatters/human.details.test.ts @@ -333,6 +333,16 @@ describe("formatIssueDetails", () => { expect(result).toContain("→"); }); + test("omits the release row for releases with only a version", () => { + const issue = createMockIssue({ + firstRelease: { version: "backend@1.0.0+abc123" }, + lastRelease: { version: "backend@1.0.0+abc123" }, + }); + + const result = stripAnsi(formatIssueDetails(issue)); + expect(result).not.toContain("Release"); + }); + test("includes assignee name", () => { const issue = createMockIssue({ assignedTo: { name: "John Doe" }, diff --git a/packages/cli/test/script/output-schema-fields.test.ts b/packages/cli/test/script/output-schema-fields.test.ts index 87a76b20e..6727ec7b9 100644 --- a/packages/cli/test/script/output-schema-fields.test.ts +++ b/packages/cli/test/script/output-schema-fields.test.ts @@ -5,7 +5,11 @@ import { object, optional, pipe, + record, + strictObject, string, + union, + unknown, } from "valibot"; import { describe, expect, test } from "vitest"; import { @@ -34,6 +38,20 @@ describe("extractSchemaFields", () => { }); }); + test("reports strict objects as objects", () => { + // `@sentry/api` 1.52.0 emits `strictObject` for objects whose spec sets + // `additionalProperties: false`, often as one member of a union. + const [field] = extractSchemaFields( + object({ + config: union([ + record(string(), unknown()), + strictObject({ frequency: optional(string()) }), + ]), + }), + ); + expect(field?.type).toBe("object"); + }); + test("prefers a description the CLI adds over the API's", () => { const [field] = extractSchemaFields( object({ formatted: pipe(apiField, description("CLI description")) }), From d980d3a95a0b4935d83d3432fd9a804b340af637 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 17:04:03 +0000 Subject: [PATCH 3/4] docs(cli): Regenerate skill references for @sentry/api 1.52.0 The field tables pick up the new API descriptions for event `contexts` and release `status` and `adoptionStages`. Monitor `config` loses its description because 1.52.0 turns it into a union and the generated valibot schema doesn't keep the description the spec puts on that union. Event `occurrence` now shows `unknown`, because its spec union has an untyped member. --- .../skills/sentry-cli/references/alert.md | 2 +- .../skills/sentry-cli/references/event.md | 4 +-- .../skills/sentry-cli/references/release.md | 28 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md index 0791b2921..f0ebf6ccb 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md @@ -402,7 +402,7 @@ Edit a metric alert rule | `dateUpdated` | string | When the monitor was last updated (ISO 8601) | | `dataSources` | array \| null | Data sources the monitor evaluates, such as a query subscription | | `conditionGroup` | object \| null | Conditions that decide the monitor's status | -| `config` | object | Configuration of the monitor, which depends on its type | +| `config` | object | | | `enabled` | boolean | Whether the monitor is enabled | | `org` | string | Organization slug | | `status` | string | Rule status (active, disabled) | diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md index 4cae2fe8c..3afc37c96 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md @@ -45,11 +45,11 @@ View details of one or more events | `packages` | object | Modules loaded when the event occurred, keyed by module name with their versions | | `type` | string | Event type, such as error, default or transaction | | `metadata` | object | Event metadata | -| `occurrence` | object \| null | | +| `occurrence` | object \| unknown \| null | | | `_meta` | object | Metadata about changes Sentry made to the event's fields, such as data scrubbing or trimming | | `user` | object \| null | User context of the event | | `tags` | array | Tags attached to the event | -| `contexts` | object \| null | Contexts of the event, such as device, os, browser and runtime | +| `contexts` | object \| null | Contexts of the event, such as device, os, browser and runtime, keyed by alias | | `sdk` | object \| null | SDK that sent the event | | `context` | object \| null | Additional data sent with the event in its extra field | | `errors` | array | Errors Sentry found while processing the event | diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/release.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/release.md index cc144b70d..17a449433 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/release.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/release.md @@ -38,7 +38,7 @@ List releases with adoption and health metrics | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -53,7 +53,7 @@ List releases with adoption and health metrics | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | | `orgSlug` | string | Organization slug | | `targetProject` | string | Project slug, when listing several | @@ -106,7 +106,7 @@ View release details with health metrics | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -121,7 +121,7 @@ View release details with health metrics | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | **Examples:** @@ -164,7 +164,7 @@ Create a release | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -179,7 +179,7 @@ Create a release | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release (only slug with --dry-run) | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | | `dryRun` | boolean | True when --dry-run made no change | **Examples:** @@ -236,7 +236,7 @@ Finalize a release | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -251,7 +251,7 @@ Finalize a release | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | | `dryRun` | boolean | True when --dry-run made no change | | `org` | string | Organization slug (--dry-run) | | `released` | string | Release date to set (--dry-run) | @@ -332,7 +332,7 @@ Archive a release | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -347,7 +347,7 @@ Archive a release | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | | `dryRun` | boolean | True when --dry-run made no change | | `org` | string | Organization slug (--dry-run) | @@ -385,7 +385,7 @@ Restore an archived release | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -400,7 +400,7 @@ Restore an archived release | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | | `dryRun` | boolean | True when --dry-run made no change | | `org` | string | Organization slug (--dry-run) | @@ -529,7 +529,7 @@ Set commits for a release | `version` | string | Release version | | `shortVersion` | string | Shortened release version | | `versionInfo` | object \| null | Parsed version information | -| `status` | string | Release status (open or archived) | +| `status` | string | Release status | | `ref` | string \| null | Version control reference, such as a commit SHA or tag | | `url` | string \| null | Release URL | | `dateCreated` | string \| null | When the release was created (ISO 8601) | @@ -544,7 +544,7 @@ Set commits for a release | `authors` | array | Authors of the release's commits | | `owner` | object \| null | Release owner | | `projects` | array | Projects in the release | -| `adoptionStages` | object \| null | Adoption stage of the release in each project | +| `adoptionStages` | object \| null | Adoption stage of the release in each project, keyed by project slug | **Examples:** From d16889643eb64cfff9ff1131d7494b0e108637a9 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 17:52:58 +0000 Subject: [PATCH 4/4] fix(cli): Align the app link-form comment and regenerate skill references After merging #2113, the link-form comment in issue-app-links.ts still said the component schema is typed per component type. The component listing on this branch leaves each app's schema unchecked, so say that. The regenerated alert reference shows `config` as `object` again. Main's copy shows `unknown` because #2113 ran the extractor before it handled `strictObject`. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com> --- .../plugins/sentry-cli/skills/sentry-cli/references/alert.md | 4 ++-- packages/cli/src/lib/api/issue-app-links.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md index 3ef5f9452..f0ebf6ccb 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/alert.md @@ -197,7 +197,7 @@ Edit an issue alert rule | `triggers` | object \| null | Conditions on which the alert triggers | | `actionFilters` | array \| null | Filters to run before actions fire, each with the actions to fire | | `environment` | string \| null | Name of the environment the alert is limited to. Null for all environments | -| `config` | unknown | Configuration of the alert, such as frequency in minutes | +| `config` | object | Configuration of the alert, such as frequency in minutes | | `detectorIds` | array \| null | IDs of the monitors connected to the alert | | `enabled` | boolean | Whether the alert is enabled | | `lastTriggered` | string \| null | When the alert last fired (ISO 8601) | @@ -402,7 +402,7 @@ Edit a metric alert rule | `dateUpdated` | string | When the monitor was last updated (ISO 8601) | | `dataSources` | array \| null | Data sources the monitor evaluates, such as a query subscription | | `conditionGroup` | object \| null | Conditions that decide the monitor's status | -| `config` | object \| unknown | | +| `config` | object | | | `enabled` | boolean | Whether the monitor is enabled | | `org` | string | Organization slug | | `status` | string | Rule status (active, disabled) | diff --git a/packages/cli/src/lib/api/issue-app-links.ts b/packages/cli/src/lib/api/issue-app-links.ts index ed7fdbd45..924cf5173 100644 --- a/packages/cli/src/lib/api/issue-app-links.ts +++ b/packages/cli/src/lib/api/issue-app-links.ts @@ -335,8 +335,8 @@ async function getLinkForm( JSON.stringify(component.error), ); } - // The component schema is typed per component type, but its form fields - // are app-defined, so validate the link form here. + // ComponentsSchema leaves each app's schema unchecked, so validate only + // this app's link form here. const { schema } = component; const form = safeParse( LinkFormSchema,