source dump of claude code
at main 55 lines 1.9 kB view raw
1import { getGlobalConfig, saveGlobalConfig } from '../config.js' 2 3const SKILL_USAGE_DEBOUNCE_MS = 60_000 4 5// Process-lifetime debounce cache — avoids lock + read + parse on debounced 6// calls. Same pattern as lastConfigStatTime / globalConfigWriteCount in config.ts. 7const lastWriteBySkill = new Map<string, number>() 8 9/** 10 * Records a skill usage for ranking purposes. 11 * Updates both usage count and last used timestamp. 12 */ 13export function recordSkillUsage(skillName: string): void { 14 const now = Date.now() 15 const lastWrite = lastWriteBySkill.get(skillName) 16 // The ranking algorithm uses a 7-day half-life, so sub-minute granularity 17 // is irrelevant. Bail out before saveGlobalConfig to avoid lock + file I/O. 18 if (lastWrite !== undefined && now - lastWrite < SKILL_USAGE_DEBOUNCE_MS) { 19 return 20 } 21 lastWriteBySkill.set(skillName, now) 22 saveGlobalConfig(current => { 23 const existing = current.skillUsage?.[skillName] 24 return { 25 ...current, 26 skillUsage: { 27 ...current.skillUsage, 28 [skillName]: { 29 usageCount: (existing?.usageCount ?? 0) + 1, 30 lastUsedAt: now, 31 }, 32 }, 33 } 34 }) 35} 36 37/** 38 * Calculates a usage score for a skill based on frequency and recency. 39 * Higher scores indicate more frequently and recently used skills. 40 * 41 * The score uses exponential decay with a half-life of 7 days, 42 * meaning usage from 7 days ago is worth half as much as usage today. 43 */ 44export function getSkillUsageScore(skillName: string): number { 45 const config = getGlobalConfig() 46 const usage = config.skillUsage?.[skillName] 47 if (!usage) return 0 48 49 // Recency decay: halve score every 7 days 50 const daysSinceUse = (Date.now() - usage.lastUsedAt) / (1000 * 60 * 60 * 24) 51 const recencyFactor = Math.pow(0.5, daysSinceUse / 7) 52 53 // Minimum recency factor of 0.1 to avoid completely dropping old but heavily used skills 54 return usage.usageCount * Math.max(recencyFactor, 0.1) 55}