(matches: EpisodeMatch[])
| 143 | |
| 144 | /** Build the concise system-prompt block from matches. Empty when none. */ |
| 145 | export function buildEpisodeBlock(matches: EpisodeMatch[]): string { |
| 146 | if (matches.length === 0) return ''; |
| 147 | const lines = ['# Similar past work (your own, on this project)', '', |
| 148 | 'You have done comparable tasks here before. Reuse what worked — don\'t rediscover it:', '']; |
| 149 | for (const m of matches) { |
| 150 | const files = m.filesChanged.slice(0, 4).join(', '); |
| 151 | lines.push(`- **"${m.prompt.replace(/\s+/g, ' ').trim().slice(0, 80)}"** → ${m.summary.replace(/\s+/g, ' ').trim().slice(0, 160)}${files ? ` (touched: ${files})` : ''}`); |
| 152 | } |
| 153 | return lines.join('\n'); |
| 154 | } |
| 155 | |
| 156 | /** Convenience: read → rank → build the injectable block for a query. Used by the loop. |
| 157 | * Builds a one-shot file-existence Set (each touched file checked once) so the pure ranker |
no test coverage detected