Skip to content

Enhancement: Exclude rules-{slug} folder from mode export paths for flexible slug changes #6185

@hannesrudolph

Description

@hannesrudolph

What specific problem does this solve?

When exporting a mode using the mode export functionality, the relative paths in rulesFiles include the full rules-{slug} folder name (e.g., rules-release-notes-writer/10_discord_only_workflow.xml). This prevents users from being able to change the slug in the exported YAML file and have the rules automatically imported into the correct folder.

Who is affected: Users who want to:

  • Share modes with different names/slugs
  • Create variations of existing modes by changing the slug
  • Import modes with renamed slugs without manual path editing

When this happens: During mode export/import operations when:

  • A user exports a mode with rules files
  • The user wants to change the slug before importing
  • The import places files in the wrong folder (old slug's folder)

Current behavior:

  • Export includes: relativePath: "rules-release-notes-writer/10_discord_only_workflow.xml"
  • Changing slug to release-notes-writer-v2 in the export file has NO EFFECT on where files are placed
  • Import creates: .roo/rules-release-notes-writer/10_discord_only_workflow.xml (using the old slug from the path)
  • The new slug is ignored, and rules are placed in the wrong folder

Expected behavior:

  • Export should include: relativePath: "10_discord_only_workflow.xml" (or subfolder/file.xml for nested files)
  • Import should use the mode's slug to construct: .roo/rules-{new-slug}/10_discord_only_workflow.xml
  • Changing the slug should automatically place rules in the correct new folder

Impact: Users must manually edit all file paths in the export file when changing slugs, which is error-prone and defeats the purpose of easy mode sharing.

Additional context

The current implementation in src/core/config/CustomModesManager.ts (lines 786-789) includes the rules-{slug} folder in the relative path during export. The import logic at lines 884-885 then uses these paths directly, ignoring the mode's new slug entirely.

🔍 Comprehensive Issue Scoping

Root Cause / Implementation Target

The issue stems from how relative paths are calculated during mode export. The export function includes the rules-{slug} folder name in the relative path, making the paths slug-dependent. During import, these paths are used directly with the base .roo directory, completely ignoring the mode's slug. This means changing the slug has no effect on where the rules files are placed.

Affected Components

  • Primary Files:

    • src/core/config/CustomModesManager.ts (lines 786-789): Export path calculation needs to exclude the rules-{slug} folder
    • src/core/config/CustomModesManager.ts (lines 854, 884-885): Import path construction needs to use the mode's slug
  • Secondary Impact:

    • Test files that verify the current behavior will need updates
    • Any existing exported mode files in the wild (backwards compatibility concern)

Current Implementation Analysis

  1. During export, the relative path is calculated from .roo directory, which includes rules-{slug}/
  2. During import, the baseDir is set to .roo (line 853)
  3. The files are placed using: path.join(baseDir, normalizedRelativePath) where normalizedRelativePath still contains rules-{old-slug}/
  4. This results in: .roo/rules-{old-slug}/file.xml regardless of the mode's new slug
  5. The rulesFolderPath variable (line 854) that contains the new slug is only used for cleanup, not for file placement

Proposed Implementation

Step 1: Modify Export Path Calculation

  • File: src/core/config/CustomModesManager.ts (lines 786-789)
  • Changes: Calculate relative paths from within the rules-{slug} directory, not from .roo
  • Rationale: Makes paths slug-independent by excluding the rules folder name
// Current implementation includes the rules folder:
const relativePath = isGlobalMode
  ? path.relative(baseDir, filePath)
  : path.relative(path.join(baseDir, ".roo"), filePath)
// Results in: "rules-release-notes-writer/10_discord_only_workflow.xml"

// New implementation should exclude the rules folder:
const relativePath = path.relative(modeRulesDir, filePath)
// Results in: "10_discord_only_workflow.xml"

Step 2: Update Import Path Construction

  • File: src/core/config/CustomModesManager.ts (lines 873-885)
  • Changes:
    1. Add backwards compatibility check to detect old format
    2. Use rulesFolderPath instead of baseDir for constructing target paths
  • Rationale: Ensures files go into the correct rules-{new-slug} folder
// Add after line 876 (after path normalization):
let cleanedRelativePath = normalizedRelativePath;

// Check if path starts with a rules-* folder (old export format)
const rulesMatch = normalizedRelativePath.match(/^rules-[^\/\\]+[\/\\]/);
if (rulesMatch) {
  // Strip the entire rules-* folder reference for backwards compatibility
  cleanedRelativePath = normalizedRelativePath.substring(rulesMatch[0].length);
}

// Change line 884 to use rulesFolderPath instead of baseDir:
const targetPath = path.join(rulesFolderPath, cleanedRelativePath);

Code Architecture Considerations

  • The solution maintains the existing security checks for path traversal
  • Follows the existing pattern of path normalization
  • Preserves folder structure within the rules directory (subfolders are maintained)
  • The rulesFolderPath variable already exists and contains the correct destination

Testing Requirements

  • Unit Tests:
    • Test export excludes rules-{slug} from paths
    • Test import correctly places files in rules-{new-slug} when slug is changed
    • Test backwards compatibility: old exports with rules-{slug}/ are handled correctly
    • Test nested folder structures (e.g., subfolder/file.xml) are preserved
    • Test security: path traversal attempts are still blocked
  • Integration Tests:
    • Test full export/import cycle with slug change
    • Test that files end up in the correct rules-{new-slug} folder
  • Edge Cases:
    • Files at root of rules folder
    • Files in deeply nested subfolders
    • Files with special characters in names

Performance Impact

  • Expected performance change: Neutral
  • The regex check for backwards compatibility is minimal overhead

Security Considerations

  • Path traversal protection must remain intact
  • The cleaned paths must still be validated against escaping the rules directory
  • Existing security checks in lines 879-892 remain effective

Migration Strategy

Not required - backwards compatibility ensures old exports continue to work correctly.

Rollback Plan

If issues arise, revert the changes. Old exports will continue to work with the reverted code.

Dependencies and Breaking Changes

  • External dependencies affected: None
  • API contract changes: None (internal implementation only)
  • Breaking changes for users: None (backwards compatible)

Implementation Complexity

  • Estimated effort: Small
  • Risk level: Low
  • Prerequisites: None

Metadata

Metadata

Assignees

Labels

EnhancementNew feature or requestIssue - In ProgressSomeone is actively working on this. Should link to a PR soon.proposal

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions