mirror of
https://github.com/cline/cline.git
synced 2026-09-19 02:05:44 +08:00
S5 of the message-state redesign. The webview decided "thinking vs approving vs done" and which buttons to show by inspecting the TAIL of clineMessages. Because the backend appends bookkeeping (api_req_started usage) after content and even after approval asks, the tail routinely meant the wrong thing — producing stuck "Thinking", vanishing Approve/Reject, and the footer disagreeing with the buttons (RC1, reproduced on camera). Now the webview reads the authoritative backend-owned TurnState (added in S4): - buttonConfig: add buttonsForPhase(turnState, anchoredMessage) and the dispatcher getButtonConfigFromState(messages, turnState, mode). The button SET is chosen by phase; approval labels (Approve vs Save, Run Command, MCP, subagents) come from the anchored message (turnState.anchorTs). When turnState is absent (classic/older state) it falls back to the legacy tail-walking getButtonConfigForMessages. - ActionButtons reads turnState from useExtensionState and uses getButtonConfigFromState. - MessagesArea.isWaitingForResponse short-circuits to `phase === "streaming"` when turnState is present (and only shows the footer loader until a content row is actually streaming); the legacy tail inference is kept as the fallback. Button actions (approve/reject/proceed/new_task) already send a fixed responseType independent of clineAsk, and the SDK backend resolves the pending approval/followup promise — so routing is correct under TurnState. Classic fallback paths are untouched. New unit tests cover buttonsForPhase (every phase + anchored-label selection + mistake_limit-vs-api_req_failed) and getButtonConfigFromState (prefers TurnState over a trailing bookkeeping tail; legacy fallback). 68 webview chat tests pass; tsc + biome clean.