Dashboard › cli › Distillation
62f570c2-a449-410e-bc1d-9ae2bc59cdc4["lore_tm_v1_CBw_NGdZh8Id_WxS6wcgLPl6w7XhbXIkbhEAEJqunZc"]
π΄ (20:32) User provided Sentry CLI project context: Node.js + pnpm + Stricli CLI in packages/cli; documentation site in apps/cli-docs; goals include zero-config DSN-based context detection, Seer AI debugging, gh-style UX, agent-friendly JSON output, native Node SEA binaries via fossilize, and SQLite API-response caching.
π΄ (20:32) User stated agents must read .cursor/rules/ultracite.mdc before working in the codebase.
π΄ (20:32) User stated the project runs on Node.js and was migrated from Bun; use node:* standard-library APIs and never reintroduce Bun.*, bun:test, or bun CLI commands.
π΄ (20:32) User stated Node.js API conventions: readFile/writeFile from node:fs/promises; existsSync and permission-aware mkdirSync(dir, { recursive: true, mode: 0o700 }) from node:fs; spawn()/execFile() from node:child_process; setTimeout from node:timers/promises; the which helper in src/lib/which.ts; scanner utilities in src/lib/scan/; and JSON.parse(await readFile(path, "utf-8")) for JSON files.
π΄ (20:32) User stated shell execution should prefer execFileSync with array arguments over string-based execSync when values are user-controlled, to prevent shell injection.
π΄ (20:32) User stated that when @sentry/api supplies API response types, they must be imported directly rather than duplicated as Zod schemas in src/types/sentry.ts.
π΄ (20:32) User stated command files must import buildCommand from ../../lib/command.js, never directly from @stricli/core; the wrapper adds telemetry, --json/--fields injection, and output rendering.
π΄ (20:32) User stated command implementations use async *func() generators, yield new CommandOutput(data), and may return { hint }; output.human and JSON serialization must use the same data object.
π΄ (20:32) User stated commands must not define their own json flag, branch on flags.json, or use stdout.write(); the command wrapper handles output behavior.
π΄ (20:32) User stated command files in src/commands/ should contain only argument parsing, API orchestration/error handling/enrichment, and CommandOutput dispatch; formatting belongs in src/lib/formatters/<domain>.ts, and files over roughly 400 lines should extract formatter helpers.
π΄ (20:32) User stated stderr.write() is banned in command files by a GritQL rule; diagnostics use logger, and data uses CommandOutput.
π΄ (20:32) User stated route groups must import buildRouteMap from ../../lib/route-map.js, never directly from @stricli/core; its standard auto-aliases are listβls, viewβshow, deleteβremove/rm, and createβnew, so these aliases must not be manually duplicated.
π΄ (20:32) User stated standard positional parsing should use parseSlashSeparatedArg and parseOrgProjectArg from src/lib/arg-parsing.ts; required trace IDs and span IDs are positional arguments, not flags.
π΄ (20:32) User stated list-command target syntax supports: <org>/<project> for explicit context, <org>/ for all projects in an organization, <project> for cross-organization project-name search, and omission for DSN/config auto-detection.
π΄ (20:32) User stated context resolution priority is: 1. positional <org>/<project> arguments, which always win; 2. config defaults set via sentry config set; 3. DSN auto-detection through SENTRY_DSN or source code.
π΄ (20:32) User stated all view commands support -w/--web; all view/list commands support JSON output; list commands support --limit.
π΄ (20:32) User stated non-trivial human output must use the markdown pipeline with mdKvTable(), colorTag(), escapeMarkdownCell(), and renderMarkdown(); raw muted()/chalk must not be embedded in output strings.
π΄ (20:32) User stated tree output that cannot use renderMarkdown() should follow plainSafeMuted: isPlainOutput() ? text : muted(text); isPlainOutput() precedence is SENTRY_PLAIN_OUTPUT > NO_COLOR > FORCE_COLOR for TTYs > !isTTY, and implementation lives in src/lib/formatters/plain-detect.ts.
π΄ (20:32) User stated delete commands must use buildDeleteCommand() from src/lib/mutate-command.ts; it injects --yes/-y, --force/-f, and --dry-run/-n, and blocks non-interactive deletion unless --yes or --force is provided, while dry-run bypasses that guard.
π΄ (20:32) User stated delete-command utilities include isConfirmationBypassed(flags), guardNonInteractive(flags), confirmByTyping(expected, message), requireExplicitTarget(parsed, entityType, usage), and bundles DESTRUCTIVE_FLAGS/DESTRUCTIVE_ALIASES; create commands use DRY_RUN_FLAG and DRY_RUN_ALIASES.
π΄ (20:32) User stated API-paginated list commands must use bidirectional cursor-stack infrastructure from src/lib/db/pagination.ts with LIST_CURSOR_FLAG, buildPaginationContextKey, resolveCursor, advancePaginationState, and hasPreviousPage.
π΄ (20:32) User stated cursor navigation supports -c next, -c prev, and -c first; "last" is a silent alias for "next"; the database stores a JSON array of opaque page-start cursors plus an index, and back-then-forward navigation truncates stale entries.
π΄ (20:32) User stated pagination responses should expose both nextCursor and hasPrev; hints show previous navigation when hasPreviousPage() is true and next navigation when a next cursor exists.
π΄ (20:32) User stated pagination hints must be generated with paginationHint() from src/lib/list-command.ts, not manually assembled with navParts; it combines pre-built prevHint and nextHint strings into consistent output.
π΄ (20:32) User stated preferred list abstractions, highest applicable first: 1. buildOrgListCommand for simple org-scoped commands such as team/repo lists; 2. dispatchOrgScopedList with overrides for project/issue lists; 3. buildListCommand with manual pagination for trace/span/dashboard lists.
π΄ (20:32) User stated list commands using dispatchOrgScopedList must call resolveCursor() inside the org-all override, use "Project" as the ContextError resource in handleProjectSearch, and explicitly set orgSlugMatchBehavior to "redirect" or "error" as appropriate.
π΄ (20:32) User stated shared hex validators are validateHexId(value, label) for 32-character IDs, validateSpanId(value) for 16-character span IDs, and validateTraceId(value) in src/lib/trace-id.ts; they remove UUID dashes, normalize lowercase, and throw ValidationError on malformed input.
π΄ (20:32) User stated timestamp sort values must use "date", not "time", and sort types should be exported from the API layer, such as SpanSortValue from api/traces.ts.
π΄ (20:32) User stated generated docs and skills use pnpm run generate:docs, which runs generate:command-docs then generate:skill and is automatically invoked by dev, build, typecheck, and test.
π΄ (20:32) User stated generated command docs are gitignored and derive from CLI metadata plus fragments in docs/src/fragments/commands/; skill files in plugins/sentry-cli/skills/sentry-cli/ are committed and auto-committed by CI when stale; pnpm run check:fragments validates fragment/route consistency.
π΄ (20:32) User stated positional placeholder metadata must be descriptive, such as "org/project/trace-id", never generic values such as "args".
π΄ (20:32) User stated config and API validation uses Zod schemas alongside inferred types in src/types/*.ts; principal files are src/types/sentry.ts, src/types/config.ts, src/types/oauth.ts, and src/types/seer.ts, with re-exports from src/types/index.ts.
π΄ (20:32) User stated SQL upserts should use upsert() or runUpsert() from src/lib/db/utils.ts; upsert() supports excludeFromUpdate, for example preserving created_at.
π΄ (20:32) User stated all CLI errors extend CliError from src/lib/errors.ts, and callers must use EXIT.* constants rather than hardcoded numeric exit codes outside that file.
π΄ (20:32) User stated the error hierarchy and codes: CliError default 1; HostScopeError 13; ApiError 30; AuthError 10β12 by reason; ConfigError 20; OutputError 60; ContextError 22; ResolutionError 23; ValidationError 21; DeviceFlowError 51; SeerError 40β42 by reason; TimeoutError 31; UpgradeError 50; and WizardError 61β64 by workflow step.
π΄ (20:32) User stated error selection rules: omitted required context uses ContextError; a supplied but unfound value uses ResolutionError; malformed input uses ValidationError.
π΄ (20:32) User stated ContextError.command must be a single-line CLI usage example and its constructor rejects newlines; irrelevant defaults should use alternatives: []; plural resources should use " and ", such as "Trace ID and span ID".
π΄ (20:32) User stated pnpm run check:errors scans for multiline ContextError commands, CliError instances with ad-hoc "Try:" strings, and silent catches.
π΄ (20:32) User stated unresolved user-provided names/titles should use fuzzyMatch() from src/lib/fuzzy.ts, returning at most 5 similar candidates rather than listing every entity.
π΄ (20:32) User stated silent production catch blocks are prohibited: each catch must rethrow, call log.debug()/log.warn(), or return a fallback while logging why the error was suppressed; command files should use logger.withTag("command-name").
π΄ (20:32) User stated silent-catch enforcement is currently advisory because of existing backlog, but can be made strict with SENTRY_STRICT_SILENT_CATCH=1; new silent catches must not be introduced.
π΄ (20:32) User stated commands should auto-recover when the user supplies an unambiguously wrong identifier type: 1. detect using looksLikeIssueShortId(), SPAN_ID_RE, HEX_ID_RE, or non-hex checks; 2. resolve to the intended type; 3. warn through log.warn(); 4. return a hint suggesting the correct command.
π΄ (20:32) User stated wrong-entity recovery references include event/view.ts for issue short IDβlatest event, span/view.ts for traceId/spanId splitting, trace/view.ts for issue short IDβissue trace, and hex-id.ts for entity-aware validation hints.
π΄ (20:32) User stated all config operations are asynchronous and must be awaited, including getAuthToken(), isAuthenticated(), and setAuthToken(token, expiresIn).
π΄ (20:32) User stated before adding src/lib/*.ts, check existing modules first; if an existing module covers at least 80% of the need, extend it rather than creating a file. Every new src/lib/**/*.ts file requires module-level JSDoc.
π΄ (20:32) User stated local ESM imports require .js extensions; imports should be grouped external-first then local, and type-only imports must use the type keyword.
π΄ (20:32) User stated Sentry endpoint project filters differ and must never be combined: Discover/Events queryEvents uses project:<slug> via buildProjectQuery(); Replay index listReplays uses projectSlugs; Issue index listIssuesPaginated uses either a project parameter or query syntax depending on mode.
π΄ (20:32) User stated new explore datasets must centralize sorting, querying, fetching, and field validation in resolveDatasetConfig, rather than scattering if (dataset === ...) checks through the command body.
π΄ (20:32) User stated documentation style is JSDoc-first: every exported function, class, and typeβand important internal declarationsβneeds JSDoc covering purpose, constraints, assumptions, edge cases, side effects, and non-obvious rationale; type/interface fields must document units, allowed values, null meaning, and defaults.
π΄ (20:32) User stated inline comments are reserved for non-expressible rationale, business constraints, surprising behavior, workarounds, and hardcoded-value reasoning; comments that narrate syntax and ASCII-art/box-drawing section dividers are prohibited.
π΄ (20:32) User stated test preference order is: 1. model-based tests for stateful systems; 2. property-based tests for parsing, validation, and transformations; 3. traditional unit tests only for trivial logic, hard-to-express properties, exact errors/output, or external integration.
π΄ (20:32) User stated test naming/location conventions: property tests test/lib/*.property.test.ts; model-based tests test/lib/db/*.model-based.test.ts; unit tests mirror src/ under test/; E2E tests live in test/e2e/.
π΄ (20:32) User stated database/config tests must use useTestConfigDir() from test/helpers.ts; tests must never delete process.env.SENTRY_CONFIG_DIR, capture it at module scope, or manually set/delete it in beforeEach/afterEach.
π΄ (20:32) User stated TEST_TMP_DIR is namespaced by VITEST_POOL_ID in test/constants.ts, preventing parallel workers from wiping one anotherβs preload state.
π΄ (20:32) User stated property/model tests should use DEFAULT_NUM_RUNS from test/model-based/helpers.ts, equal to exactly 50 runs; isolated database tests should use createIsolatedDbContext() and always clean it up in finally.
π΄ (20:32) User stated unit tests must not duplicate invariants already covered by companion property tests; when adding property tests, remove newly redundant units and add a file-header note identifying which invariants live in the property file.
π΄ (20:32) User stated automated bug-fix PR workflow: 1. search open PRs and all issues for the same file/symbol using gh pr list --state open --search "in:title <file-or-symbol>" and gh issue list --state all --search "<symbol>"; 2. comment on or extend existing work rather than opening duplicates; 3. rebase onto current main and verify the bug still exists before review; 4. separate correctness bugs from subjective UX changes; 5. prefer existing shared helpers such as autoPaginate() and safeParseJson() over one-off fixes.
π΄ (20:32) User stated long-term project knowledge managed by lore is stored in .lore.md at the project root.