AGENTS.md@packages/client/src/lib/state · git:20261020.359a43a · 2026-10-20 · sha256 1bd8704300d94522
AGENTS.md@packages/client/src/lib/state git:20261020.359a43aA
Immutable. This exact content never changes and is served at /api/v1/blob/1bd8704300d94522.
# DOX — packages/client/src/lib/state
Files in this directory. One row per source file. See change: fold-oversized-agents-directories.
| File | Purpose |
|------|---------|
| `CardSectionsContext.tsx` | Card-section visibility context. `CardSectionsProvider` (value `{prefs, send?, showToast?}` from App), `useCardSectionPrefs`, `useCardSectionVisible(session, id)` (worktree → main folder; no provider = visible), `useCardSectionActions()` → `canWrite` (send wired AND `connected !== false`), `setVisibility`, `resetFolder`, `hideInFolder`/`hideEverywhere` (Undo toast restores the value captured before the write). See change: configurable-session-card-sections. Context value gains `folderListMode` + `pluginNames`. Adds `usePluginSectionFilter(kind, folderKey)` → `(pluginId) => boolean` (fed to the slot consumers), `usePluginNames()`, `useFocusState()` → `FocusInfo`, and `useFocusActions()` → `setEnabled`, `saveCurrent`, `setRow` (the FIRST edit copies the built-in profile, so editing never mutates the built-in), `setFolderListMode`, `reset`. See change: add-focus-mode-and-card-block-toggles. `useCardToast()` returns the app toast sink. See change: add-session-actions-flyout. |
| `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. |
| `plugin-internals-pref.ts` | Per-browser "Show plugin internals" flag. `PLUGIN_INTERNALS_KEY` (`pi-dashboard:show-plugin-internals`), `loadShowPluginInternals`, `saveShowPluginInternals`, `useShowPluginInternals()` → `[on, set]` (`useSyncExternalStore`, cross-tab via `storage`). Default off; localStorage only, never `/api/config`. Gates slot claims in `PluginSettingsPage`; toggled on Developer page. See change: retro-ux-plugin-settings-wave-2. |
| `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>`. |
| `SessionMenuScopeContext.tsx` | One open actions menu across scopes: `SessionMenuScopeContext`, `useSessionMenuScope()`, `sessionScopeKey(id)`. State `{menuFor, source, point, opener}`; local fallback outside a provider. See change: add-session-actions-flyout. |
| `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. |
| `terminal-limit-notice-store.ts` | Singleton notice store, one per (cwd, inline) slot: show replaces, dismiss, `clearTerminalLimitNotices(cwd)` on `terminal_added`. `useSyncExternalStore`-friendly (`getTerminalLimitNoticeVersion`). See change: harden-server-capability-bounds. |