* 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>