Skip to content

[FEATURE] Support marketplace notation (name@marketplace) in apm uninstall #1323

@sergio-sisternes-epam

Description

@sergio-sisternes-epam

Is your feature request related to a problem? Please describe.

apm install accepts marketplace notation (apm install my-plugin@official), but apm uninstall does not -- it rejects any package whose name does not contain /:

$ apm uninstall my-plugin@official
[x] Invalid package format: my-plugin@official. Use 'owner/repo' format.

The rejection happens in _validate_uninstall_packages (src/apm_cli/commands/uninstall/engine.py:48), before any resolution is attempted. To remove a plugin that was installed via a marketplace, users have to open apm.yml (or apm.lock.yaml) to look up the canonical owner/repo form -- a clear install/uninstall asymmetry that breaks the "remove what you installed, the way you installed it" expectation set by npm/pip/cargo.

Describe the solution you'd like

Make apm uninstall accept the same NAME@MARKETPLACE[#REF] grammar that apm install accepts (defined by _MARKETPLACE_RE in src/apm_cli/marketplace/resolver.py:41). Resolve the marketplace ref to its canonical identity, then run the existing identity-match logic against apm.yml.

Resolution strategy (lockfile-first, registry fallback):

  1. Lockfile lookup (offline, cheap): scan LockFile.dependencies for entries whose discovered_via == <marketplace> and marketplace_plugin_name == <name> -- this provenance is already written at install time (src/apm_cli/deps/lockfile.py:43-44).
  2. Marketplace-registry fallback (silent, mirrors install): when the lockfile does not carry the provenance, call parse_marketplace_ref() + resolve_marketplace_plugin() to obtain the canonical owner/repo and match by identity.
  3. Clear failure: if both fail, surface plugin '<name>@<marketplace>' is not installed (marketplace-specific wording, distinct from the generic "not found in apm.yml" used for canonical refs).

Expected behaviour after the change:

$ apm uninstall my-plugin@official
[+] my-plugin@official - found in apm.yml (as acme/my-plugin)
[+] Removed acme/my-plugin from apm.yml
[+] Uninstall complete: Removed 1 package(s) from apm.yml, Removed 1 package(s) from apm_modules/

apm uninstall my-plugin@official --dry-run, -g, and batch mixes (canonical + marketplace refs that point at the same dep) should all work without extra flags.

Describe alternatives you've considered

  • Require an explicit opt-in flag (--resolve-marketplace) for the registry fallback. Rejected: install is silent, and the lockfile-first path covers the common case with zero network calls, so requiring a flag would just add friction without protecting against anything.
  • Lockfile-only resolution (no registry fallback). Rejected: would fail for users whose lockfile has been deleted/regenerated without the provenance fields, even though the canonical owner/repo is in apm.yml and reachable.
  • Document the asymmetry and leave it. Rejected: the install/uninstall symmetry is a core npm-style ergonomic the project already commits to, and the cost to fix is small.

Additional context

  • Validator gate to relax: src/apm_cli/commands/uninstall/engine.py:48.
  • Marketplace grammar: _MARKETPLACE_RE in src/apm_cli/marketplace/resolver.py:41.
  • Provenance written by install: discovered_via, marketplace_plugin_name in src/apm_cli/deps/lockfile.py:43-44, populated in src/apm_cli/commands/install.py:400-405.
  • Out of scope: no change to apm.yml storage format (marketplace refs continue to be resolved to canonical form before being persisted); no change to install; no new flags.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/cliCLI command surface, flags, help text (cross-cutting).area/docs-sitedocs/src/content (Starlight), README, doc generation.area/marketplacemarketplace.json schema, federation, authoring suite, source parity.priority/highShips in current or next milestonestatus/acceptedDirection approved, safe to start work.status/triagedInitial agentic triage complete; pending maintainer ratification (silence = approval).theme/portabilityOne manifest, every target. Multi-target deploy, marketplace, packaging, install.type/featureNew capability, new flag, new primitive.

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions