* refactor(chat): extract tool display subsystem from ChatBubble.kt ChatBubble.kt was a 2578-line god file. Split it into four files in the same package (zero import churn, no behavior change): - ChatBubble.kt: user/assistant/system bubbles + dispatch + shared helpers (formatTimestamp, buildHighlightedString, InlineAttachment) - ParsedToolData.kt: the parsed tool payload model - ToolResultParser.kt: parseToolOutput + per-tool formatters + the Gson-compat JSON shims and tolerant exit_code parser - ToolBubble.kt: ToolBubble + ExpandedToolContent + HeaderRow + SecurityRiskChip + CopyButton formatTimestamp became internal (shared with ToolBubble.kt). Verified: ktlintCheck + testDebugUnitTest green locally. * refactor(chat): drop dead ParsedToolData fields and unused shim Verified via grep: parsed.args / parsed.result / parsed.stderr / parsed.isRunning / parsed.toolName had zero readers across app/src (main + test + androidTest). toolName + isRunning are asserted by ToolBubbleParsingTest, so they stay; args/result/stderr were built by every formatter (21 construction sites) and never read — removing them also kills a JSON.stringify-per-tool-complete wasted map build. keySet() shim had no call sites. formatTodoToolOutput's args param became unused with the field removal — dropped it too. Verified: ktlintCheck + testDebugUnitTest green locally. * refactor(chat): drop unused lastSessionId and ToolBubble isDarkTheme param ChatScrollController.lastSessionId: introduced in #683, never read or written since (namefreq scan + git log -S confirm single occurrence at declaration). Session-change detection moved to lastTailKey/ lastMessageCount. ToolBubble.isDarkTheme: never read in the body (MaterialTheme + statusColors do the theming); single call site updated. Verified: ktlintCheck + compileDebugKotlin green locally. --------- Co-authored-by: hy4ri <hy4ri@users.noreply.github.com>