diff --git a/src/renderer/src/components/native-chat/native-chat-composer-state.test.ts b/src/renderer/src/components/native-chat/native-chat-composer-state.test.ts index 1cceead2fd7..8ff28afcb7b 100644 --- a/src/renderer/src/components/native-chat/native-chat-composer-state.test.ts +++ b/src/renderer/src/components/native-chat/native-chat-composer-state.test.ts @@ -456,6 +456,19 @@ describe('native skill and command picker', () => { expect(items[1]).toMatchObject({ kind: 'skill', description: null, sources: [] }) }) + it('keeps the first reported description for duplicate unlocated skill names', () => { + const items = buildNativeChatPickerItems([], [], '', '/', [ + { name: 'missing' }, + { name: 'missing', description: 'Later description' }, + { name: 'present', description: 'First description' }, + { name: 'present', description: 'Later description' } + ]) + expect(items).toMatchObject([ + { name: 'missing', description: null }, + { name: 'present', description: 'First description' } + ]) + }) + it('keeps the disk scan only when a session report is absent', () => { const items = buildNativeChatPickerItems( [], diff --git a/src/shared/native-chat-picker-items.ts b/src/shared/native-chat-picker-items.ts index 7402584ab1e..b82c16bd278 100644 --- a/src/shared/native-chat-picker-items.ts +++ b/src/shared/native-chat-picker-items.ts @@ -156,7 +156,9 @@ function mergeNativeChatSkills( if (!safeName) { continue } - byName.set(safeName, [...(byName.get(safeName) ?? []), { ...skill, name: safeName }]) + const namedSkills = byName.get(safeName) ?? [] + namedSkills.push({ ...skill, name: safeName }) + byName.set(safeName, namedSkills) } const discovered = new Map( [...byName.entries()].map(([name, namedSkills]) => [ @@ -172,8 +174,12 @@ function mergeNativeChatSkills( // A reported skill with its file is its own row: two skills may share a name, and the pick // tells the agent which file it means. const nameCounts = new Map() + const firstReportedByName = new Map() for (const skill of sessionSkills ?? []) { nameCounts.set(skill.name, (nameCounts.get(skill.name) ?? 0) + 1) + if (!firstReportedByName.has(skill.name)) { + firstReportedByName.set(skill.name, skill) + } } const located = (sessionSkills ?? []).flatMap((skill) => skill.path && isTokenSafe(skill.name) @@ -202,7 +208,7 @@ function mergeNativeChatSkills( ...located, ...[...new Set(names)].map((name) => { const skill = discovered.get(name) ?? pickerSkill(name, [], skillSigil) - const reported = sessionSkills?.find((entry) => entry.name === name)?.description + const reported = firstReportedByName.get(name)?.description return skill.description === null && reported ? { ...skill, description: sanitizePickerText(reported, 240) } : skill