feat: 按实际生效标签归类分类 + 保留手动分类归属 - #264
Conversation
…tegories Implements issue #262 by introducing a new 'effective' category matching mode (default) that ranks repositories using the same tags shown on cards (custom_tags > ai_tags > topics) instead of only ai_tags. - add getEffectiveTags() and a mode-aware matchesCategory() - persist categoryMatchMode (default 'effective') with a settings radio - resolveCategoryAssignment: preserve manually assigned/cleared custom categories from being overwritten by AI analysis; match custom category names by mutual substring - sidebars and category counts now honor the configured match mode
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds persisted ChangesCategory matching and analysis
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CategoryPanel
participant useAppStore
participant RepositoryList
participant AIAnalysisOptimizer
participant AIService
CategoryPanel->>useAppStore: setCategoryMatchMode(mode)
useAppStore-->>RepositoryList: categoryMatchMode
RepositoryList->>AIAnalysisOptimizer: analyzeRepositoriesPipelined(categoryHints)
AIAnalysisOptimizer->>AIService: analyzeRepository(categoryHints)
AIService-->>RepositoryList: categorized repository analysis
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/settings/CategoryPanel.tsx`:
- Around line 335-339: Update the descriptive copy near the mode-specific
category text in CategoryPanel so protection of manually assigned
custom_category values is stated independently of matching mode. Remove it from
effective-only wording or place it in shared mode-neutral copy, while preserving
the existing tag-source explanation.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1792ce6a-a6dc-4eed-b6b5-4be344131386
📒 Files selected for processing (7)
src/components/CategorySidebar.tsxsrc/components/RepositoryList.tsxsrc/components/settings/CategoryPanel.tsxsrc/store/useAppStore.tssrc/types/index.tssrc/utils/categoryUtils.test.tssrc/utils/categoryUtils.ts
Per CodeRabbit review: the resolveCategoryAssignment preservation applies regardless of matching mode, so the claim that manual assignments survive AI analysis should not be stated only under the effective-mode option.
|
Fixed per CodeRabbit review (commit adcf74f): moved the 'manually assigned categories are always kept' statement from the effective-mode description to the shared mode-neutral intro copy, since resolveCategoryAssignment preserves manual assignments in both modes. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/categoryUtils.ts (1)
138-140: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winUse the effective-tag contract in search paths.
Effective mode can classify a repository from
custom_tags.AIService.performEnhancedSearch,performBasicSearch, and the static fallback do not searchcustom_tags.performEnhancedBasicSearchsearches both tag sets without the priority rule.The same custom tag can therefore place a repository in a category but fail to find it in search. Route all search builders through
getEffectiveTags().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/categoryUtils.ts` around lines 138 - 140, The search builders performEnhancedSearch, performBasicSearch, performEnhancedBasicSearch, and the static fallback must use getEffectiveTags() whenever effective mode is active. Replace their direct or combined AI/custom tag collection with the helper’s result so searches follow the same priority contract as category matching, while preserving non-effective tag behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/utils/categoryUtils.ts`:
- Around line 229-232: Update the resolveCategoryAssignment calls in
RepositoryList, DiscoveryView, and aiAnalysisHelper to pass a repository copy
with ai_summary set to the current result.summary before metadata fallback runs.
Preserve existing repository fields and add a test covering a custom category
matched only by the newly generated summary.
- Around line 197-200: Update the custom-category matching logic in the category
utility to normalize keywords and exclude blank results before calling
repoText.includes, preventing whitespace-only keywords from matching every
repository. Preserve the existing category-name fallback for categories with no
valid keywords, and add a regression test covering keywords: [' '].
---
Outside diff comments:
In `@src/utils/categoryUtils.ts`:
- Around line 138-140: The search builders performEnhancedSearch,
performBasicSearch, performEnhancedBasicSearch, and the static fallback must use
getEffectiveTags() whenever effective mode is active. Replace their direct or
combined AI/custom tag collection with the helper’s result so searches follow
the same priority contract as category matching, while preserving non-effective
tag behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c4dffb02-5cf2-4243-acce-26cfafdedf0a
📒 Files selected for processing (7)
src/components/DiscoveryView.tsxsrc/components/RepositoryList.tsxsrc/services/aiAnalysisHelper.tssrc/services/aiAnalysisOptimizer.tssrc/services/aiService.tssrc/utils/categoryUtils.test.tssrc/utils/categoryUtils.ts
…ary, custom_tags search)
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/utils/categoryUtils.test.ts`:
- Around line 409-417: Update the test around buildCategoryHints to assert the
exact normalized hint string, rather than only checking that it contains Skill
and excludes partial patterns. Verify whitespace-only keywords are removed and
the resulting hint matches the expected value, so outputs retaining those
keywords fail.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ae3e1f1-c6d2-4b9a-a33a-86a5414bccba
📒 Files selected for processing (7)
src/components/DiscoveryView.tsxsrc/components/RepositoryList.tsxsrc/services/aiAnalysisHelper.tssrc/services/aiService.test.tssrc/services/aiService.tssrc/utils/categoryUtils.test.tssrc/utils/categoryUtils.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- src/components/DiscoveryView.tsx
- src/services/aiService.ts
- src/components/RepositoryList.tsx
- src/utils/categoryUtils.ts
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/services/aiService.test.ts (1)
86-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover the enhanced search path.
The tests cover static fallback search and basic search. The changed
performEnhancedSearchpath at Line [1451] is not exercised. Add one custom-tag-only query test for that path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/services/aiService.test.ts` around lines 86 - 114, Add a test in the AIService search tests that exercises the performEnhancedSearch method with a repository matching only through custom_tags and a custom-tag-only query. Assert that the matching repository is returned, following the existing static fallback and performBasicSearch test patterns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/DiscoveryView.tsx`:
- Around line 813-817: Update the Discovery analysis call to
resolveCategoryAssignment so it receives the complete active category list,
including built-in and custom categories, rather than only
allCategoriesForResolution derived from storeState.customCategories. Preserve
manually assigned built-in categories and keep the existing result update flow
unchanged.
In `@src/services/aiService.ts`:
- Around line 847-851: Update the custom prompt construction around customPrompt
and the {CATEGORIES_HINT} replacement so supplied categoryHints are preserved
even when the placeholder is absent. Keep placeholder replacement working when
present, and append or otherwise merge the sanitized hints only for prompts that
do not include {CATEGORIES_HINT}.
In `@src/utils/categoryUtils.ts`:
- Around line 8-15: Update getEffectiveTags to remove blank or whitespace-only
tags from custom_tags, ai_tags, and topics before selecting the first non-empty
source, preserving fallback to the next source when filtering leaves no tags.
Also update legacy-mode tag matching to ignore blank tags before
keyword.includes or category-name containment checks, and add regression tests
covering empty custom_tags and empty ai_tags.
---
Nitpick comments:
In `@src/services/aiService.test.ts`:
- Around line 86-114: Add a test in the AIService search tests that exercises
the performEnhancedSearch method with a repository matching only through
custom_tags and a custom-tag-only query. Assert that the matching repository is
returned, following the existing static fallback and performBasicSearch test
patterns.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b36df1fd-96d3-42d4-971a-291b86568eb9
📒 Files selected for processing (12)
src/components/CategorySidebar.tsxsrc/components/DiscoveryView.tsxsrc/components/RepositoryList.tsxsrc/components/settings/CategoryPanel.tsxsrc/services/aiAnalysisHelper.tssrc/services/aiAnalysisOptimizer.tssrc/services/aiService.test.tssrc/services/aiService.tssrc/store/useAppStore.tssrc/types/index.tssrc/utils/categoryUtils.test.tssrc/utils/categoryUtils.ts
…t, custom prompt hints)
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/categoryUtils.ts (1)
238-240: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift不要把 AI 自动生成的分类当作手动归属永久保留。
DiscoveryView会在分析成功后把resolvedCategory写回custom_category,即使category_locked为false。此处随后对任意有效的repository.custom_category直接返回。因此下一次分析不会检查新的aiTags,而matchesCategory也会在 Line 147-151 提前短路。重新分析或编辑
custom_tags后,分类可能仍停留在旧的 AI 分类。请使用明确的来源标记区分手动归属和 AI 归属,仅保留手动值,并增加两次分析及修改标签后的回归测试。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/categoryUtils.ts` around lines 238 - 240, 更新 categoryUtils 中基于 repository.custom_category 的保留逻辑,使用明确的来源标记区分手动分类与 DiscoveryView 写入的 AI 分类;仅在分类确实由用户手动设置(包括显式清空)时直接返回,否则重新依据 aiTags 计算。同步调整相关写入流程以维护该来源标记,并为重复分析及修改 custom_tags 后重新分类增加回归测试。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/utils/categoryUtils.ts`:
- Around line 238-240: 更新 categoryUtils 中基于 repository.custom_category
的保留逻辑,使用明确的来源标记区分手动分类与 DiscoveryView 写入的 AI 分类;仅在分类确实由用户手动设置(包括显式清空)时直接返回,否则重新依据
aiTags 计算。同步调整相关写入流程以维护该来源标记,并为重复分析及修改 custom_tags 后重新分类增加回归测试。
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 86d1bccf-b58d-4614-9d18-33a11228a9bb
📒 Files selected for processing (5)
src/components/DiscoveryView.tsxsrc/services/aiService.test.tssrc/services/aiService.tssrc/utils/categoryUtils.test.tssrc/utils/categoryUtils.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- src/services/aiService.test.ts
- src/components/DiscoveryView.tsx
- src/utils/categoryUtils.test.ts
- src/services/aiService.ts
…tegory Only a locked custom_category (manual) or explicit empty (cleared) is honored in category matching/assignment. Unlocked custom_category is an AI-analysis artifact, so it now falls through to tag/metadata matching and is recomputed on re-analysis instead of freezing the last result.
Closes #262
背景
matchesCategory()分类匹配只读取ai_tags,导致分类归属与卡片实际展示的标签不一致:custom_tags不参与分类匹配resolveCategoryAssignment返回undefined)变更
1. 新增
categoryMatchMode设置(默认effective)effective(推荐,默认):按卡片展示的标签归类custom_tags > ai_tags > topicslegacy:保留旧版仅按ai_tags归类2.
matchesCategory支持模式参数getEffectiveTags()与tagMatchesCategory()辅助函数effective模式下自定义分类额外支持分类名互相包含匹配(解决无关键词自定义分类无法命中)3.
resolveCategoryAssignment保留手动归属custom_category(含显式清空)不再被 AI 分析覆盖4. 自定义分类 metadata 兜底归类(新)
getRepoText()聚合仓库元数据(名称 / 描述 / 语言 / topics / AI 摘要)buildCategoryHints():生成自定义分类「名称 + 关键词」提示,注入 AI 分析提示词(中英文默认提示与{CATEGORIES_HINT}占位符),让模型在仓库无 Topics 时也能识别自定义分类resolveCategoryAssignment在 AI 标签为空或未命中自定义分类时,按仓库元数据关键词兜底匹配自定义分类(空关键词分类回退到分类名包含匹配)aiAnalysisHelper/aiAnalysisOptimizer(单仓、批量、Discovery 流水线)均透传 hints;提示词注入处统一经sanitizeForPrompt消毒5. 调用方
测试
categoryUtils.test.ts扩展到 26 个用例(有效标签优先级、自定义分类名匹配、归属保留、metadata 兜底、建 hints 等)vitest run187 个全部通过;tsc --noEmit通过;本次改动文件eslint通过Summary by CodeRabbit