source dump of claude code
at main 59 lines 1.7 kB view raw
1import type { 2 RenderableMessage, 3 SystemStopHookSummaryMessage, 4} from '../types/message.js' 5 6function isLabeledHookSummary( 7 msg: RenderableMessage, 8): msg is SystemStopHookSummaryMessage { 9 return ( 10 msg.type === 'system' && 11 msg.subtype === 'stop_hook_summary' && 12 msg.hookLabel !== undefined 13 ) 14} 15 16/** 17 * Collapses consecutive hook summary messages with the same hookLabel 18 * (e.g. PostToolUse) into a single summary. This happens when parallel 19 * tool calls each emit their own hook summary. 20 */ 21export function collapseHookSummaries( 22 messages: RenderableMessage[], 23): RenderableMessage[] { 24 const result: RenderableMessage[] = [] 25 let i = 0 26 27 while (i < messages.length) { 28 const msg = messages[i]! 29 if (isLabeledHookSummary(msg)) { 30 const label = msg.hookLabel 31 const group: SystemStopHookSummaryMessage[] = [] 32 while (i < messages.length) { 33 const next = messages[i]! 34 if (!isLabeledHookSummary(next) || next.hookLabel !== label) break 35 group.push(next) 36 i++ 37 } 38 if (group.length === 1) { 39 result.push(msg) 40 } else { 41 result.push({ 42 ...msg, 43 hookCount: group.reduce((sum, m) => sum + m.hookCount, 0), 44 hookInfos: group.flatMap(m => m.hookInfos), 45 hookErrors: group.flatMap(m => m.hookErrors), 46 preventedContinuation: group.some(m => m.preventedContinuation), 47 hasOutput: group.some(m => m.hasOutput), 48 // Parallel tool calls' hooks overlap; max is closest to wall-clock. 49 totalDurationMs: Math.max(...group.map(m => m.totalDurationMs ?? 0)), 50 }) 51 } 52 } else { 53 result.push(msg) 54 i++ 55 } 56 } 57 58 return result 59}