* feat: allow multiline custom answers in clarification overlay
Swap the single-line custom-answer input for an auto-growing textarea so users
can type multi-line replies to ask_user_question. Enter submits, Shift+Enter
inserts a newline; the box grows to ~6 lines then scrolls. Adds unit and e2e
coverage.
* fix: address review feedback on multiline clarification input
- Always preventDefault on desktop plain Enter so an empty draft can't leak a
stray newline before the trim guard (Claude/CodeRabbit).
- On coarse-pointer devices let Enter insert a newline and submit via the
existing Submit button; hide the keyboard hints on touch (mobile parity).
- Preserve newlines in the resolved clarification history message via
whitespace-pre-wrap + items-start.
- Strengthen e2e to guard against fused lines; add Ctrl+Enter and touch tests.
* fix: touch submit button and IME guard for clarification input
- Guard against submitting on the Enter that confirms an IME candidate
(e.nativeEvent.isComposing) on CJK keyboards.
- Add an inline Send button on coarse-pointer devices so single-question custom
answers (which have no overlay Submit button) have a touch-reachable send
path. Fixes the regression from switching touch Enter to newline.
* refactor: extract clarification custom-input controls
- Pull the Enter/⇧↵ hints and touch Send button into a CustomInputControls
subcomponent to shrink ClarificationCustomInput.
- Compute the trimmed draft once and reuse it across the keydown handler and the
Send button (disabled state, click, styling) so the conditions can't drift.
- Add a test asserting the touch Send button is disabled while isSubmitting.
* fix: ignore auto-repeat Enter in clarification custom input
A held Enter key emits auto-repeat keydown events; guard the handler with
e.repeat so it can't fire onSubmit more than once. Adds a regression test.
* fix: suppress newline on repeat Enter and add mobile clarification e2e
- Repeat Enter on desktop now calls preventDefault before bailing, so a held key
can't leak newlines into the current or next question's textarea after the
carousel advances; it still never re-fires onSubmit/finalize.
- Add a mobile-chrome (Pixel 5) e2e covering the touch path: Enter inserts a
newline and the inline Send button submits the multiline answer.
* test: consolidate clarification e2e seed helper
Extract the shared seed → navigate → waitForLoad flow into
e2e/helpers/clarification.ts and delegate from the clarification, resize, and
mobile specs instead of duplicating it in each.
* fix: coalesce ci auto-fix queue rounds
* fix: centralize ci auto-fix round cap
* fix: keep ci auto-fix state fresh
* fix: refine ci auto-fix round status
* fix: handle ci auto-fix exhaustion edge cases
* fix: reduce ci auto-fix dispatch complexity
* fix: refresh pending ci auto-fix before direct prompt
* fix: harden ci auto-fix queue replacement
---------
Co-authored-by: root <root@kandev.ts.net>
* feat(web): add sidebar view system to mobile task switcher
* test(web): scope mobile view-system gear indicator to the sheet
* fix(web): disable view-chip drag-reorder on touch to keep row scrollable
* fix(web): use mouse+touch sensors so chip drag works on hybrid devices
* fix(web): match kanban PointerSensor+TouchSensor convention for chip dnd
* fix(web): use MouseSensor+TouchSensor so touch swipe scrolls chip row
* fix(web): wire group collapse + align/clean view bar in mobile sheet
* feat(web): surface PR mergeability + conflict state in the CI popover
The CI hover popover showed checks/reviews but nothing about mergeability, so an
unmergeable PR silently dropped its merge button with no reason. Add a mergeability
row that reuses the detail panel's conflict banner + "Resolve conflicts" agent prompt
for dirty PRs, a "Behind base" chip, and a branch-protection note explaining why a
blocked PR is gated. Replace the compact merge split-button+dropdown with an inline
primary + "or <method>" buttons so the menu's detached portal no longer closes the
hover popover.
* feat(web): reflect PR mergeability in status colors and badges
The PR status pill, badge, and chat-input CI chip derived their colour from
checks/reviews only, so a conflicted or blocked PR still read as a green "all good"
check. Map dirty -> red, behind -> amber, and branch-protection blocked -> amber across
getPRStatusColor, the PRStatusIcon badge, and the chip glyph, so the indicators agree
with the popover. Blocked stays sky/in-progress while a requested review is still
outstanding (that's the awaiting-review gate, not a hard block).
* refactor(web): remove dead merge-menu keep-open plumbing
The compact merge control was redesigned to inline buttons (no dropdown portal),
which already fixes the hover popover closing. That leaves the keepOpen ref /
setKeepOpen / onMergeMenuOpenChange / onMenuOpenChange chain threaded through
usePopoverInteractions, PRCIPopover, and PRMergeButton unreachable: the popover
always renders PRMergeButton with compact, and the only DropdownMenu lives in the
non-compact detail-panel path that never passes the callback. Drop the unused
scaffolding (flagged by OpenCode + greptile).
* fix(web): keep CI popover quiet for blocked PRs only awaiting review
PRMergeabilityRow rendered "Blocked by branch protection" for any blocked PR,
including one blocked solely because a requested reviewer hasn't responded. That
contradicted the chip/pill/badge, which deliberately read that case as the calm
"awaiting review" state. Skip the note (render nothing) when isPRAwaitingReview is
true, and narrow blockedReason so an empty checks_state no longer falsely claims a
required status check failed. Flagged by Claude (blocker) and greptile.
* refactor(web): rename mergeability-notice compact prop to popover
The `compact` prop made the chip/text larger (to match the popover's text-xs rows)
while ConflictBanner's `compact` tightened padding — so "compact" rendered bigger,
which reads as inverted. Rename it to `popover` (the variant rendered inside the CI
hover popover) and document that the chip intentionally matches the popover rows.
No visual change. Flagged by cubic.
* fix(web): show default cursor on disabled compact merge alternates
The compact "or <method>" alternates kept cursor-pointer while disabled (during the
~1s merging state); add disabled:cursor-default to match the primary button. Flagged
by OpenCode.