feat(ui): render compacted history as a collapsible card on all three surfaces (#1649)
After auto-compaction, the synthesized recap was being stored as a
plain assistant message with a HISTORY_FOLD_MARKER prefix. None of the
three surfaces special-cased it — TUI hydrated it as a regular streaming
card on resume; Desktop and Dashboard rendered it inline through
AssistantText. Users had no way to tell compaction had happened or
distinguish the recap from a real model reply.
- Single-source the marker + helpers in @reasonix/core-utils/compaction
(COMPACTION_SUMMARY_MARKER, isCompactionSummary, stripCompactionMarker).
Re-export the constant from src/context-manager.ts so existing
HISTORY_FOLD_MARKER imports keep resolving.
- TUI: new kind: "compaction" in state/cards.ts, renderer in
cards/CompactionCard.tsx, hydrate.ts emits it instead of a streaming
card when the marker is present.
- Desktop / Dashboard: CompactionCard component in ui/cards.tsx,
intercepted in the assistant-segment renderer in ui/thread.tsx.
Default-collapsed, archive icon, header shows char count, body renders
the recap markdown.
- Wire vite + tsconfig aliases for the sub-import path so browser bundles
don't pull in Node-only siblings (tildeify) via the barrel.
Tests: marker detection edge cases in core-utils, hydrate emits
compaction card for the marker, full verify (262 files / 3595 tests).
Follow-up: surface the loop "warning" event ("folded N messages → M")
as a visible row on Desktop / Dashboard (currently flows through
protocol, no ChatMessage reducer).
fix(ink): scroll jitter on rapid mouse wheel (#2076) (#2095)
* fix(ink): add dependency arrays to useBoxMetrics and useTerminalViewport to prevent scroll jitter (#2076)
- useBoxMetrics: add [ref.current] deps so measurement only runs when element changes
- useTerminalViewport: add [elementRef.current, terminalSize] deps to skip expensive parent-chain walk on every render
- App: memoize TerminalSizeContext.Provider value to keep reference stable
During rapid mouse wheel scrolling (10-20 events/100ms on Windows), the
missing dependency arrays caused each wheel event to trigger 3-5 cascading
renders (30-80 renders/100ms), producing visible text jitter.
* fix(ink): address PR #2095 review — remove ref.current anti-pattern from hook deps
- useBoxMetrics: remove [ref.current] dep array (React anti-pattern);
add 16ms throttle to limit measurement frequency during rapid scrolling
- useTerminalViewport: remove elementRef.current from deps, keep only
[terminalSize] as the reactive dependency
- Add regression test verifying useBoxMetrics re-measures on parent resize