Dashboard › cli › Distillation
e9efcffe-badd-4186-a136-24467ed411fa["lore_tm_v1_J1GalLhggTaDj-WxmoZUZ1rc2bU4Jazk0Lco37FXG7M","lore_tm_v1_ShUApA1qFfF2j8goC7KrBOTsACfAvH55tZ1T1nJdx0w","lore_tm_v1_mpEkOeT2Q1zGS2ZpqGiUJngdZ7WEv9hf0fkXqjsk5b8","lore_tm_v1_0c_jjcei2hotQbygREwADRpWGNaMy_4qm7PWN8U9upE","lore_tm_v1_B7nVVxZ7nSk1Kur-1ej6MwCMZgK8KxaubxqbZEA7wDc","lore_tm_v1_1l93vylpU1-u7j8fmin21JoZozC9GVbSzIPlzgAaM_c","lore_tm_v1_JXzKylWNJ_5vKFKvuORn0y7HWVZXMnShdtVVxkOTXBw","lore_tm_v1_KQxWDXDkNy6T7BhmBgvPQUtrSvyyrdc39uqNBsDKPo0","lore_tm_v1_YKIuhEwnJGO2mgTUdT4T2yGljb0nfRpThqPk9rDYjKs","lore_tm_v1_QGn9uvTl2MmCxULTUxPDjuJshr7oXollLbUjb0kh0Jk","lore_tm_v1_u-hBGDGj31DRzhR0S6ueo_b8s5AmtbqRhxzhjDQF5og","lore_tm_v1_HVD4CU1CHig-YddTtWcFYbhGtNt4q7TXBMUw5tSJwEM","lore_tm_v1_7Gt2M7GL-pc8kQ4AqVqqVgu_QyRytOXjfrK2fsgb2mA","lore_tm_v1_pLFiDUPqkaY_86UGi5SioUEAky77h8JlrtNXtXqUFTs","lore_tm_v1_Egh6BC3CVWmkS7C9YXFuVGB30QVdWEHwuuhhb-91Cm8","lore_tm_v1_k36Yl2TTz6A9wwxrICtvU-iHdxkM58kI7K0TJrijpr8"]
packages/cli/src/lib/telemetry.ts:855-889 defines setFlagContext(flags: Record<string, unknown>): void: skips undefined, null, false, empty strings, and empty arrays; converts camelCase keys to kebab-case with key.replace(/([A-Z])/g, "-$1").toLowerCase(); emits non-sensitive values through Sentry.setTag(\flag.${kebabKey}`, flagValueToTag(value))`.setFlagContext() checks SENSITIVE_FLAGS after kebab-case conversion and reports sensitive values only as [REDACTED].setArgsContext(args: readonly unknown[]) returns without telemetry for an empty argument array; otherwise calls Sentry.setContext("args", { values, count }), retaining strings directly and serializing non-strings with JSON.stringify().recordCacheHit(cacheName, hit) emits Sentry.metrics.distribution("cache.hit_rate", hit ? 100 : 0, { attributes: { cache_name: cacheName } }); encoding misses as 0 and hits as 100 allows avg(value,cache.hit_rate,distribution,none) to directly represent a percentage because Sentry dashboard widgets do not support division.WizardPromptKind is exactly "select" | "multiselect" | "confirm" | "welcome", and WizardPromptTelemetry exposes setActiveStep(stepId, active) plus asynchronous tracePrompt<T>(kind, prompt).createWizardPromptTelemetry() tracks active wizard step IDs and accumulates human-input wait time separately from top-level sentry.init duration; prompt spans use names wizard.prompt.${kind} and operation "ui.prompt".packages/cli/src/lib/agent-skills.ts has 196 lines and implements build-time-embedded Sentry CLI skill installation using SKILL_FILES from ../generated/skill-content.js; no network fetch is needed.AgentSkillLocation contains path: string, created: boolean, and referenceCount: number.detectClaudeCode(homeDir) detects Claude Code solely through existence of <homeDir>/.claude.getSkillInstallPath(homeDir, rootDir) accepts only ".agents" | ".claude", defaults to ".claude", and returns <homeDir>/<rootDir>/skills/sentry-cli/SKILL.md.atomicWriteFile() must ensure a concurrent reader never observes a truncated or partially-written file. It writes in the destination directory and then uses rename() for an atomic POSIX replacement, avoiding the empty-frontmatter race caused by in-place writeFile() truncation.atomicWriteFile() creates temporary files as .<basename>.<pid>.<rand>.tmp, for example .SKILL.md.1234.ab12.tmp; the temporary filename never matches the SKILL.md or *.md globs used by agents.atomicWriteFile() requires dirname(destPath) to exist. On write/rename failure it best-effort removes the temporary file with rm(tempPath, { force: true }); cleanup failures are captured at level: "debug" with tag { "setup.step": "agent-skills-cleanup" }, and the original error is rethrown.writeSkillFiles(skillPath) iterates every [relativePath, content] in SKILL_FILES, recursively creates missing descendant directories with mode 0o755, atomically writes each file, and increments referenceCount for paths beginning with references/.writeSkillFiles() records whether SKILL.md existed before installation and returns { path: skillPath, created: !alreadyExists, referenceCount }; any filesystem failure is captured at level: "warning" with tag { "setup.step": "agent-skills" } and returns null.installAgentSkills(homeDir) never creates top-level agent roots; existence of <homeDir>/.agents or <homeDir>/.claude is the detection signal that a compatible agent is already installed.installAgentSkills() checks targets in this order: 1. .agents, 2. .claude; skips undetected roots and roots failing accessSync(parentDir, constants.W_OK) because some sandboxes terminate processes on write attempts before JavaScript error handling can run.installAgentSkills() returns null if no installation succeeds; otherwise it returns the first freshly created location, falling back to results[0]. This makes setup output point to a newly added installation when any target was freshly created.packages/cli/src/lib/list-command.ts defines shared LIST_CURSOR_FLAG as an optional parsed flag accepting next, prev, first, last, or a raw opaque cursor; its brief text is Navigate pages: "next", "prev", "first" (or raw cursor string).paginationHint({ hasPrev, hasMore, prevHint, nextHint }) appends Prev: ${prevHint} when hasPrev, appends Next: ${nextHint} when hasMore, joins both with " | ", and returns "" when neither direction exists.paginationHint() example with sentry trace list my-org/my-proj -c prev and sentry trace list my-org/my-proj -c next yields Prev: sentry trace list my-org/my-proj -c prev | Next: sentry trace list my-org/my-proj -c next.appendQueryHint(parts, query) appends -q "${query}" only for a truthy query and always quotes it to support spaces.appendSortHint(parts, sort, defaultSort?) appends --sort "${sort}" only when sort is truthy and differs from defaultSort; it is stringly typed to support raw API sorts such as "-count()" and command-specific enums.packages/cli/src/lib/formatters/output.ts defines formatFooter(text) as `\n${plainSafeMuted(text)}\n` and writeFooter(stdout, text) as stdout.write(formatFooter(text)); footer text is muted on TTY, plain when piped, and surrounded by newlines.plugins/sentry-cli/skills/sentry-cli/references/agent-conversation.md frontmatter has name: sentry-cli-agent-conversation, version: 0.45.0-dev.0, description List and view agent conversations, bins: ["sentry"], and auth: true.sentry agent-conversation list [<org>] reference documents flags in this order: 1. -n, --limit <value> range 1-1000, default "25"; 2. -q, --query <value>; 3. -t, --period <value> with examples "7d", "2026-08-01..2026-09-01", and ">=2026-08-01", default "7d"; 4. -f, --fresh; 5. -c, --cursor <value>.conversationId string, 2. title string or null, 3. flow array, 4. errors number, 5. llmCalls number, 6. toolCalls number, 7. totalTokens number, 8. totalCost number, 9. startTimestamp number, 10. endTimestamp number, 11. traceCount number, 12. traceIds array, 13. firstInput string or null, 14. lastOutput string or null, 15. user object or null, 16. toolNames array, 17. toolErrors number.sentry agent-conversation list; 2. sentry agent-conversation list my-org; 3. sentry agent-conversation list --limit 50 --period 24h; 4. sentry agent-conversation list -q "has:errors"; 5. sentry agent-conversation list my-org -c next.--json, --fields, --help, --log-level, and --verbose.plugins/sentry-cli/skills/sentry-cli/SKILL.md includes an Agent-conversation section with sentry agent-conversation list [<org>], sentry agent-conversation view [<org>/]<conversation-id>, and link references/agent-conversation.md.packages/cli/src/commands/agent-conversation/index.ts exports conversationRoute = buildRouteMap(...) with routes ordered list: listCommand, then view: viewCommand; defaultCommand is "list".List and view agent conversations, full description List and view agent conversations from Sentry Explore. followed by command descriptions for list and view, and hideRoute: {}.packages/cli/src/lib/formatters/json.ts defines parseFieldsList(input) by splitting on commas, trimming whitespace, removing empty entries, and deduplicating through Set; examples are "id, title , status" → ["id", "title", "status"] and "id,,title" → ["id", "title"].formatJson<T>(data) returns JSON.stringify(data, null, 2).writeJson(stream, data, fields?) applies filterFields(data, fields) only when fields is nonempty and writes pretty JSON followed by \n.writeJsonList() wraps list output in { data, hasMore, nextCursor? }; --fields filtering applies to each array element inside data, while metadata keys such as hasMore and nextCursor remain preserved.emitJsonObject(stdout, obj) hands the object directly to stdout.captureObject(obj) when zero-copy library capture is available; otherwise it writes ${formatJson(obj)}\n.renderCommandOutput(stdout, data, config, renderer, ctx) sends Uint8Array directly to stdout.write(data) with no JSON formatting, newline, or string coercion, preserving byte-for-byte output for sentry api attachment downloads and other binary content types.renderCommandOutput() is: 1. call config.jsonTransform(data, ctx.fields) when present and emit nothing if it returns undefined; 2. otherwise apply applyJsonExclude(data, config.jsonExclude); 3. apply filterFields() only when ctx.fields is nonempty; 4. emit the final object.renderer.render(data) and, when text is truthy, writes ${ctx.clearPrefix ?? ""}${text}\n; hints are not rendered by renderCommandOutput() and are instead emitted once after generator completion via finalize() or writeFooter().rejectAtSelector(value, label) rejects every @-prefixed org/project value. Recognized issue selectors produce an actionable error directing users to sentry issue view ${value}; unknown values produce an invalid-slug error stating slugs contain only letters, numbers, hyphens, and underscores.@ is never valid in Sentry slugs. @latest and @most_frequent are issue selectors accepted by parseIssueArg() for issue view, explain, and plan, not project or organization slugs.parseSlashOrgProject(input) behavior: "/" throws because a project slug is required; "/cli" produces a cross-organization project search; "sentry/" produces { type: "org-all", org: "sentry" }; "sentry/cli" produces an explicit org/project result.project-search, preserving originalSlug; this applies to leading-slash, explicit org/project, and bare-input forms and avoids hard slug-validation failures such as CLI-1RA.parseOrgProjectArg(arg) returns { type: "auto-detect" } for undefined, empty, or whitespace-only input; recognizes Sentry URLs through parseSentryUrl(), applies their base URL via applySentryUrlContext(), parses slash-containing input with parseSlashOrgProject(), and otherwise performs a cross-organization project search.numeric, explicit, explicit-org-suffix, explicit-org-numeric, project-search, and suffix-only.@latest resolves to the issue with the most recent event by lastSeen; @most_frequent resolves to the issue with the highest event frequency; selectors can be combined with an explicit organization, for example sentry/@latest.normalizeSlug(slug) is intentionally a no-op returning { slug, normalized: false } after underscore normalization removal in #771 and display-name matching changes in #772; it remains as a stable call site for future normalization.looksLikeDisplayName(input) detects display names using input.includes(" "), after which parsing uses display-name search rather than slug validation or direct API lookup.ISSUE_SHORT_ID_PATTERN is /^[A-Z][A-Z0-9]*(-[A-Z][A-Z0-9]*)*-[A-Z0-9]+$/; documented matches are CAM-82X, CLI-G, and SPOTLIGHT-ELECTRON-4Y, while my-project, a9b4ad2c, and org/project do not match.HAS_UPPERCASE_ASCII_RE = /[A-Z]/, HAS_DIGIT_RE = /\d/, HAS_LETTER_ASCII_RE = /[a-zA-Z]/, TITLE_CASE_WORD_RE = /^[A-Z][a-z]+$/, TWO_SEGMENT_PARTS = 2, and ISSUE_SHORT_ID_MULTI_SEGMENT_PARTS = 3.packages/cli/src/lib/region.ts:46 exporting resolveOrgRegion(orgSlug: string): Promise<string> and packages/cli/src/lib/region.ts:65 defining resolveOrgRegionUncached(orgSlug: string): Promise<string>.