# Design notes The plugin is one hand-written client module (`client.js`, no build step) plus an empty host half. These notes record the non-obvious decisions behind it. ## Where the data comes from ``` ctx.sessions / conversation store order: [key, key, ...] // canonical display order nodeStore.get(key) // node: { kind, blocks?, parts?, text? } ``` Search walks `order` and reads each node, **not** the DOM. DOM-based find (what the browser does) only sees rendered text: collapsed steps, reasoning details and tool payloads are not in the DOM, so they are unreachable. Store-based search sees everything the session has loaded. Legacy sessions that predate `order` fall back to `legacy.nodes`. ## Projection: turning a node into searchable text `collectParts(node)` flattens a node into `{ text, role }` fragments. Roles come from three layers: | Layer | Example keys | Role | |---|---|---| | node kind | `user`, `steering` | your message | | node kind | `assistant-step` | assistant | | node kind | `system-prompt`, `compaction`, `turn-error`, … | system | | block kind | `reasoning` / `tool-call` / `tool-result` / `text` | that block's role | | raw key | `args`, `toolCall`, `toolResult`, … | tool call / result | Two projections are built from the same fragments: - **full**: every fragment, prefixed with a human-readable projection of card-shaped payloads (so a JSON blob is also searchable as prose). - **prose**: only `user` and `assistant` text. Prose mode runs the search twice: once over the full projection (for the true total) and once over prose (for the rows). `excluded = total − proseHits`. ## Matching `buildMatcher(query, options)` returns either a literal or a regex matcher: - Literal: optional lower-casing on both sides (case-insensitive default), optional word-boundary check that is applied **only** when the query is pure ASCII word characters — Chinese has no word boundaries, so a whole-word switch would silently return nothing otherwise. - Regex: the user's pattern, wrapped in `(?`; in the Electron desktop shell this opens the native save dialog in a short-lived window. `File System Access API` was tried and dropped: the first call worked, later calls silently degraded to a regular Chromium download. ## Not done on purpose - **No host half**: no index, no IPC, no cross-session search. It would need a background indexer and does not fit "zero dependencies". - **No fuzzy matching**: substring + regex only. Fuzzy over tool JSON gives noise, not help.