Dashboard › cli › Distillation
f8a8d152-0648-4407-af2d-ca2e312b57a3["lore_tm_v1_OQlfQiWwkzAm-zFlONRQHYfJ9v86QVVw4CAYnOYyCmM","lore_tm_v1_NO1v6CNcr1rpCwxEkNjpLFFlDwQwNi1VJDDXyFvYXuQ"]
Date: Sep 9, 2026
packages/cli/src/lib/introspect.ts is a 496-line shared route-tree introspection module used at runtime by sentry help --json and at build time by generate-skill.ts; it defines simplified Stricli-facing types because @stricli/core does not export internal types such as RouteMapEntry or FlagParameter.packages/cli/src/lib/introspect.ts defines route-tree types RouteMapEntry, RouteTarget, RouteMap, Command, PositionalParams, PositionalParam, PositionalInfo, and FlagDef; output metadata types are CommandInfo, FlagInfo, RouteInfo, ResolvedPath, and UnresolvedPath.Command metadata supports non-standard properties attached by buildCommand: __jsonSchema?: import("valibot").GenericSchema, __primaryUsage?: string, and __examples?: readonly CommandExample[]. CommandInfo preserves path, brief, optional fullDescription, flags, rendered positional, structured positionals, aliases, examples, and optional jsonFields.isRouteMap(target) identifies a non-null object containing getAllEntries; isCommand(target) identifies a non-null object containing parameters but not getAllEntries. Both accept unknown.getPositionalString(params) renders no params as ""; tuple params as space-separated placeholders such as <target>, wrapping optional entries as [<target>] and defaulting names to arg${i}; array params render as <${placeholder ?? "args"}...>.extractPositionals(params) returns [] when absent; tuples become one PositionalInfo per parameter with defaults placeholder: arg${i}, brief: "", and optional: false; arrays become one always-optional entry whose placeholder ends in ... and defaults to args....extractFlags(flags) normalizes each flag’s name, brief, kind, default, optional, variadic, and hidden; defaults are brief: "", variadic: false, hidden: false, while optional defaults to true only for boolean flags.buildCommandInfo(cmd, path, examples = []) extracts JSON fields from cmd.__jsonSchema, prefers cmd.__primaryUsage over generated positional syntax, preserves aliases, and prefers canonical cmd.__examples over externally supplied examples. Canonical examples are rendered exactly as # ${description}\n${command}; empty JSON-field results become undefined.extractRouteGroupCommands(routeMap, routeName, docExamples) recursively walks visible nested route maps, skips hidden entries, builds paths beginning with sentry, and obtains fallback examples from docExamples by full command path. extractAllRoutes(routeMap) similarly returns metadata for every visible top-level group or standalone command.resolveCommandPath(routeMap, path) returns null for an empty path; resolves visible standalone commands and groups recursively; skips hidden routes; prepends parent segments to nested command paths using SENTRY_PREFIX_RE = /^sentry /; and returns UnresolvedPath for unmatched segments with up to MAX_SUGGESTIONS = 3 results from fuzzyMatch().packages/cli/src/lib/list-command.ts now imports CommandDocumentation from ./command.js; buildListCommand().builderArgs.docs uses CommandDocumentation, and OrgListCommandDocs is now an alias of CommandDocumentation, allowing shared canonical documentation metadata rather than only brief and optional fullDescription.buildListCommand() preserves an existing fresh flag; otherwise it injects FRESH_FLAG, and its wrapper automatically calls applyFreshFlag(flags) before invoking the original command function.buildListCommand() injects --cursor unless options.noCursorFlag is true or the command defines cursor; injects -f → --fresh unless options.noFreshAlias is true or alias f exists; and injects -c → --cursor unless cursor injection is disabled or alias c exists.buildListCommand() is “always the target (org/project pattern).” The wrapper passes that argument through interceptSubcommand(args[0], ctx.stderr, routeName) when it is a string or undefined, preventing plural aliases from misinterpreting known subcommand names as targets.buildListCommand() and buildDeleteCommand() preserve custom flags and aliases by cloning existing definitions into mergedFlags and mergedAliases, adding defaults only when keys are available, then forwarding merged parameters and the wrapped generator to buildCommand().packages/cli/src/lib/mutate-command.ts now imports CommandDocumentation from ./command.js, and buildDeleteCommand().builderArgs.docs uses that shared type instead of a local { brief; fullDescription? } shape.buildDeleteCommand() preserves a command-owned yes flag; otherwise it injects YES_FLAG.buildDeleteCommand() additionally injects --force unless options.noForceFlag or an existing force flag prevents it, injects --dry-run unless options.noDryRunFlag or an existing "dry-run" flag prevents it, and adds available aliases -y → --yes, -f → --force, and -n → --dry-run under the corresponding opt-out rules.guardNonInteractive(flags) therefore permits "dry-run" as well as --yes or --force; buildDeleteCommand() runs this guard before the original function unless options.noNonInteractiveGuard is true.packages/cli/test/commands/agent-conversation/list.test.ts adds test "uses the canonical optional-org usage in resolution errors": when resolveOrg() returns null and listCommand.func is called with HUMAN_FLAGS and undefined, the rejection must match { command: "sentry agent-conversation list [<org>]" }.