From 39332513aed3cfb32c49bdb367fa2bf44f397741 Mon Sep 17 00:00:00 2001 From: Smartsheet-JB-Brown Date: Mon, 14 Apr 2025 15:00:14 -0700 Subject: [PATCH] documentation updates --- cline_docs/package-manager/README.md | 67 ++++- .../implementation/02-core-components.md | 8 +- .../package-manager-improvements-summary.md | 100 +++++++ .../type-filter-improvements.md | 207 ++++++++++++++ .../implementation/type-filter-test-plan.md | 190 +++++++++++++ .../user-guide/03-searching-and-filtering.md | 32 ++- .../user-guide/04-working-with-details.md | 7 +- .../user-guide/05-adding-packages.md | 265 +++++++++++++++++- .../user-guide/06-adding-custom-sources.md | 29 +- .../package-manager/PackageManagerManager.ts | 42 +-- .../__tests__/CombinedFeatures.test.ts | 94 +++++++ .../__tests__/TypeFilterBehavior.test.ts | 216 ++++++++++++++ src/services/package-manager/types.ts | 1 + 13 files changed, 1188 insertions(+), 70 deletions(-) create mode 100644 cline_docs/package-manager/implementation/package-manager-improvements-summary.md create mode 100644 cline_docs/package-manager/implementation/type-filter-improvements.md create mode 100644 cline_docs/package-manager/implementation/type-filter-test-plan.md create mode 100644 src/services/package-manager/__tests__/CombinedFeatures.test.ts create mode 100644 src/services/package-manager/__tests__/TypeFilterBehavior.test.ts diff --git a/cline_docs/package-manager/README.md b/cline_docs/package-manager/README.md index ef969180c8..893e2361f7 100644 --- a/cline_docs/package-manager/README.md +++ b/cline_docs/package-manager/README.md @@ -1,22 +1,59 @@ # Package Manager Documentation -This directory contains comprehensive documentation for the Roo Code Package Manager feature, including both user guides and implementation documentation. +This directory contains comprehensive documentation for the Roo Code Package Manager, including both user guides and implementation details. -## Table of Contents +## Documentation Structure ### User Guide -1. [Introduction to Package Manager](./user-guide/01-introduction.md) -2. [Browsing Packages](./user-guide/02-browsing-packages.md) -3. [Searching and Filtering](./user-guide/03-searching-and-filtering.md) -4. [Working with Package Details](./user-guide/04-working-with-details.md) -5. [Adding Packages](./user-guide/05-adding-packages.md) -6. [Adding Custom Package Sources](./user-guide/06-adding-custom-sources.md) + +The user guide provides end-user documentation for using the Package Manager: + +1. [Introduction to Package Manager](./user-guide/01-introduction.md) - Overview and purpose of the Package Manager +2. [Browsing Packages](./user-guide/02-browsing-packages.md) - Understanding the interface and navigating packages +3. [Searching and Filtering](./user-guide/03-searching-and-filtering.md) - Using search and filters to find packages +4. [Working with Package Details](./user-guide/04-working-with-details.md) - Exploring package details and subcomponents +5. [Adding Packages](./user-guide/05-adding-packages.md) - Creating and contributing your own packages +6. [Adding Custom Sources](./user-guide/06-adding-custom-sources.md) - Setting up and managing custom package sources ### Implementation Documentation -1. [Package Manager Architecture](./implementation/01-architecture.md) -2. [Core Components](./implementation/02-core-components.md) -3. [Data Structures](./implementation/03-data-structures.md) -4. [Search and Filter Implementation](./implementation/04-search-and-filter.md) -5. [UI Component Design](./implementation/05-ui-components.md) -6. [Testing Strategy](./implementation/06-testing-strategy.md) -7. [Extending the Package Manager](./implementation/07-extending.md) \ No newline at end of file + +The implementation documentation provides technical details for developers: + +1. [Architecture](./implementation/01-architecture.md) - High-level architecture of the Package Manager +2. [Core Components](./implementation/02-core-components.md) - Key components and their responsibilities +3. [Data Structures](./implementation/03-data-structures.md) - Data models and structures used in the Package Manager +4. [Search and Filter](./implementation/04-search-and-filter.md) - Implementation of search and filtering functionality + +### Improvement Proposals + +These documents outline proposed improvements to the Package Manager: + +1. [Package Manager Improvements Summary](./implementation/package-manager-improvements-summary.md) - Overview of completed and proposed improvements +2. [Type Filter Improvements](./implementation/type-filter-improvements.md) - Proposal for making type filter behavior more consistent +3. [Type Filter Test Plan](./implementation/type-filter-test-plan.md) - Test plan for the proposed type filter improvements +4. [Localization Improvements](./implementation/localization-improvements.md) - Implementation plan for proper locale fallback mechanism + +## Key Features + +The Package Manager provides the following key features: + +- **Component Discovery**: Browse and search for components +- **Package Management**: Add components to your environment +- **Custom Sources**: Add your own package repositories +- **Localization Support**: View components in your preferred language +- **Filtering**: Filter components by type, search term, and tags + +## Default Package Repository + +The default package repository is located at: +[https://github.com/RooVetGit/Roo-Code-Packages](https://github.com/RooVetGit/Roo-Code-Packages) + +## Contributing + +To contribute to the Package Manager documentation: + +1. Make your changes to the relevant markdown files +2. Ensure that your changes are accurate and consistent with the actual implementation +3. Submit a pull request with your changes + +For code changes to the Package Manager itself, please refer to the main [CONTRIBUTING.md](../../CONTRIBUTING.md) file. diff --git a/cline_docs/package-manager/implementation/02-core-components.md b/cline_docs/package-manager/implementation/02-core-components.md index e2123e6bce..44ebdde5ef 100644 --- a/cline_docs/package-manager/implementation/02-core-components.md +++ b/cline_docs/package-manager/implementation/02-core-components.md @@ -180,16 +180,12 @@ class PackageManagerManager { The filtering algorithm applies multiple criteria to the package items: 1. Start with the complete set of items -2. If a type filter is specified: - - Keep only items matching the specified type -3. If a search term is specified: +2. If a search term and/or filter is specified: - Check item name, description, and author for matches - Check subcomponents for matches - Keep items that match or have matching subcomponents - Add match information to the items -4. If tag filters are specified: - - Keep only items that have at least one of the specified tags -5. Return the filtered items with match information +3. Return the filtered items with match information #### Source Management diff --git a/cline_docs/package-manager/implementation/package-manager-improvements-summary.md b/cline_docs/package-manager/implementation/package-manager-improvements-summary.md new file mode 100644 index 0000000000..44d272b122 --- /dev/null +++ b/cline_docs/package-manager/implementation/package-manager-improvements-summary.md @@ -0,0 +1,100 @@ +# Package Manager Improvements Summary + +This document summarizes the improvements made to the Package Manager and proposes additional enhancements for a more consistent user experience. + +## Completed Improvements + +### 1. Repository URL Update + +- **Change**: Updated the default package manager repository URL from `https://github.com/RooVetGit/Roo-Code/tree/main/package-manager-template` to `https://github.com/RooVetGit/Roo-Code-Packages` +- **Files Modified**: `src/services/package-manager/constants.ts` +- **Documentation Updated**: All references to the repository URL in the user guide have been updated + +### 2. Localization Support + +- **Change**: Implemented proper locale fallback mechanism for metadata +- **Files Added/Modified**: + - Added `LocalizationOptions` interface to `src/services/package-manager/types.ts` + - Created `src/services/package-manager/utils.ts` with `getUserLocale()` function + - Modified `MetadataScanner.ts` to use localization options + - Updated `GitFetcher.ts` to pass localization options to MetadataScanner + - Updated `PackageManagerManager.ts` to initialize GitFetcher with localization options +- **Behavior**: + - Uses the user's locale when available + - Falls back to English when the user's locale isn't available + - Skips components that don't have either the user's locale or English metadata +- **Documentation Updated**: User guide now correctly explains the localization behavior + +### 3. Documentation Updates + +- **Change**: Updated documentation to reflect actual implementation +- **Files Modified**: + - `cline_docs/package-manager/user-guide/01-introduction.md` + - `cline_docs/package-manager/user-guide/02-browsing-packages.md` + - `cline_docs/package-manager/user-guide/03-searching-and-filtering.md` + - `cline_docs/package-manager/user-guide/04-working-with-details.md` + - `cline_docs/package-manager/user-guide/05-adding-packages.md` + - `cline_docs/package-manager/user-guide/06-adding-custom-sources.md` +- **Updates**: + - Corrected interface layout description (top-bottom split instead of left-right) + - Removed mentions of pagination controls + - Clarified search behavior as a simple string contains match that is case and whitespace insensitive + - Added information about locale fallbacks + - Removed mentions of author filtering + - Removed the Source Priority section + - Added information about the items array for referencing components outside the package directory tree + - Added information about cache TTL and force refresh + +## Proposed Improvements + +### 1. Type Filter Behavior Consistency + +- **Issue**: Currently, type filters and search terms behave differently for packages with subcomponents +- **Proposed Change**: Make type filter behavior consistent with search term behavior +- **Files to Modify**: `src/services/package-manager/PackageManagerManager.ts` +- **Detailed Proposal**: See [Type Filter Improvements](./type-filter-improvements.md) +- **Test Plan**: See [Type Filter Test Plan](./type-filter-test-plan.md) + +#### Current vs. Proposed Behavior + +| Aspect | Current Type Filter | Current Search | Proposed Type Filter | +| ---------------- | -------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------- | +| Package Matching | Only checks subcomponents | Checks package and subcomponents | Checks package and subcomponents | +| Result Inclusion | Package included if any subcomponent matches | Package included if it or any subcomponent matches | Package included if it or any subcomponent matches | +| Match Indication | Marks matching subcomponents | Marks matching package and subcomponents | Marks matching package and subcomponents | +| Match Reasons | Only sets hasMatchingSubcomponents | Sets nameMatch, descriptionMatch, hasMatchingSubcomponents | Sets typeMatch, hasMatchingSubcomponents | + +## Implementation Strategy + +### Phase 1: Repository URL and Documentation Updates (Completed) + +- Update the default repository URL +- Update all documentation to reflect the actual implementation + +### Phase 2: Localization Support (Completed) + +- Implement proper locale fallback mechanism +- Add tests for localization functionality +- Update documentation to reflect the localization behavior + +### Phase 3: Type Filter Behavior Consistency (Proposed) + +- Update the type filter logic to be consistent with search term behavior +- Add tests for the new type filter behavior +- Verify that there are no regressions in other filtering functionality + +## Benefits + +1. **Improved User Experience**: Consistent behavior between different types of filters makes the Package Manager more intuitive to use + +2. **Better Discoverability**: Users can more easily find packages that contain components of a specific type + +3. **Accurate Documentation**: Documentation now correctly reflects the actual implementation + +4. **Internationalization Support**: Proper locale fallback mechanism improves the experience for non-English users + +## Conclusion + +The completed improvements have addressed several issues with the Package Manager, particularly around documentation accuracy and localization support. The proposed type filter improvements would further enhance the user experience by making the filtering behavior more consistent and intuitive. + +These changes are targeted and careful, focusing on specific areas to minimize the risk of regressions while improving the overall functionality and user experience of the Package Manager. diff --git a/cline_docs/package-manager/implementation/type-filter-improvements.md b/cline_docs/package-manager/implementation/type-filter-improvements.md new file mode 100644 index 0000000000..70b71546b8 --- /dev/null +++ b/cline_docs/package-manager/implementation/type-filter-improvements.md @@ -0,0 +1,207 @@ +# Type Filter Improvements for Package Manager + +## Current Behavior Analysis + +Currently, there's an inconsistency between how type filters and search terms are applied to subcomponents in packages: + +### Type Filters (Current) + +- Only keeps packages that have at least one subcomponent matching the type filter +- Marks subcomponents with `matchInfo.matched = true` if their type matches the filter +- Does not check the package's own type (since it's already known to be "package") +- Sets `matchInfo.matchReason.hasMatchingSubcomponents = true` if any subcomponents match + +### Search Terms (Current) + +- Checks if the package's name or description matches the search term +- Also checks each subcomponent's name and description for matches +- Marks subcomponents with `matchInfo.matched = true` and sets appropriate match reasons if they match +- Sets `matchInfo.matchReason.hasMatchingSubcomponents = true` if any subcomponents match +- Returns true if either the package itself or any of its subcomponents match + +## Proposed Improvements + +To make the behavior consistent and provide a better user experience, we should modify the type filter logic to be more similar to the search term logic: + +### Type Filters (Proposed) + +1. For packages: + + - Check if the package itself is of the filtered type (which would always be false for type filters other than "package") + - Check if any subcomponents match the type filter + - Keep the package if either the package itself or any of its subcomponents match the type filter + - Mark subcomponents with `matchInfo.matched = true` if their type matches the filter + - Set appropriate match reasons for both the package and its subcomponents + +2. For non-packages: + - Keep the current behavior (check if the item's type matches the filter) + +## Implementation Changes + +Here's the proposed code change for the `filterItems` method in `PackageManagerManager.ts`: + +```typescript +filterItems( + items: PackageManagerItem[], + filters: { type?: ComponentType; search?: string; tags?: string[] }, +): PackageManagerItem[] { + // Helper function to normalize text for case/whitespace-insensitive comparison + const normalizeText = (text: string) => text.toLowerCase().replace(/\s+/g, " ").trim() + + // Normalize search term once + const searchTerm = filters.search ? normalizeText(filters.search) : "" + + // Helper function to check if text contains the search term + const containsSearchTerm = (text: string) => { + if (!searchTerm) return true + return normalizeText(text).includes(normalizeText(searchTerm)) + } + + const filteredItems = items.map((originalItem) => { + // Create a deep clone of the item to avoid modifying the original + return JSON.parse(JSON.stringify(originalItem)) as PackageManagerItem + }) + + console.log("Initial items:", JSON.stringify(filteredItems)) + return filteredItems.filter((item) => { + // For packages, handle differently based on filters + if (item.type === "package") { + // If we have a type filter + if (filters.type) { + // Check if the package itself matches the type filter + const packageTypeMatch = item.type === filters.type + + // Check subcomponents if they exist + let hasMatchingSubcomponents = false + if (item.items && item.items.length > 0) { + // Mark subcomponents with matchInfo based on type + item.items.forEach((subItem) => { + const subTypeMatch = subItem.type === filters.type + subItem.matchInfo = { + matched: subTypeMatch, + matchReason: { + typeMatch: subTypeMatch + } + } + }) + + // Check if any subcomponents match + hasMatchingSubcomponents = item.items.some((subItem) => subItem.matchInfo?.matched) + } + + // Set package matchInfo + item.matchInfo = { + matched: packageTypeMatch || hasMatchingSubcomponents, + matchReason: { + typeMatch: packageTypeMatch, + hasMatchingSubcomponents + } + } + + // Keep package if it or any of its subcomponents match the type filter + return packageTypeMatch || hasMatchingSubcomponents + } + + // For search term + if (searchTerm) { + // Check package and subcomponents + const nameMatch = containsSearchTerm(item.name) + const descMatch = containsSearchTerm(item.description) + + // Process subcomponents if they exist + if (item.items && item.items.length > 0) { + // Add matchInfo to each subcomponent + item.items.forEach((subItem) => { + if (!subItem.metadata) { + subItem.matchInfo = { matched: false } + return + } + + const subNameMatch = containsSearchTerm(subItem.metadata.name) + const subDescMatch = containsSearchTerm(subItem.metadata.description) + + if (subNameMatch || subDescMatch) { + subItem.matchInfo = { + matched: true, + matchReason: { + nameMatch: subNameMatch, + descriptionMatch: subDescMatch, + }, + } + } else { + subItem.matchInfo = { matched: false } + } + }) + } + + // Check if any subcomponents matched + const hasMatchingSubcomponents = item.items?.some((subItem) => subItem.matchInfo?.matched) ?? false + + // Set package matchInfo + item.matchInfo = { + matched: nameMatch || descMatch || hasMatchingSubcomponents, + matchReason: { + nameMatch, + descriptionMatch: descMatch, + hasMatchingSubcomponents, + }, + } + + // Only keep package if it or its subcomponents match the search term + const packageMatches = nameMatch || descMatch + const subcomponentMatches = hasMatchingSubcomponents + return packageMatches || subcomponentMatches + } + + // No filters, everything matches + item.matchInfo = { matched: true } + if (item.items) { + item.items.forEach((subItem) => { + subItem.matchInfo = { matched: true } + }) + } + return true + } + + // For non-packages + if (filters.type && item.type !== filters.type) { + return false + } + if (searchTerm) { + return containsSearchTerm(item.name) || containsSearchTerm(item.description) + } + return true + }) +} +``` + +## Benefits of the Proposed Changes + +1. **Consistent User Experience**: Type filters and search terms will behave consistently for packages and their subcomponents. + +2. **Improved Discoverability**: Users will be able to find packages that contain components of a specific type, even if the package itself is not of that type. + +3. **Better Visual Feedback**: The UI will show which subcomponents match the type filter, making it easier for users to understand why a package is included in the results. + +4. **Minimal Code Changes**: The proposed changes maintain the existing structure and logic, only modifying the type filter behavior to be more consistent with the search term behavior. + +5. **No Regressions**: The changes are focused on the type filter logic for packages only, leaving the rest of the filtering logic unchanged. + +## Testing Strategy + +To ensure the changes work correctly and don't introduce regressions, we should: + +1. **Unit Tests**: Update existing unit tests for the `filterItems` method to cover the new behavior. + +2. **Integration Tests**: Test the filtering functionality with real data to ensure it works as expected. + +3. **UI Tests**: Verify that the UI correctly displays which subcomponents match the type filter. + +4. **Regression Tests**: Ensure that other filtering functionality (search terms, tags) still works correctly. + +## Implementation Plan + +1. Update the `filterItems` method in `PackageManagerManager.ts` with the proposed changes. +2. Update unit tests to cover the new behavior. +3. Test the changes with real data to ensure they work as expected. +4. Update documentation to reflect the new behavior. diff --git a/cline_docs/package-manager/implementation/type-filter-test-plan.md b/cline_docs/package-manager/implementation/type-filter-test-plan.md new file mode 100644 index 0000000000..981eb66962 --- /dev/null +++ b/cline_docs/package-manager/implementation/type-filter-test-plan.md @@ -0,0 +1,190 @@ +# Type Filter Test Plan for Package Manager + +This document outlines the test plan for the proposed improvements to the type filtering functionality in the Package Manager. + +## Unit Tests + +### 1. Basic Type Filtering Tests + +#### Test: Filter by Package Type + +- **Input**: Items with various types including "package" +- **Filter**: `{ type: "package" }` +- **Expected**: Only items with type "package" are returned +- **Verification**: Check that the returned items all have type "package" + +#### Test: Filter by Mode Type + +- **Input**: Items with various types including "mode" +- **Filter**: `{ type: "mode" }` +- **Expected**: Only items with type "mode" are returned +- **Verification**: Check that the returned items all have type "mode" + +#### Test: Filter by MCP Server Type + +- **Input**: Items with various types including "mcp server" +- **Filter**: `{ type: "mcp server" }` +- **Expected**: Only items with type "mcp server" are returned +- **Verification**: Check that the returned items all have type "mcp server" + +### 2. Package with Subcomponents Tests + +#### Test: Package with Matching Subcomponents + +- **Input**: A package with subcomponents of various types +- **Filter**: `{ type: "mode" }` +- **Expected**: The package is returned if it contains at least one subcomponent with type "mode" +- **Verification**: + - Check that the package is returned + - Check that `item.matchInfo.matched` is `true` + - Check that `item.matchInfo.matchReason.hasMatchingSubcomponents` is `true` + - Check that subcomponents with type "mode" have `subItem.matchInfo.matched` set to `true` + - Check that subcomponents with other types have `subItem.matchInfo.matched` set to `false` + +#### Test: Package with No Matching Subcomponents + +- **Input**: A package with subcomponents of various types, but none matching the filter +- **Filter**: `{ type: "prompt" }` +- **Expected**: The package is not returned +- **Verification**: Check that the package is not in the returned items + +#### Test: Package with No Subcomponents + +- **Input**: A package with no subcomponents +- **Filter**: `{ type: "mode" }` +- **Expected**: The package is not returned (since it's not a mode and has no subcomponents) +- **Verification**: Check that the package is not in the returned items + +### 3. Combined Filtering Tests + +#### Test: Type Filter and Search Term + +- **Input**: Various items including packages with subcomponents +- **Filter**: `{ type: "mode", search: "test" }` +- **Expected**: Only items that match both the type filter and the search term are returned +- **Verification**: + - Check that all returned items have type "mode" or are packages with mode subcomponents + - Check that all returned items have "test" in their name or description, or have subcomponents with "test" in their name or description + +#### Test: Type Filter and Tags + +- **Input**: Various items with different tags +- **Filter**: `{ type: "mode", tags: ["test"] }` +- **Expected**: Only items that match both the type filter and have the "test" tag are returned +- **Verification**: Check that all returned items have type "mode" or are packages with mode subcomponents, and have the "test" tag + +## Integration Tests + +### 1. UI Display Tests + +#### Test: Type Filter UI Updates + +- **Action**: Apply a type filter in the UI +- **Expected**: + - The UI shows only items that match the filter + - For packages, subcomponents that match the filter are highlighted or marked in some way +- **Verification**: Visually inspect the UI to ensure it correctly displays which items and subcomponents match the filter + +#### Test: Type Filter and Search Combination + +- **Action**: Apply both a type filter and a search term in the UI +- **Expected**: The UI shows only items that match both the type filter and the search term +- **Verification**: Visually inspect the UI to ensure it correctly displays which items match both filters + +### 2. Real Data Tests + +#### Test: Filter with Real Package Data + +- **Input**: Real package data from the default package source +- **Action**: Apply various type filters +- **Expected**: The results match the expected behavior for each filter +- **Verification**: Check that the results are consistent with the expected behavior + +## Regression Tests + +### 1. Search Term Filtering + +#### Test: Search Term Only + +- **Input**: Various items including packages with subcomponents +- **Filter**: `{ search: "test" }` +- **Expected**: The behavior is unchanged from before the type filter improvements +- **Verification**: Compare the results with the expected behavior from the previous implementation + +### 2. Tag Filtering + +#### Test: Tag Filter Only + +- **Input**: Various items with different tags +- **Filter**: `{ tags: ["test"] }` +- **Expected**: The behavior is unchanged from before the type filter improvements +- **Verification**: Compare the results with the expected behavior from the previous implementation + +### 3. No Filters + +#### Test: No Filters Applied + +- **Input**: Various items +- **Filter**: `{}` +- **Expected**: All items are returned +- **Verification**: Check that all items are returned and that their `matchInfo` properties are set correctly + +## Edge Cases + +### 1. Empty Input + +#### Test: Empty Items Array + +- **Input**: Empty array +- **Filter**: `{ type: "mode" }` +- **Expected**: Empty array is returned +- **Verification**: Check that an empty array is returned + +### 2. Invalid Filters + +#### Test: Invalid Type + +- **Input**: Various items +- **Filter**: `{ type: "invalid" as ComponentType }` +- **Expected**: No items are returned (since none match the invalid type) +- **Verification**: Check that an empty array is returned + +### 3. Null or Undefined Values + +#### Test: Null Subcomponents + +- **Input**: A package with `items: null` +- **Filter**: `{ type: "mode" }` +- **Expected**: The package is not returned (since it has no subcomponents to match) +- **Verification**: Check that the package is not in the returned items + +#### Test: Undefined Metadata + +- **Input**: A package with subcomponents that have `metadata: undefined` +- **Filter**: `{ type: "mode" }` +- **Expected**: The package is returned if any subcomponents have type "mode" +- **Verification**: Check that the package is returned if appropriate and that subcomponents with undefined metadata are handled correctly + +## Performance Tests + +### 1. Large Dataset + +#### Test: Filter Large Dataset + +- **Input**: A large number of items (e.g., 1000+) +- **Filter**: Various filters +- **Expected**: The filtering completes in a reasonable time +- **Verification**: Measure the time taken to filter the items and ensure it's within acceptable limits + +### 2. Deep Nesting + +#### Test: Deeply Nested Packages + +- **Input**: Packages with deeply nested subcomponents +- **Filter**: Various filters +- **Expected**: The filtering correctly handles the nested structure +- **Verification**: Check that the results are correct for deeply nested structures + +## Conclusion + +This test plan covers the basic functionality, edge cases, and potential regressions for the proposed type filter improvements. By executing these tests, we can ensure that the changes work correctly and don't introduce any regressions. diff --git a/cline_docs/package-manager/user-guide/03-searching-and-filtering.md b/cline_docs/package-manager/user-guide/03-searching-and-filtering.md index 434e40f62c..ab9d00b706 100644 --- a/cline_docs/package-manager/user-guide/03-searching-and-filtering.md +++ b/cline_docs/package-manager/user-guide/03-searching-and-filtering.md @@ -39,11 +39,11 @@ The search uses a simple string contains match that is case and whitespace insen ### Example Searches -| Search Term | Will Find | -|-------------|-----------| -| "data" | Components with "data" in their name, description, or subcomponents | -| "validator" | Components that include validation functionality or have validator subcomponents | -| "machine learning" | Components related to machine learning technology | +| Search Term | Will Find | +| ------------------ | -------------------------------------------------------------------------------- | +| "data" | Components with "data" in their name, description, or subcomponents | +| "validator" | Components that include validation functionality or have validator subcomponents | +| "machine learning" | Components related to machine learning technology | ## Filtering by Package Type @@ -62,9 +62,16 @@ The type filter allows you to focus on specific categories of components: 2. Select multiple types to show components that match any of the selected types 3. Clear all type filters to show all components again +When filtering by type, packages are handled specially: + +- A package will be included if it matches the selected type +- A package will also be included if it contains any subcomponents matching the selected type +- When viewing a package that was included due to its subcomponents, the matching subcomponents will be highlighted + ### Type Filter Behavior -- Type filters apply to the primary component type, not subcomponents +- Type filters apply to both the primary component type and subcomponents +- Packages are included if they contain subcomponents matching the selected type - The type is displayed as a badge on each package card - Type filtering can be combined with search terms and tag filters @@ -104,11 +111,12 @@ For the most precise results, you can combine search terms, type filters, and ta ### Combined Filter Examples -| Search Term | Type Filter | Tag Filter | Will Find | -|-------------|-------------|------------|-----------| -| "data" | MCP Server | "analytics" | MCP Servers related to data analytics | -| "test" | Mode | "automation", "quality" | Test automation or quality-focused modes | -| "visualization" | Package | "dashboard", "chart" | Packages for creating dashboards or charts | +| Search Term | Type Filter | Tag Filter | Will Find | +| --------------- | ----------- | ----------------------- | ---------------------------------------------------- | +| "data" | MCP Server | "analytics" | MCP Servers related to data analytics | +| "test" | Mode | "automation", "quality" | Test automation or quality-focused modes | +| "visualization" | Package | "dashboard", "chart" | Packages for creating dashboards or charts | +| "" | Mode | "" | All modes and packages containing mode subcomponents | ### Clearing Filters @@ -129,4 +137,4 @@ The Package Manager provides visual feedback about your current filters: --- -**Previous**: [Browsing Packages](./02-browsing-packages.md) | **Next**: [Working with Package Details](./04-working-with-details.md) \ No newline at end of file +**Previous**: [Browsing Packages](./02-browsing-packages.md) | **Next**: [Working with Package Details](./04-working-with-details.md) diff --git a/cline_docs/package-manager/user-guide/04-working-with-details.md b/cline_docs/package-manager/user-guide/04-working-with-details.md index 460b997519..4e06822f24 100644 --- a/cline_docs/package-manager/user-guide/04-working-with-details.md +++ b/cline_docs/package-manager/user-guide/04-working-with-details.md @@ -118,8 +118,9 @@ When a subcomponent matches your search: The search uses a simple string contains match that is case-insensitive: - "validator" will match "Data Validator", "Validator Tool", etc. -- "valid" will match "validation", "validator", etc. -- The search will match any part of the name or description +- "valid" will match "validation" or "validator" +- validator will not match "validation" +- The search will match any part of the name or description that contains the exact search term ### Example Scenario @@ -127,7 +128,7 @@ If you search for "validator": 1. Packages containing components with "validator" in their name or description remain visible 2. The details section expands automatically for packages with matching subcomponents -3. Components like "Data Validator" or those with "validation" in their description are highlighted +3. Components like "Data Validator" or those with "validator" in their description are highlighted 4. A badge might show "2 matches" if two subcomponents match your search term ### Benefits of Subcomponent Matching diff --git a/cline_docs/package-manager/user-guide/05-adding-packages.md b/cline_docs/package-manager/user-guide/05-adding-packages.md index 58d7812278..c1fc61c1d7 100644 --- a/cline_docs/package-manager/user-guide/05-adding-packages.md +++ b/cline_docs/package-manager/user-guide/05-adding-packages.md @@ -1,6 +1,269 @@ +# Adding Packages + +This guide explains how to create and contribute your own packages to the Roo Code Package Manager. By following these steps, you can share your components with the community and help expand the ecosystem. + +## Package Structure and Metadata + +Each package in the Package Manager requires specific metadata files and follows a consistent directory structure. + +### Directory Structure + +The basic structure for a package is: + +``` +package-name/ +├── metadata.en.yml # Required metadata file (English) +├── metadata.fr.yml # Optional localized metadata (French) +├── README.md # Documentation for the package +├── modes/ # Directory for mode components +│ └── my-mode/ +│ └── metadata.en.yml +├── mcp servers/ # Directory for MCP server components +│ └── my-server/ +│ └── metadata.en.yml +└── prompts/ # Directory for prompt components + └── my-prompt/ + └── metadata.en.yml +``` + +### Metadata File Format + +Metadata files use YAML format and must include specific fields: + +```yaml +name: "My Package" +description: "A detailed description of what this package does" +version: "1.0.0" +type: "package" # One of: package, mode, mcp server, prompt +tags: + - tag1 + - tag2 +items: # Only for packages AND when a subcomponent isn't located in the packages directory tree + - type: "prompt" + path: "../shared-prompts/data-analysis" # Reference to component outside package directory +``` + +### Package Example in Source Tree + +Here's how a package might look in the actual source tree: + +``` +Roo-Code-Packages/ +├── shared-prompts/ # Shared prompts directory +│ └── data-analysis/ +│ └── metadata.en.yml +│ +└── data-toolkit/ # Your package directory + ├── metadata.en.yml # Package metadata + ├── metadata.fr.yml # Localized metadata + ├── README.md # Documentation + ├── modes/ # Modes directory + │ └── data-analyst/ + │ └── metadata.en.yml + └── mcp servers/ # MCP servers directory + └── data-processor/ + └── metadata.en.yml +``` + +### Required Fields + +- **name**: A clear, descriptive name for your component +- **description**: A detailed explanation of what your component does +- **version**: Semantic version number (e.g., "1.0.0") +- **type**: Component type (one of: "package", "mode", "mcp server", "prompt") +- **tags**: (Optional) Array of relevant tags for filtering +- **items**: (Only for packages) Array of subcomponents with their type and path - when the path is not in the packages directory tree + +### The Items Array and External References + +The `items` array in a package's metadata serves only one important purposes: + +**External Component References**: It allows referencing components that exist outside the package's directory tree. + +Components that are within the package's directory tree are implicitly included and will be found at runtime. + +#### Referencing External Components + +You can reference components from anywhere in the repository by using relative paths: + +```yaml +items: + # Component within the package directory + - type: "mode" + path: "modes/my-mode" + + # Component outside the package directory (using relative path) + - type: "prompt" + path: "../shared-prompts/data-analysis" + + # Component from a completely different part of the repository + - type: "mcp server" + path: "../../other-category/useful-server" +``` + +This allows you to: + +- Create shared components that can be used by multiple packages +- Organize components logically while maintaining package relationships +- Reference existing components without duplicating them + +#### How It Works + +- The `path` is relative to the package's directory +- The Package Manager resolves these paths when loading the package +- Components referenced this way appear as part of the package in the UI +- The same component can be included in multiple packages + +### Localization Support + +You can provide metadata in multiple languages by using locale-specific files: + **Important Notes on Localization:** + - Only files with the pattern `metadata.{locale}.yml` are supported - The Package Manager will display metadata in the user's locale if available - If the user's locale is not available, it will fall back to English - The English locale (`metadata.en.yml`) is required as a fallback -- Files without a locale code (e.g., just `metadata.yml`) are not supported \ No newline at end of file +- Files without a locale code (e.g., just `metadata.yml`) are not supported + +## Contributing Process + +To contribute your package to the official repository, follow these steps: + +### 1. Fork the Repository + +1. Visit the official Roo Code Packages repository: [https://github.com/RooVetGit/Roo-Code-Packages](https://github.com/RooVetGit/Roo-Code-Packages) +2. Click the "Fork" button in the top-right corner +3. This creates your own copy of the repository where you can make changes + +### 2. Clone Your Fork + +Clone your forked repository to your local machine: + +```bash +git clone https://github.com/YOUR-USERNAME/Roo-Code-Packages.git +cd Roo-Code-Packages +``` + +### 3. Create Your Package + +1. Create a new directory for your package with an appropriate name +2. Add the required metadata files and component directories +3. Follow the structure and format described above +4. Add documentation in a README.md file + +Example of creating a simple package: + +```bash +mkdir -p my-package/modes/my-mode +touch my-package/metadata.en.yml +touch my-package/README.md +touch my-package/modes/my-mode/metadata.en.yml +``` + +### 4. Test Your Package + +Before submitting, test your package by adding your fork as a custom source in the Package Manager: + +1. In VS Code, open the Package Manager +2. Go to the "Settings" tab +3. Click "Add Source" +4. Enter your fork's URL (e.g., `https://github.com/YOUR-USERNAME/Roo-Code-Packages`) +5. Click "Add" +6. Verify that your package appears and functions correctly + +### 5. Commit and Push Your Changes + +Once you're satisfied with your package: + +```bash +git add . +git commit -m "Add my-package with mode component" +git push origin main +``` + +### 6. Create a Pull Request + +1. Go to the original repository: [https://github.com/RooVetGit/Roo-Code-Packages](https://github.com/RooVetGit/Roo-Code-Packages) +2. Click "Pull Requests" and then "New Pull Request" +3. Click "Compare across forks" +4. Select your fork as the head repository +5. Click "Create Pull Request" +6. Provide a clear title and description of your package +7. Submit the pull request + +### 7. Review Process + +After submitting your pull request: + +1. Maintainers will review your package +2. They may request changes or improvements +3. Once approved, your package will be merged into the main repository +4. Your package will be available to all users of the Package Manager + +## Best Practices + +- **Clear Documentation**: Include detailed documentation in your README.md +- **Descriptive Metadata**: Write clear, informative descriptions +- **Appropriate Tags**: Use relevant tags to make your package discoverable +- **Testing**: Thoroughly test your package before submitting +- **Localization**: Consider providing metadata in multiple languages +- **Semantic Versioning**: Follow semantic versioning for version numbers +- **Consistent Naming**: Use clear, descriptive names for components + +## Example Package + +Here's a comprehensive example of a data science package that includes both internal components and references to external components: + +**data-science-toolkit/metadata.en.yml**: + +```yaml +name: "Data Science Toolkit" +description: "A comprehensive collection of tools for data science workflows" +version: "1.0.0" +type: "package" +tags: + - data + - science + - analysis + - visualization + - machine learning +items: + # External components (outside this package directory) + - type: "prompt" + path: "../shared-prompts/data-cleaning" + - type: "mcp server" + path: "../../ml-tools/model-trainer" + - type: "mode" + path: "../visualization-tools/chart-creator-mode" +``` + +**data-science-toolkit/modes/data-scientist-mode/metadata.en.yml**: + +```yaml +name: "Data Scientist Mode" +description: "A specialized mode for data science tasks" +version: "1.0.0" +type: "mode" +tags: + - data + - science + - analysis +``` + +**shared-prompts/data-cleaning/metadata.en.yml**: + +```yaml +name: "Data Cleaning Prompt" +description: "A prompt for cleaning and preprocessing datasets" +version: "1.0.0" +type: "prompt" +tags: + - data + - cleaning + - preprocessing +``` + +--- + +**Previous**: [Working with Package Details](./04-working-with-details.md) | **Next**: [Adding Custom Sources](./06-adding-custom-sources.md) diff --git a/cline_docs/package-manager/user-guide/06-adding-custom-sources.md b/cline_docs/package-manager/user-guide/06-adding-custom-sources.md index 951cdfb78e..d5386e59c6 100644 --- a/cline_docs/package-manager/user-guide/06-adding-custom-sources.md +++ b/cline_docs/package-manager/user-guide/06-adding-custom-sources.md @@ -84,8 +84,8 @@ description: "A collection of specialized components for data science workflows" version: "1.0.0" author: "Your Name or Organization" tags: - - custom - - data-science + - custom + - data-science ``` ### Component Organization @@ -102,9 +102,9 @@ Once you have a properly structured package source repository, you can add it to ### Default Package Source Roo Code comes with a default package source: + - URL: `https://github.com/RooVetGit/Roo-Code-Packages` -- Name: "Roo Code Package Manager Template" -- This source is enabled by default +- This source is enabled by default, and anytime all sources have been deleted. ### Adding a New Source @@ -113,18 +113,16 @@ Roo Code comes with a default package source: 3. Switch to the "Sources" tab 4. Click the "Add Source" button 5. Enter the repository URL: - - Format: `https://github.com/username/repository.git` - - Example: `https://github.com/your-username/your-package-repo.git` + - Format: `https://github.com/username/repository.git` + - Example: `https://github.com/your-username/your-package-repo.git` 6. Click "Add" to save the source ### Managing Sources The "Sources" tab provides several options for managing your package sources: -1. **Enable/Disable**: Toggle sources on or off without removing them -2. **Remove**: Delete a source from your configuration -3. **Refresh**: Update the package list from all enabled sources -4. **View Details**: See information about each source +1. **Remove**: Delete a source from your configuration +2. **Refresh**: Update the package list from a sources - this is forced git clone/pull to override local caching of data ### Source Caching and Refreshing @@ -132,9 +130,9 @@ Package Manager sources are cached to improve performance: - **Cache Duration**: Sources are cached for 1 hour (3600000 ms) - **Force Refresh**: To force an immediate refresh of a source: - 1. Go to the "Sources" tab - 2. Click the "Refresh" button next to the source you want to update - 3. This will bypass the cache and fetch the latest data from the repository + 1. Go to the "Sources" tab + 2. Click the "Refresh" button next to the source you want to update + 3. This will bypass the cache and fetch the latest data from the repository ### Troubleshooting Sources @@ -190,9 +188,8 @@ The Package Manager supports multiple package sources simultaneously: 1. Keep the default source enabled for core components 2. Add specialized sources for specific needs 3. Create a personal source for testing and development -4. Disable sources temporarily when not needed -5. Regularly update sources to get the latest components +4. Refresh sources after you've pushed changes to them to get the latest components --- -**Previous**: [Adding Packages](./05-adding-packages.md) | **Next**: [Package Manager Architecture](../implementation/01-architecture.md) \ No newline at end of file +**Previous**: [Adding Packages](./05-adding-packages.md) | **Next**: [Package Manager Architecture](../implementation/01-architecture.md) diff --git a/src/services/package-manager/PackageManagerManager.ts b/src/services/package-manager/PackageManagerManager.ts index 31802786eb..9a3edad0a5 100644 --- a/src/services/package-manager/PackageManagerManager.ts +++ b/src/services/package-manager/PackageManagerManager.ts @@ -274,32 +274,40 @@ export class PackageManagerManager { return filteredItems.filter((item) => { // For packages, handle differently based on filters if (item.type === "package") { - // If we have a type filter that's not "package" - if (filters.type && filters.type !== "package") { - // Only keep packages that have at least one matching subcomponent - if (!item.items) return false + // If we have a type filter + if (filters.type) { + // Check if the package itself matches the type filter + const packageTypeMatch = item.type === filters.type - // Mark subcomponents with matchInfo based on type - item.items.forEach((subItem) => { - subItem.matchInfo = { - matched: subItem.type === filters.type, - } - }) + // Check subcomponents if they exist + let hasMatchingSubcomponents = false + if (item.items && item.items.length > 0) { + // Mark subcomponents with matchInfo based on type + item.items.forEach((subItem) => { + const subTypeMatch = subItem.type === filters.type + subItem.matchInfo = { + matched: subTypeMatch, + matchReason: { + typeMatch: subTypeMatch, + }, + } + }) - // Keep package if it has any matching subcomponents - const hasMatchingType = item.items.some((subItem) => subItem.type === filters.type) + // Check if any subcomponents match + hasMatchingSubcomponents = item.items.some((subItem) => subItem.matchInfo?.matched) + } // Set package matchInfo item.matchInfo = { - matched: hasMatchingType, + matched: packageTypeMatch || hasMatchingSubcomponents, matchReason: { - nameMatch: false, - descriptionMatch: false, - hasMatchingSubcomponents: hasMatchingType, + typeMatch: packageTypeMatch, + hasMatchingSubcomponents, }, } - return hasMatchingType + // Keep package if it or any of its subcomponents match the type filter + return packageTypeMatch || hasMatchingSubcomponents } // For search term diff --git a/src/services/package-manager/__tests__/CombinedFeatures.test.ts b/src/services/package-manager/__tests__/CombinedFeatures.test.ts new file mode 100644 index 0000000000..1fc4618ce3 --- /dev/null +++ b/src/services/package-manager/__tests__/CombinedFeatures.test.ts @@ -0,0 +1,94 @@ +import { PackageManagerManager } from "../PackageManagerManager" +import { ComponentType, PackageManagerItem } from "../types" +import * as vscode from "vscode" + +// Mock vscode +jest.mock("vscode") + +describe("Combined Features", () => { + let packageManagerManager: PackageManagerManager + let mockContext: vscode.ExtensionContext + + beforeEach(() => { + mockContext = { + globalStorageUri: { fsPath: "/test/path" }, + } as unknown as vscode.ExtensionContext + + packageManagerManager = new PackageManagerManager(mockContext) + }) + + describe("Type Filter and Localization", () => { + test("should work together correctly", () => { + // This test verifies that the type filter and localization changes work together + // Since we can't easily test the actual localization in a unit test, + // we're just verifying that the type filter works correctly + + // Create test items + const testItems: PackageManagerItem[] = [ + { + name: "Test Package", + description: "A test package", + type: "package", + url: "test/package", + repoUrl: "https://example.com", + items: [ + { + type: "mode", + path: "test/mode", + metadata: { + name: "Test Mode", + description: "A test mode", + version: "1.0.0", + type: "mode", + }, + }, + { + type: "mcp server", + path: "test/server", + metadata: { + name: "Test Server", + description: "A test server", + version: "1.0.0", + type: "mcp server", + }, + }, + ], + }, + { + name: "Test Mode", + description: "A standalone test mode", + type: "mode", + url: "test/standalone-mode", + repoUrl: "https://example.com", + }, + ] + + // Filter by mode type + const filtered = packageManagerManager.filterItems(testItems, { type: "mode" }) + + // Should include both the package (because it has a mode subcomponent) and the standalone mode + expect(filtered.length).toBe(2) + + // Check the package + const packageItem = filtered.find((item) => item.type === "package") + expect(packageItem).toBeDefined() + expect(packageItem?.matchInfo?.matched).toBe(true) + expect(packageItem?.matchInfo?.matchReason?.typeMatch).toBe(false) + expect(packageItem?.matchInfo?.matchReason?.hasMatchingSubcomponents).toBe(true) + + // Check that the mode subcomponent is marked as matched + const modeSubcomponent = packageItem?.items?.find((item) => item.type === "mode") + expect(modeSubcomponent).toBeDefined() + expect(modeSubcomponent?.matchInfo?.matched).toBe(true) + + // Check that the server subcomponent is not marked as matched + const serverSubcomponent = packageItem?.items?.find((item) => item.type === "mcp server") + expect(serverSubcomponent).toBeDefined() + expect(serverSubcomponent?.matchInfo?.matched).toBe(false) + + // Check the standalone mode + const modeItem = filtered.find((item) => item.type === "mode") + expect(modeItem).toBeDefined() + }) + }) +}) diff --git a/src/services/package-manager/__tests__/TypeFilterBehavior.test.ts b/src/services/package-manager/__tests__/TypeFilterBehavior.test.ts new file mode 100644 index 0000000000..e3a9b55207 --- /dev/null +++ b/src/services/package-manager/__tests__/TypeFilterBehavior.test.ts @@ -0,0 +1,216 @@ +import { PackageManagerManager } from "../PackageManagerManager" +import { ComponentType, PackageManagerItem } from "../types" +import * as vscode from "vscode" + +// Mock vscode +jest.mock("vscode") + +describe("Type Filter Behavior", () => { + let packageManagerManager: PackageManagerManager + let mockContext: vscode.ExtensionContext + + beforeEach(() => { + mockContext = { + globalStorageUri: { fsPath: "/test/path" }, + } as unknown as vscode.ExtensionContext + + packageManagerManager = new PackageManagerManager(mockContext) + }) + + describe("Package with Subcomponents", () => { + let testItems: PackageManagerItem[] + + beforeEach(() => { + // Create test items + testItems = [ + { + name: "Test Package", + description: "A test package", + type: "package", + url: "test/package", + repoUrl: "https://example.com", + items: [ + { + type: "mode", + path: "test/mode", + metadata: { + name: "Test Mode", + description: "A test mode", + version: "1.0.0", + type: "mode", + }, + }, + { + type: "mcp server", + path: "test/server", + metadata: { + name: "Test Server", + description: "A test server", + version: "1.0.0", + type: "mcp server", + }, + }, + ], + }, + { + name: "Test Mode", + description: "A standalone test mode", + type: "mode", + url: "test/standalone-mode", + repoUrl: "https://example.com", + }, + ] + }) + + test("should include package when filtering by its own type", () => { + // Filter by package type + const filtered = packageManagerManager.filterItems(testItems, { type: "package" }) + + // Should include the package + expect(filtered.length).toBe(1) + expect(filtered[0].name).toBe("Test Package") + expect(filtered[0].matchInfo?.matched).toBe(true) + expect(filtered[0].matchInfo?.matchReason?.typeMatch).toBe(true) + }) + + test("should include package when filtering by subcomponent type", () => { + // Filter by mode type + const filtered = packageManagerManager.filterItems(testItems, { type: "mode" }) + + // Should include both the package (because it has a mode subcomponent) and the standalone mode + expect(filtered.length).toBe(2) + + // Check the package + const packageItem = filtered.find((item) => item.type === "package") + expect(packageItem).toBeDefined() + expect(packageItem?.matchInfo?.matched).toBe(true) + expect(packageItem?.matchInfo?.matchReason?.typeMatch).toBe(false) + expect(packageItem?.matchInfo?.matchReason?.hasMatchingSubcomponents).toBe(true) + + // Check that the mode subcomponent is marked as matched + const modeSubcomponent = packageItem?.items?.find((item) => item.type === "mode") + expect(modeSubcomponent).toBeDefined() + expect(modeSubcomponent?.matchInfo?.matched).toBe(true) + + // Check that the server subcomponent is not marked as matched + const serverSubcomponent = packageItem?.items?.find((item) => item.type === "mcp server") + expect(serverSubcomponent).toBeDefined() + expect(serverSubcomponent?.matchInfo?.matched).toBe(false) + + // Check the standalone mode + const modeItem = filtered.find((item) => item.type === "mode") + expect(modeItem).toBeDefined() + }) + + test("should not include package when filtering by type with no matching subcomponents", () => { + // Create a package with no matching subcomponents + const noMatchPackage: PackageManagerItem = { + name: "No Match Package", + description: "A package with no matching subcomponents", + type: "package", + url: "test/no-match", + repoUrl: "https://example.com", + items: [ + { + type: "prompt", + path: "test/prompt", + metadata: { + name: "Test Prompt", + description: "A test prompt", + version: "1.0.0", + type: "prompt", + }, + }, + ], + } + + // Filter by mode type + const filtered = packageManagerManager.filterItems([noMatchPackage], { type: "mode" }) + + // Should not include the package + expect(filtered.length).toBe(0) + }) + + test("should handle package with no subcomponents", () => { + // Create a package with no subcomponents + const noSubcomponentsPackage: PackageManagerItem = { + name: "No Subcomponents Package", + description: "A package with no subcomponents", + type: "package", + url: "test/no-subcomponents", + repoUrl: "https://example.com", + } + + // Filter by mode type + const filtered = packageManagerManager.filterItems([noSubcomponentsPackage], { type: "mode" }) + + // Should not include the package + expect(filtered.length).toBe(0) + }) + }) + + describe("Consistency with Search Term Behavior", () => { + let testItems: PackageManagerItem[] + + beforeEach(() => { + // Create test items + testItems = [ + { + name: "Test Package", + description: "A test package", + type: "package", + url: "test/package", + repoUrl: "https://example.com", + items: [ + { + type: "mode", + path: "test/mode", + metadata: { + name: "Test Mode", + description: "A test mode", + version: "1.0.0", + type: "mode", + }, + }, + ], + }, + ] + }) + + test("should behave consistently with search term for packages", () => { + // Filter by type + const typeFiltered = packageManagerManager.filterItems(testItems, { type: "package" }) + + // Filter by search term that matches the package + const searchFiltered = packageManagerManager.filterItems(testItems, { search: "test package" }) + + // Both should include the package + expect(typeFiltered.length).toBe(1) + expect(searchFiltered.length).toBe(1) + + // Both should mark the package as matched + expect(typeFiltered[0].matchInfo?.matched).toBe(true) + expect(searchFiltered[0].matchInfo?.matched).toBe(true) + }) + + test("should behave consistently with search term for subcomponents", () => { + // Filter by type that matches a subcomponent + const typeFiltered = packageManagerManager.filterItems(testItems, { type: "mode" }) + + // Filter by search term that matches a subcomponent + const searchFiltered = packageManagerManager.filterItems(testItems, { search: "test mode" }) + + // Both should include the package + expect(typeFiltered.length).toBe(1) + expect(searchFiltered.length).toBe(1) + + // Both should mark the package as matched + expect(typeFiltered[0].matchInfo?.matched).toBe(true) + expect(searchFiltered[0].matchInfo?.matched).toBe(true) + + // Both should mark the subcomponent as matched + expect(typeFiltered[0].items?.[0].matchInfo?.matched).toBe(true) + expect(searchFiltered[0].items?.[0].matchInfo?.matched).toBe(true) + }) + }) +}) diff --git a/src/services/package-manager/types.ts b/src/services/package-manager/types.ts index e9f5529c7e..cf7bcd1e41 100644 --- a/src/services/package-manager/types.ts +++ b/src/services/package-manager/types.ts @@ -7,6 +7,7 @@ export interface MatchInfo { nameMatch?: boolean descriptionMatch?: boolean tagMatch?: boolean + typeMatch?: boolean hasMatchingSubcomponents?: boolean } }