Context
The miner dashboard (apps/loopover-miner-ui) contains proven, app-agnostic chat UI primitives that the upcoming maintainer chat surface in apps/loopover-ui must reuse rather than fork. Per the repo's design-system rule, shared UI belongs in packages/loopover-ui-kit (@loopover/ui-kit). This issue moves the app-agnostic primitives there — a pure relocation with zero behavior change.
Hard constraints — read before writing any code
- ⚠️ Move exactly these three units, nothing else:
apps/loopover-miner-ui/src/components/streaming-text.tsx → packages/loopover-ui-kit/src/components/streaming-text.tsx
apps/loopover-miner-ui/src/lib/use-streaming-text.ts → packages/loopover-ui-kit/src/hooks/use-streaming-text.ts
apps/loopover-miner-ui/src/components/chat/typing-indicator.tsx → packages/loopover-ui-kit/src/components/typing-indicator.tsx
- ⚠️ Do NOT move
chat-composer.tsx, chat-rail.tsx, components/chat/conversation.tsx, message-bubble.tsx, message-list.tsx, governor-action-result.tsx, fixtures.ts, or anything under src/lib/ besides the hook listed — they are app-coupled and out of scope.
- Zero behavior change: no edits to component logic, props, DOM structure, class names, styling, or exports beyond what the new import paths mechanically require. The public API of each moved unit is identical.
- Move, not copy: the originals are deleted;
apps/loopover-miner-ui imports the moved units from @loopover/ui-kit. No re-export shim files left behind in loopover-miner-ui.
- Preserve the react-refresh constraint documented at the top of
streaming-text.tsx (the file exports only the component; its reduced-motion helper stays internal). Neither package gains a motion/framer-motion dependency — no new dependencies in either package.
- Tests move with the code:
streaming-text.test.tsx, use-streaming-text.test.ts, and components/chat/typing-indicator.test.tsx relocate into packages/loopover-ui-kit beside their subjects and must pass there. Both moved sides of every existing branch/assertion stay covered — do not drop or weaken any assertion during the move.
Anti-patterns that will fail the gate
- Copying the files and leaving the originals (duplicate source of truth).
- "Fixing" or restyling anything while moving it.
- Satisfying imports via tsconfig path aliases instead of the real
@loopover/ui-kit package import.
- Adding exports to ui-kit's public surface beyond the three moved units.
- Touching any file not required by the move and its import updates.
Deliverables
- The three moved units + their tests, live in
@loopover/ui-kit, deleted from loopover-miner-ui, with all miner-ui imports updated.
- Before/after screenshots of the miner dashboard chat surface in the PR body demonstrating pixel-identical rendering (visual-change PRs require screenshots; here they prove the absence of visual change).
- Full local gate green (
npm run test:ci), UI lint/prettier included.
Expected outcome
@loopover/ui-kit exposes the streaming-text component, its hook, and the typing indicator, ready for consumption by apps/loopover-ui's maintainer chat surface, with the miner dashboard visually and behaviorally unchanged.
Context
The miner dashboard (
apps/loopover-miner-ui) contains proven, app-agnostic chat UI primitives that the upcoming maintainer chat surface inapps/loopover-uimust reuse rather than fork. Per the repo's design-system rule, shared UI belongs inpackages/loopover-ui-kit(@loopover/ui-kit). This issue moves the app-agnostic primitives there — a pure relocation with zero behavior change.Hard constraints — read before writing any code
apps/loopover-miner-ui/src/components/streaming-text.tsx→packages/loopover-ui-kit/src/components/streaming-text.tsxapps/loopover-miner-ui/src/lib/use-streaming-text.ts→packages/loopover-ui-kit/src/hooks/use-streaming-text.tsapps/loopover-miner-ui/src/components/chat/typing-indicator.tsx→packages/loopover-ui-kit/src/components/typing-indicator.tsxchat-composer.tsx,chat-rail.tsx,components/chat/conversation.tsx,message-bubble.tsx,message-list.tsx,governor-action-result.tsx,fixtures.ts, or anything undersrc/lib/besides the hook listed — they are app-coupled and out of scope.apps/loopover-miner-uiimports the moved units from@loopover/ui-kit. No re-export shim files left behind inloopover-miner-ui.streaming-text.tsx(the file exports only the component; its reduced-motion helper stays internal). Neither package gains amotion/framer-motiondependency — no new dependencies in either package.streaming-text.test.tsx,use-streaming-text.test.ts, andcomponents/chat/typing-indicator.test.tsxrelocate intopackages/loopover-ui-kitbeside their subjects and must pass there. Both moved sides of every existing branch/assertion stay covered — do not drop or weaken any assertion during the move.Anti-patterns that will fail the gate
@loopover/ui-kitpackage import.Deliverables
@loopover/ui-kit, deleted fromloopover-miner-ui, with all miner-ui imports updated.npm run test:ci), UI lint/prettier included.Expected outcome
@loopover/ui-kitexposes the streaming-text component, its hook, and the typing indicator, ready for consumption byapps/loopover-ui's maintainer chat surface, with the miner dashboard visually and behaviorally unchanged.