Skip to content

Conversation

matt-rudolph
Copy link

@matt-rudolph matt-rudolph commented Sep 19, 2025

fix(marketplace): distinguish marketplace-installed modes from local custom modes by origin flags; key installed metadata by marketplaceItemId; restrict removal to marketplace-installed mode in selected scope; add scoped delete in CustomModesManager to avoid unintended deletions (fixes #4828)

Related GitHub Issue
Closes: #4828

Roo Code Task Context (Optional)
N/A

Description
This PR resolves a slug-collision bug in the Marketplace where a marketplace mode and a locally created custom mode share the same slug. Previously:

  • Installed status was inferred solely by slug, causing the marketplace card to show "Installed" when only a local mode existed.
  • The Remove action deleted by slug without verifying origin or scope, potentially removing a user's custom mode.

Key changes:

  • Mode origin flags:
    • Added optional fields to the Mode schema: installedFromMarketplace?: boolean, marketplaceItemId?: string in packages/types/src/mode.ts.
  • Annotate during install:
    • On installing a marketplace mode, the installer injects installedFromMarketplace = true and marketplaceItemId = item.id before importing via CustomModesManager in src/services/marketplace/SimpleInstaller.ts.
  • Installed status computation:
    • Marketplace installed metadata now keys by marketplaceItemId and only for modes with installedFromMarketplace = true in src/services/marketplace/MarketplaceManager.ts. This decouples local custom modes with the same slug from marketplace-installed items.
  • Scoped, safe removal:
    • Remove now targets only a mode that matches all of:
      • slug, installedFromMarketplace === true, marketplaceItemId === item.id, and source === selected target ("project"/"global"), implemented in src/services/marketplace/SimpleInstaller.ts.
    • Introduced a scoped deletion helper to delete from only the selected source and clean up the appropriate rules folder in src/core/config/CustomModesManager.ts.

Files changed:

packages/types/src/mode.ts
src/services/marketplace/SimpleInstaller.ts
src/services/marketplace/MarketplaceManager.ts
src/core/config/CustomModesManager.ts
Tests updated: src/services/marketplace/tests/SimpleInstaller.spec.ts

Reviewer notes:

  • Origin fields are optional to maintain backward compatibility. They will only be present for marketplace-installed modes going forward.
  • Removal respects the selected scope and will not delete an unrelated local custom mode, even if slugs match.
    Test Procedure
    Unit tests

From repo root:

  • export PATH="(brew−−prefixnode)/bin:PATH"
  • corepack enable
  • pnpm install
  • pnpm --filter @roo-code/types build
    Run targeted tests from the src package (per repo rules, run from the package directory):
  • cd src
  • pnpm test -- services/marketplace/tests/SimpleInstaller.spec.ts
    Expected: tests pass (previous run summary: 296 files, 3812+ passing tests overall, several skipped; SimpleInstaller tests pass with marketplace-origin assertions).
  • To run the full src suite: cd src && pnpm test

Manual verification steps

  1. Create a custom mode locally with slug S (via .roomodes or global settings).
  2. Ensure the Marketplace includes an item with id S (or a different id whose mode content has slug S).
  3. Open Marketplace:
  • Before marketplace installation: the item should NOT show "Installed".
  1. Click "Remove":
  • If the marketplace item was not installed, removal should be blocked with: "This mode was not installed from the marketplace for the selected target".
  1. Install the marketplace item:
  • The item should now show "Installed" (project/global as appropriate).
  1. Click "Remove" with target scope selection:
  • Only the marketplace-installed mode in the selected scope is removed; local custom mode (same slug) remains intact.

Environment notes

  • Engine warning may appear if using Node v24+. The workspace indicates node 20.19.2 as the preferred engine. Tests still pass on Node v24, but you can use Node 20.19.2 to match engines:
  • nvm install 20.19.2 && nvm use 20.19.2
  • corepack enable

Pre-Submission Checklist

  • [X ] Issue Linked: This PR is linked to an approved issue (see "Related GitHub Issue" above).
  • [ X] Scope: Changes are focused on the linked issue.
  • [ X] Self-Review: Performed a thorough self-review.
  • [ X] Testing: Added/updated unit tests; ran targeted and package tests.
  • [ X] Documentation Impact: No user-facing documentation updates required.
  • [ X] Contribution Guidelines: Read and agree to the Contributor Guidelines.

Screenshots / Videos
N/A (no UI changes visible; behavior changes are in installed badge logic and scoped removal; functional verification described in "Test Procedure").

Documentation Updates
No documentation updates are required.

Additional Notes
Backward compatibility: existing modes without marketplace origin metadata are unaffected.
i18n: No user-facing strings changed for this fix.


Important

Fixes slug-collision bug by distinguishing marketplace-installed modes from local modes using origin flags and updating removal logic.

  • Behavior:
    • Distinguish marketplace-installed modes from local modes using installedFromMarketplace and marketplaceItemId flags in mode.ts.
    • Restrict removal to marketplace-installed modes matching slug, marketplaceItemId, and source in SimpleInstaller.ts.
  • Installation and Removal:
    • Annotate modes with marketplace metadata during installation in SimpleInstaller.ts.
    • Implement scoped deletion in CustomModesManager.ts to prevent unintended deletions.
  • Tests:
    • Update tests in SimpleInstaller.spec.ts to verify new behavior and error handling for marketplace-installed modes.

This description was created by Ellipsis for a76bc0b. You can customize this summary. It will automatically update as commits are pushed.

…custom modes by origin flags; key installed metadata by marketplaceItemId; restrict removal to marketplace-installed mode in selected scope; add scoped delete in CustomModesManager to avoid unintended deletions (fixes RooCodeInc#4828)
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Sep 19, 2025
Copy link

@roomote roomote bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this comprehensive fix to the slug collision issue! The approach of using origin metadata fields to distinguish marketplace-installed modes from local custom modes is solid, and I appreciate the attention to backward compatibility. The test coverage looks thorough as well.

@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Sep 19, 2025
…safety and i18n; atomic deleteCustomModeForSource; update tests and en locale
…lled mode; remove added en locale key to satisfy translation check
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. size:L This PR changes 100-499 lines, ignoring generated files.
Projects
Status: Triage
Development

Successfully merging this pull request may close these issues.

[BUG] Marketplace mode shows Installed when a custom mode has the same slug
2 participants