feat: session rename + graph chrome polish (popovers dismiss, no-shift no-match, coverage reseat)

Rename (owner ask): clicking the header title opens edit mode with the
whole title selected — typing replaces, arrows move inside. Enter or a
click away commits (PUT /api/chats/:id); Escape and an empty commit
discard. renameChat joins the ChatStore port; like saveSettings it is
NOT conversation activity — updatedAt stays put so sidebar order never
churns on a rename. The sidebar patch is instant: the header dispatches
lh:chat-renamed and SessionsSidebar folds it into its snapshot (the 2.5s
poll is only a backstop). Sidebar right-click rename is DELIBERATELY
deferred: it needs a real context-menu system, which gets its own pass
later (owner decision, 2026-09-17).

Graph chrome:
- The extraction-coverage button moves between search and import; the
  gear keeps the far-right corner. Coverage still renders on an EMPTY
  graph (that is exactly when it matters).
- The no-match search note no longer shifts its siblings: the chrome
  row is items-start (every button is 44px tall, so top alignment pins
  the row while the search container grows downward).
- Popovers dismiss properly: pointerdown anywhere outside the control's
  root (button + panel) closes it, and so does Escape. Two panels can
  never be open at once — the sibling chrome buttons are outside the open
  root, so pointerdown closes the first before the click opens the
  second. New shared hook components/popover-dismiss.ts, wired into
  both the settings gear and the coverage control.

Gates: typecheck, eslint, 498/498 (+2 rename store tests), build.
Live-verified: select-all/focus/Enter/Escape/empty/blur round-trip,
updatedAt untouched, sidebar instant patch; chrome order + frozen
positions under a no-match query; popover close via canvas, search
input, Esc, mutual exclusion, toggle intact.
This commit is contained in:
amosblomqvist
2026-09-17 14:28:20 +03:00
parent 5c380de669
commit 769a3da186
9 changed files with 219 additions and 17 deletions
+4
View File
@@ -54,6 +54,10 @@ export interface ChatStore {
/** Persist the per-chat model/thinking settings (the model control).
* Replace-whole: the picker sends the complete settings object. */
saveSettings(id: string, settings: ChatSettings): void;
/** Rename a session (the header's click-to-edit title, 2026-09-17).
* Like saveSettings: a rename is NOT conversation activity — updatedAt
* stays put, so sidebar order never churns on a rename. */
renameChat(id: string, title: string): ChatRecord;
}
// ─── GraphStore — the append-only evidence ledgers (data/graph) ──────────────