(input: SkillSuggestionInput)
| 112 | } |
| 113 | |
| 114 | export function suggestSkillFromSession(input: SkillSuggestionInput): SkillSuggestion { |
| 115 | const area = commonArea(input.changedFiles); |
| 116 | const n = input.changedFiles.length; |
| 117 | const multiFile = n >= 2 && n <= 12; // focused multi-file = a pattern, not a one-off or a sprawl |
| 118 | const focused = input.cohesion >= 0.6; // concentrated in one module / connected cluster |
| 119 | const verb = taskVerb(input.prompt); |
| 120 | const score = (multiFile ? 0.4 : 0) + (focused ? 0.3 : 0) + (verb ? 0.3 : 0); |
| 121 | // A skill is a cross-file pattern: multi-file is a hard gate (a one-file edit is never a skill). |
| 122 | const worth = multiFile && score >= 0.6; |
| 123 | const symbolsBit = input.touchedSymbols?.length ? ` touching ${input.touchedSymbols.slice(0, 3).join(', ')}` : ''; |
| 124 | const reason = worth |
| 125 | ? `A focused ${verb ?? 'change'} across ${n} file(s) in ${area || 'one area'}${symbolsBit} (cohesion ${input.cohesion.toFixed(2)}) — a repeatable pattern worth capturing as a skill.` |
| 126 | : `Not a clear reusable pattern (${n} file(s), cohesion ${input.cohesion.toFixed(2)}${verb ? '' : ', no clear task verb'}).`; |
| 127 | return { worth, score, reason, proposedName: proposeSkillName(input.prompt), area }; |
| 128 | } |
no test coverage detected