( messages: RenderableMessage[], tools: Tools, )
| 760 | * - Breaks groups when assistant text appears |
| 761 | */ |
| 762 | export function collapseReadSearchGroups( |
| 763 | messages: RenderableMessage[], |
| 764 | tools: Tools, |
| 765 | ): RenderableMessage[] { |
| 766 | const result: RenderableMessage[] = [] |
| 767 | let currentGroup = createEmptyGroup() |
| 768 | let deferredSkippable: RenderableMessage[] = [] |
| 769 | |
| 770 | function flushGroup(): void { |
| 771 | if (currentGroup.messages.length === 0) { |
| 772 | return |
| 773 | } |
| 774 | result.push(createCollapsedGroup(currentGroup)) |
| 775 | for (const deferred of deferredSkippable) { |
| 776 | result.push(deferred) |
| 777 | } |
| 778 | deferredSkippable = [] |
| 779 | currentGroup = createEmptyGroup() |
| 780 | } |
| 781 | |
| 782 | for (const msg of messages) { |
| 783 | if (isCollapsibleToolUse(msg, tools)) { |
| 784 | // This is a collapsible tool use - type predicate narrows to CollapsibleMessage |
| 785 | const toolInfo = getCollapsibleToolInfo(msg, tools)! |
| 786 | |
| 787 | if (toolInfo.isMemoryWrite) { |
| 788 | // Memory file write/edit — check if it's team memory |
| 789 | const count = countToolUses(msg) |
| 790 | if ( |
| 791 | feature('TEAMMEM') && |
| 792 | teamMemOps?.isTeamMemoryWriteOrEdit(toolInfo.name, toolInfo.input) |
| 793 | ) { |
| 794 | currentGroup.teamMemoryWriteCount = |
| 795 | (currentGroup.teamMemoryWriteCount ?? 0) + count |
| 796 | } else { |
| 797 | currentGroup.memoryWriteCount += count |
| 798 | } |
| 799 | } else if (toolInfo.isAbsorbedSilently) { |
| 800 | // Snip/ToolSearch absorbed silently — no count, no summary text. |
| 801 | // Hidden from the default view but still shown in verbose mode |
| 802 | // (Ctrl+O) via the groupMessages iteration in CollapsedReadSearchContent. |
| 803 | } else if (toolInfo.mcpServerName) { |
| 804 | // MCP search/read — counted separately so the summary says |
| 805 | // "Queried slack N times" instead of "Read N files". |
| 806 | const count = countToolUses(msg) |
| 807 | currentGroup.mcpCallCount = (currentGroup.mcpCallCount ?? 0) + count |
| 808 | currentGroup.mcpServerNames?.add(toolInfo.mcpServerName) |
| 809 | const input = toolInfo.input as { query?: string } | undefined |
| 810 | if (input?.query) { |
| 811 | currentGroup.latestDisplayHint = `"${input.query}"` |
| 812 | } |
| 813 | } else if (isFullscreenEnvEnabled() && toolInfo.isBash) { |
| 814 | // Non-search/read Bash command — counted separately so the summary |
| 815 | // says "Ran N bash commands" instead of breaking the group. |
| 816 | const count = countToolUses(msg) |
| 817 | currentGroup.bashCount = (currentGroup.bashCount ?? 0) + count |
| 818 | const input = toolInfo.input as { command?: string } | undefined |
| 819 | if (input?.command) { |
no test coverage detected