diff --git a/src/lib/arg-parsing.ts b/src/lib/arg-parsing.ts index 588de7738..a0e6c9273 100644 --- a/src/lib/arg-parsing.ts +++ b/src/lib/arg-parsing.ts @@ -369,6 +369,12 @@ export type ParsedOrgProject = projectSlug: string; /** True if project slug was normalized */ normalized?: boolean; + /** + * Organization slug to scope the search to, when the caller provided + * one (e.g. "org/My Project"). When unset the search spans all + * accessible organizations. + */ + org?: string; /** * Pre-normalization input when {@link normalized} is `true`. * Used by the resolution layer to produce user-friendly messages @@ -536,6 +542,18 @@ function parseSlashOrgProject(input: string): ParsedOrgProject { // "sentry/cli" → explicit org and project rejectAtSelector(rawProject, "project slug"); + if (looksLikeDisplayName(rawProject)) { + // Spaces → display name, not a slug. Skip slug validation and let the + // resolution layer do a fuzzy name-based search (mirrors the bare-slug + // and leading-slash paths). Prevents a hard ValidationError when callers + // pass a project display name in "org/project" form (CLI-1RA). + return { + type: "project-search", + projectSlug: rawProject, + originalSlug: rawProject, + org: no.slug, + }; + } const np = normalizeSlug(rawProject); validateResourceId(np.slug, "project slug"); const normalized = no.normalized || np.normalized; diff --git a/src/lib/resolve-target.ts b/src/lib/resolve-target.ts index 9f1b97b0e..300ce6d41 100644 --- a/src/lib/resolve-target.ts +++ b/src/lib/resolve-target.ts @@ -1640,10 +1640,17 @@ export async function resolveOrgProjectTarget( case "project-search": { const displaySlug = parsed.originalSlug ?? parsed.projectSlug; const isDisplayName = parsed.originalSlug !== undefined; - const { projects, orgs } = isDisplayName + const { projects, orgs: foundOrgs } = isDisplayName ? { projects: [], orgs: await listOrganizations() } : await findProjectsBySlug(parsed.projectSlug); + // When the caller provided an org (e.g. "org/My Project"), scope the + // display-name search to that org instead of all accessible orgs. + const orgs = + isDisplayName && parsed.org !== undefined + ? foundOrgs.filter((o) => o.slug === parsed.org) + : foundOrgs; + if (projects.length === 0) { const outcome = await triageProjectNotFound( parsed.projectSlug,