You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Consolidate target parsing into positional parsers #1564
parseOrgTarget and parseOrgProjectTarget (packages/cli/src/lib/completion-target.ts, added in #1557) are identity parsers. They only mark a positional's completion kind. Each command still parses and validates the raw string itself inside func, using parseOrgProjectArg, parseSlashSeparatedArg, parseIssueArg, and similar helpers from src/lib/arg-parsing.ts.
Commands that share a target syntax repeat the same parse call, and the positional definition and its parsing live in different places.
Some flows depend on the raw string reaching func today: buildListCommand rewrites the first positional to catch plural-alias subcommand typos, maybeRecoverWithHelp treats a literal help argument as --help, and some commands auto-recover from the wrong entity type. Parse failures currently surface as CliError subclasses with specific exit codes. Errors thrown from a Stricli parser go through Stricli's argument-error handling instead.
Fixed by #1594 (merged 2026-10-23), which adds the target positional parser and moves trace list, replay list, feedback list, project view and project delete onto it. The PR used Refs #1564, so it didn't close this automatically. Closing per @BYK.
Reopening: #1594 landed the lazy parsed/resolved positional mechanism and migrated trace list, replay list, feedback list, project view and project delete, but the migration and some hardening are still open.
Harden destructive checks: right now the guard only runs when a destructive command reads .resolved. A command that reads .parsed and then mutates skips it. buildListCommand's re-wrap also drops the destructive mark (no destructive list commands exist today, so this can't trigger yet). The require-target-resolution lint rule is easy to get around.
LazyPositional: memoize parse failures (a failing .parsed re-parses on every read) and avoid unhandled rejections when .resolved is read but never awaited.
Migrate any remaining unblocked positionals. log list, replay view and replay download are variadic or depend on the number of arguments, so they stay in func.
ref(cli): Parse target positionals in Stricli's argument scanner #1655 (new): target positionals now parse in Stricli's argument scanner. Every argument parse error exits 252, positionals included, and the exit code docs say so. Pasting a Sentry URL as a target no longer switches the CLI to that URL's server during parsing; that now happens when the target resolves, after the auth guard. The destructive-command check runs in buildCommand, so it no longer depends on the command reading target.resolved. ref(cli): Parse target positionals in Stricli's argument scanner #1655 also replaces the parse-memoization and destructive-guard hardening I mentioned earlier.
Still to do: migrate LIST_TARGET_POSITIONAL users, including agent-conversation list, once #1575 lands, and look at the issue and dashboard targets after #1572. log list, replay view and replay download keep parsing in func.
Done. Every target and ID positional in the CLI is now parsed before the command runs, through shared bound parsers. The lint rules that enforce this have no allow-list.
What changed
Target positionals ([<org>/][<project>], org-only, releases, alert rules) use the parsers in src/lib/target-positional.ts / boundPositional / boundArguments. func reads await target.resolved and never parses or resolves by hand.
ID positionals go through parseIdArguments() and the shared grammar/id-arguments.pegjs. Issues have their own grammar. Parsing has no side effects: a pasted URL's server is applied when the target resolves, after the auth guard.
sentry-cli/require-target-resolution and sentry-cli/no-ad-hoc-id-arguments reject hand parsing in src/commands/, with no exemptions. Before this work, 45 command files used hand-parsing helpers. Now none do.
test/lib/argument-conventions.test.ts checks the same argument forms across commands.
Activity
linear-code commentedon Oct 20, 2026
MCP-1099
ref(cli): Hand commands parsed targets instead of a lazy wrapper
ref(cli): Parse target positionals lazily behind the parsed type
ref(cli): Bind target resolution to the positional as a lazy promise
ref(cli): Derive target command names and guard destructive targets
ref(cli): Replace the target Proxy with a LazyPositional class
feat(cli): Parse and resolve org/project targets in their positional (#…
sentry-junior commentedon Oct 23, 2026
Fixed by #1594 (merged 2026-10-23), which adds the target positional parser and moves
trace list,replay list,feedback list,project viewandproject deleteonto it. The PR usedRefs #1564, so it didn't close this automatically. Closing per @BYK.fix(cli): Keep CliError exit codes for argument parser failures
sentry-junior commentedon Oct 23, 2026
Reopening: #1594 landed the lazy parsed/resolved positional mechanism and migrated
trace list,replay list,feedback list,project viewandproject delete, but the migration and some hardening are still open.Open PRs that this issue depends on
LIST_TARGET_POSITIONALusers, includingagent-conversation listNew PRs
exploreontoorgOptionalTarget, with org/project shell completionCliErrorexit code when a flag or positional parser throws (it used to exit with 252)Next, in priority order
.resolved. A command that reads.parsedand then mutates skips it.buildListCommand's re-wrap also drops the destructive mark (no destructive list commands exist today, so this can't trigger yet). Therequire-target-resolutionlint rule is easy to get around.LazyPositional: memoize parse failures (a failing.parsedre-parses on every read) and avoid unhandled rejections when.resolvedis read but never awaited.log list,replay viewandreplay downloadare variadic or depend on the number of arguments, so they stay infunc.I'll link the new PRs here as I open them.
ref(cli): Move explore onto the org-optional target positional (#1650)
sentry-junior commentedon Oct 25, 2026
Status update:
exploreonorgOptionalTarget): merged.CliError's exit code when an argument fails to parse.buildCommand, so it no longer depends on the command readingtarget.resolved. ref(cli): Parse target positionals in Stricli's argument scanner #1655 also replaces the parse-memoization and destructive-guard hardening I mentioned earlier.Still to do: migrate
LIST_TARGET_POSITIONALusers, includingagent-conversation list, once #1575 lands, and look at the issue and dashboard targets after #1572.log list,replay viewandreplay downloadkeep parsing infunc.16 remaining items
ref(cli): Ratchet hand-parsed positionals and test argument conventions
fix(cli): Keep all-digit event IDs after <short-id>/ as events (#1738)
ref(cli): Ratchet hand-parsed positionals and test argument conventio…
ref(cli): Parse dashboard and issue arguments with the shared ID gram…
test(cli): Check dashboard and issue search arguments across commands (…
ref(cli): Bind org-only and opaque-ID positionals (#1744)
fix(cli): Read only the first line of an org argument (#1749)
ref(cli): Parse issue view, explain, and merge positionals before run (…
ref(cli): Drop the empty ad-hoc ID parsing allow-list
ref(cli): Parse init, project create and dashboard create arguments b…
ref(cli): Drop the unbound target parsing allow-list
ref(cli): Parse alert rule positionals before the command runs (#1745)
ref(cli): Remove the completion-only target parsers (#1750)
sentry-junior commentedon Oct 30, 2026
Done. Every target and ID positional in the CLI is now parsed before the command runs, through shared bound parsers. The lint rules that enforce this have no allow-list.
What changed
[<org>/][<project>], org-only, releases, alert rules) use the parsers insrc/lib/target-positional.ts/boundPositional/boundArguments.funcreadsawait target.resolvedand never parses or resolves by hand.parseIdArguments()and the sharedgrammar/id-arguments.pegjs. Issues have their own grammar. Parsing has no side effects: a pasted URL's server is applied when the target resolves, after the auth guard.sentry-cli/require-target-resolutionandsentry-cli/no-ad-hoc-id-argumentsreject hand parsing insrc/commands/, with no exemptions. Before this work, 45 command files used hand-parsing helpers. Now none do.test/lib/argument-conventions.test.tschecks the same argument forms across commands.PRs
#1711, #1728, #1729, #1730, #1733, #1738, #1739, #1742, #1744, #1745, #1746, #1747, #1749, and the cleanup #1750 (removed the unused completion-only parsers).
Two regressions came in during the migration and were fixed right after (#1738, #1749).