Dashboard › cli › Distillation
7fbe62a2-7772-4499-9070-57c75a4023bf["lore_tm_v1_RQrFdLAKuQGU1srKwjq62CBZ1UjLFUtgI1v56POJitM"]
Date: Sep 8, 2026
package.json for the latest scripts; commands run from packages/cli or via pnpm --filter sentry run <script> from the repository root.devDependencies, never dependencies, because esbuild bundles everything at build time and CI enforces the rule with pnpm run check:deps.pnpm add -D <package> using the -D flag.per_page value larger than API_MAX_PER_PAGE to an API. API_MAX_PER_PAGE is 100; the server silently caps larger values, causing commands to return fewer items than requested.--limit > API_MAX_PER_PAGE: calculate perPage = Math.min(flags.limit, API_MAX_PER_PAGE) and fetch pages until results.length >= flags.limit, no nextCursor remains, or MAX_PAGINATION_PAGES is reached. Reference pattern: listIssuesAllPages; reference templates: trace/list.ts, span/list.ts, and dashboard/list.ts.packages/cli/src/commands/agent-conversation/list.ts found listCommand currently calls listConversations(org, { query: flags.query, limit: flags.limit, cursor, ...timeParams }) once at lines 170β182; it does not visibly cap the request at API_MAX_PER_PAGE or loop across pages when the requested limit exceeds 100.packages/cli/src/commands/agent-conversation/list.ts defines COMMAND_NAME = "agent-conversation list", PAGINATION_KEY = "agent-conversation-list", and DEFAULT_PERIOD = "7d"; parseLimit() validates against LIST_MIN_LIMIT and LIST_MAX_LIMIT.packages/cli/src/commands/agent-conversation/list.ts defines ListFlags with limit, optional query, period, json, optional cursor, fresh, and optional fields; ConversationListResult contains conversations, hasMore, optional hasPrev, optional nextCursor, and org.formatListHuman() is: "No conversations on this page." when the current page is empty but hasMore; "No agent conversations found." when empty with no further page; otherwise Agent conversations in ${org}:\n\n${formatConversationTable(conversations)}.jsonTransform() optionally applies filterFields() to each conversation and emits an envelope with data, hasMore, Boolean hasPrev, and nextCursor only when present.listCommand uses buildListCommand("agent-conversation", ...), has docs.customUsage: ["[<org>]"], and documents examples for auto-detected organization, explicit my-org, --limit 50, --period 24h, and -q "has:errors".org is optional. Flags include parsed limit with range ${LIST_MIN_LIMIT}-${LIST_MAX_LIMIT} and default LIST_DEFAULT_LIMIT, optional parsed query, and LIST_PERIOD_FLAG; aliases are ...PERIOD_ALIASES, n: "limit", and q: "query".resolveOrg({ org: target, cwd }); missing context throws new ContextError("Organization", "sentry agent-conversation list <org>")."agent-conversation", the resolved organization, query q, and serialized period. It uses resolveCursor(), advancePaginationState(), hasPreviousPage(), and paginationHint().sentry agent-conversation list ${org} -c next${flagSuffix} and sentry agent-conversation list ${org} -c prev${flagSuffix}.-c next and -c prev; hints must show previous navigation when hasPreviousPage() is true, next navigation when hasMore is true, and JSON envelopes must include nextCursor and hasPrev.paginationHint() from src/lib/list-command.ts with prebuilt prevHint and nextHint; list commands must not manually assemble navParts.buildOrgListCommand for simple organization-scoped lists, 2. dispatchOrgScopedList with overrides for complex modes, 3. buildListCommand with manual pagination for standalone commands such as trace/span/dashboard lists.node:* standard-library APIs and never reintroduce Bun.* globals, bun:test, or bun CLI commands.buildCommand from ../../lib/command.js, never directly from @stricli/core; the wrapper adds telemetry, --json/--fields, and rendering. Commands must use async *func(), yield new CommandOutput(data), avoid stdout.write(), and avoid custom if (flags.json) output branches.buildRouteMap from ../../lib/route-map.js, never directly from @stricli/core; standard aliases are automatically injected as list β ls, view β show, delete β remove/rm, and create β new.buildDeleteCommand() from src/lib/mutate-command.ts; it injects --yes, --force, and --dry-run with aliases -y, -f, and -n, and guards non-interactive destructive execution unless confirmation is bypassed.validateHexId(value, label) for 32-character hexadecimal IDs, validateSpanId(value) for 16-character span IDs, and validateTraceId(value) as the trace-ID wrapper; validators strip UUID dashes where applicable, normalize to lowercase, and throw ValidationError."date", not "time", and to export sort types from the API layer.pnpm run generate:docs; hand-written command fragments belong under docs/src/fragments/commands/, committed skill files under plugins/sentry-cli/skills/sentry-cli/, and positional placeholders must be descriptive.catch blocks to rethrow, log via log.debug()/log.warn(), or log before returning a fallback; silent and return-only catches are prohibited by lint-rules/no-silent-catch.grit, and obsolete biome-ignore suppressions must be removed because suppressions/unused fails lint.useTestConfigDir() from test/helpers.ts; tests must never delete process.env.SENTRY_CONFIG_DIR, capture it at module scope, or manually manage it with beforeEach/afterEach.main before review, 3. separate correctness fixes from subjective UX changes, and 4. reuse shared helpers such as autoPaginate() and safeParseJson() rather than hand-rolling fixes.