19 file(s), +648 / -527 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +3 | -5 |
| messages/hi.json | Config | +3 | -5 |
| src/components/agents/agent-dock-mount.tsx | Component | +64 | -31 |
| src/components/agents/mira-dock-mount.tsx | Component | +241 | -0 |
| src/components/matter-detail/brief/brief-mira-ccb.tsx | Component | +29 | -8 |
| src/components/matter-detail/brief/frame-summary-history.stories.tsx | Component | +7 | -0 |
| src/components/matter-detail/brief/matter-brief-page.tsx | Component | +17 | -11 |
| src/components/matter-detail/brief/matter-brief-sections.tsx | Component | +4 | -1 |
| src/components/matter-detail/ccb/mira-control-bar.stories.tsx | Component | +71 | -5 |
| src/components/matter-detail/ccb/mira-control-bar.tsx | Component | +24 | -0 |
| src/components/matter-detail/ccb/mira-conversation-panel.stories.tsx | Component | +0 | -123 |
| src/components/matter-detail/ccb/mira-conversation-panel.tsx | Component | +0 | -220 |
| src/components/matter-detail/ccb/mira-dock.stories.tsx | Component | +121 | -0 |
| src/components/matter-detail/ccb/mira-matter-dock.stories.tsx | Component | +0 | -35 |
| src/components/matter-detail/ccb/mira-matter-dock.tsx | Component | +0 | -64 |
| src/components/matters/matter-shell-chrome.tsx | Component | +22 | -15 |
| src/lib/agents/__tests__/agent-surface.test.ts | Library | +5 | -0 |
| src/lib/agents/agent-surface.ts | Library | +17 | -4 |
| src/stores/agent-dock-store.ts | Source | +20 | -0 |
Story-2040 shipped Mira's two surfaces but mounted her conversation behind a
floating "Ask Mira" pill — chrome that was never approved. The approved
primitive (availability-over-visibility doctrine) is the gutter
Mira avatar → Counsel Control Bar: Mira is available at
every editable field and visible nowhere until summoned. This
story deletes the floating dock, completes the gutter entry (the
frame_summary hero was the one editable field missing the
avatar), and — per the founder's scope amendment — moves the conversation
surface onto the canonical pinned Agent Dock
(AgentDock), the exact substrate Atlas rides: APB pill when
closed ⇄ in-flow pushing panel when open, never floating/fixed.
mira-matter-dock.tsx (+ its story) and its mount in
matter-shell-chrome.tsx are gone. The bespoke
mira-conversation-panel.tsx (+ story) is gone too: it
wrapped AgentChatPanel in a second panel shell that
AgentDock already renders — reuse-don't-recreate. Its one
Mira-specific affordance (the "Do it" escalation chip) moved into the
new dock footer.
resolveAgentSurface now returns
agent: "atlas" | "mira" (a matter detail page is Mira's,
mirroring the registry's agent: "matter" field), and the
layout-mounted AgentDockMount swaps the wired inner mount on
that seam: AtlasDockMount everywhere,
MiraDockMount on /matters/[matterId]/…. ONE
dock, one shared open/width store, never both agents.
MiraDockMount
(src/components/agents/mira-dock-mount.tsx) — renders
AgentDock with Mira's localized descriptor (name
Mira, role Matter Expert,
/agent-avatars/mira-matter-expert.png), her matter-scoped
conversation rail (use-mira-conversation-rail) feeding the
thread (streamed replies + thinking state intact), and the "Do it" chip +
composer through the existing footer/headerSlot
seams. A settled "Do it" command invalidates the Brief query so the
proposal lands on the existing ratify rail.
miraContext: id + title/type/stage) into
agent-dock-store, CPC-style, cleared on unmount. The
layout-mounted dock reads it; no browser matter fetch, no new proxy
route.
BriefHeader passes
onMira into FrameSummaryHistory, so the
frame_summary hero now shows Mira's avatar ABOVE the
timeline icon — the same stack as every other editable field. Clicking
it opens the CCB scoped to frame_summary (new
MatterDetail.brief.summary label, en + hi).
MiraControlBar
gains a Talk affordance (bar state + command-panel header;
Mira.ccb.talk, en + hi). It opens the pinned Mira dock via
the shared store's openDock() and dismisses the bar — the
conversation is reachable from the CCB with zero floating chrome.
BriefMiraCcb now rides the shared
riseFromBottomCentered preset (centering via the variant's
x: "-50%", transform-conflict rule) inside an
AnimatePresence in the Brief page, so dismissal sinks the
bar out the way it rose in.
| Before (2040) | After (2041) |
|---|---|
| Floating "Ask Mira" pill, fixed bottom-right; conversation in a fixed overlay drawer (bespoke panel wrapper). | No standing chrome. Gutter avatar → CCB (command); CCB "Talk" / APB pill → the pinned AgentDock showing MIRA — in-flow flex child, page reflows beside it, drag-resize, AnimatePresence pill⇄panel swap. |
frame_summary hero gutter: timeline icon only. |
Mira avatar (opacity-55, hover-revealed) above the timeline icon — parity with every editable field. |
MatterDetail/MiraControlBar → FromGutter — hover the hero, click the gutter avatar: the CCB rises in scoped to the field; dismiss sinks it out (enter + exit).MatterDetail/MiraDock → Closed / Open — Mira on the canonical dock: pill ⇄ panel enter/exit and the page-column push reflow, same demonstration as Agents/AgentDock.MatterDetail/FrameSummaryHistory → HoverWithMira — the hero's full gutter stack.pnpm lint — clean (one pre-existing <img> warning in add-matter, untouched).pnpm test — 163 files / 1014 tests green (surface-resolver tests extended for the agent field).pnpm build — green.src/ or tests/; orphaned i18n keys (Mira.openLabel/closeLabel, unused panel keys) removed from both locales.Live-data seam: the dock reuses Story-2040's Mira rails unchanged (converse + command over the ADR-110 broker WS); broker-side Mira WS routing remains the Story-2040/RFD Story-G seam to confirm live. The component-boundary → system-boundary check on staging is that follow-up's evidence, not this PR's Storybook.