git:20260816.b085c2f to git:20260904.c6805ff

1 added, 0 removed. Audit A to A.

# DOX — packages/client/src/lib/state
Files in this directory. One row per source file. See change: fold-oversized-agents-directories.
| File | Purpose |
|------|---------|
+ | `custom-event-groups.ts` | Module-cached `GET /api/custom-event-groups` fetch + `useCustomEventGroups()` hook → group definitions (id/label/default, resolution order, never patterns). Consumed by SettingsPanel + ChatViewMenu for one toggle per group. See change: add-custom-event-group-filters. |
| `DisplayPrefsContext.tsx` | React context exposing `{ global: DisplayPrefs|undefined, getSessionOverride(id):… → see `DisplayPrefsContext.tsx.AGENTS.md` |
| `ModelConfigContext.tsx` | Neutral per-session model config context (renamed from `OpenSpecRunConfigContext.tsx`, no alias). Exports `ModelConfigValue { model?, models?, thinkingLevel?, favorites?, setModel, setThinkingLevel, toggleFavorite, refreshModels, notify }`, `ModelConfigProvider`, `useModelConfig()` (throws outside the provider), `useModelConfigOptional()` (no-throw read for hosts rendering outside a session). Provided once in `App.tsx`; consumed by the OpenSpec launch dialogs AND the shell-bound `ui:model-selector` primitive. See changes: openspec-dialog-model-effort-selector, upgrade-model-selector-primitives. |
| `PopoverBoundaryContext.tsx` | React context providing the nearest clipping-pane ref to descendant popovers. `PopoverBoundaryProvider` (value = `RefObject<HTMLElement\|null>`), `usePopoverBoundary()` → ref or `undefined` (viewport root). Consumers pass it to `usePopoverFlip({ boundaryRef })` so flip/clamp measures the pane edge, not the viewport. Provided at the split chat pane (`SplitWorkspace.tsx:112`, `split-chat-pane`). Read by ChatViewMenu / ModelSelector / ThinkingLevelSelector / WorktreeActionsMenu / PackageRow. **Pane provisioning (fix-popover-pane-bounded-height):** a boundary-less consumer measures the VIEWPORT, which over-reports space inside an offset scroll pane → popover renders past the pane's `overflow` edge and grows its scroll extent (second scrollbar). Every scroll pane hosting a consumer must therefore provide itself. Provider mounts are now: `SplitWorkspace.tsx` (`split-chat-pane`), `SettingsPanel.tsx` (settings-pages scroll pane; wraps all three tab branches but the ref attaches only inside the general-settings branch — the other two host no consumer and fall back to the viewport), `DirectoryHomeView.tsx` (`directory-home`, `overflow-auto`, hosts the focal CommandInput), and `components/openspec/useOpenSpecRunConfigRow.tsx` (the OpenSpec launch dialogs' "Runs with" row — boundary resolved by a SCOPED `closest('[role="dialog"]')` lookup to the shared `Dialog` panel, `max-h-[80vh] overflow-y-auto`; a single-selector ancestor lookup is permitted and is NOT the rejected general `overflow` ancestor walk). `App.tsx` + `ComposerSessionActions.tsx` need NO mount: their chat/composer content reaches `SplitWorkspace` via `SessionSplitView`'s `chat` prop and is already bounded. `CommandInput`'s composer dropdown newly consumes the boundary (immune horizontally via `left-3 right-3`, NOT immune vertically since it applies a height bound). `ThemePicker` stays boundary-less — its only mount is the SessionList header bar, a sibling above that view's scroll list. Boundary must be the clipping pane and must contain the trigger (hook dev-warns otherwise); when panes nest, use the innermost. See change: fix-popover-container-clip. See change: fix-popover-pane-bounded-height. |
| `draft-storage.ts` | Per-session chat-input draft persistence in `localStorage` under `chat-draft:<sessionId>`. → see `draft-storage.ts.AGENTS.md` |
| `recovery-offer-bus.ts` | App-level channel for the cold-start recovery offer: server broadcasts/replays one `recovery_offer` (≥1 unclean-shutdown session, setting `ask`); `setRecoveryOffer(candidates)`, `RecoveryOffer`. Consumed by `<RecoveryOfferHost>`. |
| `spawn-error-toast-bus.ts` | Module-singleton bus for off-screen `spawn_error` toasts. → see `spawn-error-toast-bus.ts.AGENTS.md` |
| `subagent-inspector-telemetry.ts` | Records what share of subagent runtime has a detail view MOUNTED — the P5 kill-switch signal that did not exist before (C4: abort above 50 %). Exports `noteSubagentRunning`, `noteSubagentTerminal`, `trackInspectorMounted`, `readInspectorTelemetry`, `inspectorOpenShare`, `resetInspectorTelemetry`; reading also hung off `globalThis.__piSubagentInspectorTelemetry` for harness reads. Overlapping views count once. See change: reduce-subagent-details-payload. |