AGENTS.md@packages/client/src/hooks · git:20261023.a1b763f · 2026-10-23 · sha256 701cee32bac67bb6

AGENTS.md@packages/client/src/hooks git:20261023.a1b763fA

Immutable. This exact content never changes and is served at /api/v1/blob/701cee32bac67bb6.

# DOX — packages/client/src/hooks

Files in this directory. One row per source file.

| File | Purpose |
|------|---------|
| `useActiveChatSelection.ts` | `useActiveChatSelection(containerRef, mapRange) → { isSelecting, isSelectingRef, selectionSpanRef,… → see `useActiveChatSelection.ts.AGENTS.md` |
| `useAddonIssues.ts` | Subscribes to `addon-issues-store` (plugin issues + `packages[]` health, one count for the Issues tab and the Settings rail badge); refresh on mount + `plugin-config-update`. See change: addons-hub-folder-view. On `pi-package-event` refreshes health only; folds `plugins-changed` snapshots into plugin issues (no refetch). See change: decouple-plugins-from-core. |
| `useEmbedMode.ts` | `useEmbedMode()`: `?embed=1` sets `sessionStorage["pi-dash-embed"]`, `?embed=0` clears it; returns presence, read synchronously in render. Per-tab sticky, never inherited by independent tabs. See change: add-session-ui-deep-links-for-agents. |
| `useFolderAddons.ts` | Folder Add-ons page state: folder catalog fetch, switch flow (no local flip before the server confirms; row error on failure), `keptOn`/`notOwned`(`removeUnowned` retry)/trust prompt (replays after `submitResourceTrust`), reload offer. See change: addons-hub-folder-view. |
| `useAddonCatalog.ts` | `GET /api/addons/catalog` + refetch (debounced `ADDON_CATALOG_DEBOUNCE_MS`) on `pi-package-event` success and `plugin-config-update`. See change: addons-hub-feature-catalog. |
| `useAnthropicPeerProbe.ts` | `useAnthropicPeerProbe() -> { peerMissing, peerReason, peerResolving, importFailed, refresh }` for the Anthropic OAuth row hint. → see `useAnthropicPeerProbe.ts.AGENTS.md` |
| `useAppHidden.ts` | NEW. Exports `useAppHidden()` hook + `applyAppHiddenClass(root, hidden)`. → see `useAppHidden.ts.AGENTS.md` |
| `useArchiveListing.ts` | Fetches `GET /api/openspec-archive?cwd=` into `entries: ArchiveEntry[]` with `isLoading`/`error`. → see `useArchiveListing.ts.AGENTS.md` |
| `useArchivedSessions.ts` | Per-key lazy cache for archived-session listings (`<groupPath>` for folder folds, `q:<text>` for search). Exports `useArchivedSessions`, `ARCHIVE_PAGE_SIZE` (50), `ArchivedKeyState`. Loads pages, retries, invalidates on count changes. See change: archive-sessions-lazy-load. |
| `useAsyncAction.ts` | `useAsyncAction(fn, opts) → { pending, error, run, bind }`. Wraps async action. → see `useAsyncAction.ts.AGENTS.md` |
| `useBodyDragStyle.ts` | `useBodyDragStyle()` → `{ beginBodyDrag(cursor), endBodyDrag() }`. Body `cursor` + `user-select: none` for resize drags. Both idempotent, gated on private `active` ref. One unmount cleanup ends an active drag. See change: fix-long-session-ux-degradation. |
| `useCardFxAttributes.ts` | `useCardFxAttributes(prefs)` mirrors the resolved `fx-status-animation` / `fx-selected-glow` card-effect blocks onto `<html>` as `data-fx-status` / `data-fx-glow` (`on`\|`off`). One document-level attribute pair, so `index.css` gates the effects in CSS instead of every card re-rendering on a preference change. See change: add-focus-mode-and-card-block-toggles. |
| `useChatMotion.ts` | `useChatMotion(prefs) → boolean` = `prefs.chatMotion && !prefers-reduced-motion && document visible`, via `useSyncExternalStore` on the media query + `visibilitychange` (flips in the same tick). The ONE effective-motion value every chat-motion consumer reads; false → today's exact behaviour. See change: add-fluid-chat-motion. |
| `useContentViews.ts` | URL-routing navigation helpers. `handleOpenDirectorySettings(cwd)` (renamed from `handleOpenPiResources`,… → see `useContentViews.ts.AGENTS.md` |
| `useCustomEntryPayload.ts` | On-demand fetch hook `useCustomEntryPayload(sessionId, entryId) → { payload?, error?, loading, fetchPayload }` for a custom entry's FULL payload from `GET /api/sessions/:sid/entry/:id`. Mirrors `useToolFullResult`: skips when either id is missing, 404 → `entry evicted`, never throws (a failed fetch degrades the renderer to the stored body). Collapsed-first: `fetchPayload` is called ONLY from the expand path, so at-rest rows issue zero requests. See change: add-custom-entry-renderer-slot. |
| `useDebugToolsVisible.ts` | Deprecated shim over `useDisplayPrefs().debugTools`. Exports `DEBUG_TOOL_NAMES` set +… → see `useDebugToolsVisible.ts.AGENTS.md` |
| `useDisplayPrefs.ts` | `useDisplayPrefs(sessionId?): DisplayPrefs` — reads context, returns `mergeDisplayPrefs(global,… → see `useDisplayPrefs.ts.AGENTS.md` |
| `useDocumentTitle.ts` | Sets `document.title` via `buildDocumentTitle(session, folderCwd)`; resets to `"PI Dashboard"` on cleanup. Re-runs on `session`/`folderCwd` change. |
| `useEndedSessionComposer.ts` | Composer context for an ENDED session: folder command list (kept until the session's own `commands_list` arrives — no empty flash), catalogue models, per-session model/thinking pick (`setPickField`, `getResumePick`; dropped once not ended). Exports `useEndedSessionComposer`, `ResumePick`, `EndedSessionComposer`. See change: redesign-directory-home-split. |
| `useFileAccessToasts.ts` | `useFileAccessToasts(sessions, selectedId, api, onOpen)` + `fileAccessToastKey`. Keyed non-modal warning toast (Open action) when a session not in view turns `awaitingFileAccess`; withdrawn on settlement / when the operator opens it; ended sessions never toast. See change: ask-agent-file-access-in-chat. |
| `useFlipOnLaneChange.ts` | Hand-rolled FLIP (no dep). `useFlipOnLaneChange(containerRef, fingerprint, disabled)`: render-phase snapshot of `[data-session-id]` rects on fingerprint change, inverted transform + 220ms transition after commit. Skipped under `prefers-reduced-motion` and while `disabled` (drag). Exports `prefersReducedMotion`, `FLIP_DURATION_MS`. See change: session-list-group-by. |
| `useFolderCommands.ts` | `useFolderCommands(cwd)` → `{commands, origin}` from `GET /api/pi-resources/commands`; 30s module cache, in-flight dedupe, any failure (404/5xx/network) → empty `none`. `undefined` cwd stays idle. Exports `useFolderCommands`, `resetFolderCommandsCache`. See change: redesign-directory-home-split. |
| `useHistoryLoadState.ts` | App-owned history-load bookkeeping: `loadingHistory`/`replayInFlight` flags + timers refs, `historyLoadFailed`, `historyLoadStartedAt` (ref-backed). `beginLoadingHistory(id,{restart})` (startedAt rules a/b/c, clears failed, `onTimeout` = `markHistoryLoadFailed`), `beginReplayInFlight`, `markHistoryLoadFailed` (content-gated; also clears `replayInFlight`), `clearHistoryLoadFailed`, `resetAllHistoryLoad`. Layout-effect reset on transition to `connected`. See change: show-session-history-load-state. |
| `useHostPlatform.ts` | One-shot probe of `/api/health` `platform` field. Returns host OS (darwin\|win32\|linux) for Settings → Tools… → see `useHostPlatform.ts.AGENTS.md` |
| `useIdleFx.ts` | Toggles `fx-idle` on document root after `IDLE_FX_DELAY_MS` (5000) with no deliberate input. Activity = `pointerdown`/`wheel`/`keydown`/`touchstart`/`focusin` at CAPTURE on `document`; `pointermove`+`scroll` deliberately excluded. Cleanup: timer + listeners + class. See change: fix-long-session-ux-degradation. |
| `useImagePaste.ts` | Clipboard-image-paste state. Supports uncontrolled (owns `pendingImages`) and controlled… → see `useImagePaste.ts.AGENTS.md` |
| `useInflightBashTools.ts` | Pure selector `selectInflightBashTools(state)` + memoized hook `useInflightBashTools(state)`. → see `useInflightBashTools.ts.AGENTS.md` |
| `useInitStatus.ts` | `useInitStatus(cwd, opts?) → { status: WorktreeInitStatus\|null, refetch }`; re-probes on session idle/ended + throttled tab-visible. → see `useInitStatus.ts.AGENTS.md` |
| `useInstalledPackages.ts` | Fetches `GET /api/packages/installed?scope=&cwd=` into `packages: InstalledPackage[]` with… → see `useInstalledPackages.ts.AGENTS.md` |
| `useInstallPrompt.ts` | PWA install-prompt state. Returns `{ canInstall, isInstalled, isIOS, prompt }`. → see `useInstallPrompt.ts.AGENTS.md` |
| `useLaneHysteresis.ts` | Status-lane hysteresis. Pure `stepLaneHysteresis(prev, raw, now, holdMs)`: working→review/idle held `LANE_HOLD_MS` (3000) displayed in working with `holds.get(id) = {until, dest}`; re-enter working within hold → no move; every other transition immediate. `useLaneHysteresis(raw)` owns one wake timer (earliest `until`), cleared on unmount. `nextHoldWake`, `EMPTY_HYSTERESIS`. See change: session-list-group-by. |
| `useLaunchSource.ts` | One-shot probe of `/api/health` `launchSource` field (`"electron" | "standalone" | "bridge"`). → see `useLaunchSource.ts.AGENTS.md` |
| `useMainSpecsReader.ts` | Reads `openspec/specs/` directory, fetches each `spec.md` in parallel, concatenates into single markdown… → see `useMainSpecsReader.ts.AGENTS.md` |
| `useMediaQuery.ts` | Re-export shim. Forwards `useMediaQuery` from `@blackbelt-technology/pi-dashboard-client-utils/useMediaQuery`. Migration Layer 0. |
| `useMessageHandler.ts` | New `case "view_messages_update"`: replaces `viewMessagesMap.get(sessionId)` with `msg.viewMessages.slice()`. → see `useMessageHandler.ts.AGENTS.md` Adds `sessions_page_result` merge, `openspec_get_result` apply, snapshot `endedTotals`→`endedTotalsMap` + `snapshotGeneration`, live endedTotals, tail-keeping `sessions_reordered`. See change: fix-connect-snapshot-frame-loss. Handles `session_archived` (deletes session, updates count + ended totals), `archived_count_updated`, and snapshot `archivedCountByCwd`. See change: archive-sessions-lazy-load. Reconciled `session_added` takes the server record as authoritative (a plain merge would keep a stale `currentTool`/`hostPressure` from the previous incarnation) and carries over only the client-local `resuming`/`closing`/`assets`; gates navigation off ALL tiers (placeholder/pending-spawn cleanup only on an exact `spawnRequestId`); appends a newly added id to the group order tail; an add flipping a held ended row back to live removes its `endedTotals` contribution; paging `pageReplyGen` (release in-flight on any reply) + `pageExhausted` (hide "more" until `endedTotals` changes). See change: close-registry-frame-shed-gaps. `case "group_by_prefs_updated"` → optional `setGroupByPrefs` (replace, not merge). See change: session-list-group-by. `runtime_update_{progress,staged,failed}` → `runtime-update-event` DOM event. See change: electron-runtime-overlay-updates. |
| `useMobile.tsx` | Re-export shim. Forwards `useMobile` from `@blackbelt-technology/pi-dashboard-client-utils/useMobile`. Migration Layer 0. |
| `useModelCatalogue.ts` | `useModelCatalogue({enabled, seedFromCache})` over `fetchModelCatalogue`: `catalogue`, last-good `models`, `loading` (cold only), `unavailable`, `refetch`. Extracted from `SettingsPanel`. Exports `useModelCatalogue`, `resetModelCatalogueCache`. See changes: settings-default-model-without-session, redesign-directory-home-split. |
| `useNetworkDenied.ts` | Probes `/api/health` while the socket is offline; a 403 `network_not_allowed` resolves to `{hint}` for `ConnectionStatusBanner` — separates "host refused by the guard" from "transport dropped". See change: add-lan-knock-pairing. Probes in `offline` AND `auth_required`; a 200 `/api/health` with `localProof:"required"` (or a 403 `local_proof_required`) resolves to `{reason:"local_proof_required", hint}`. See change: close-container-loopback-impersonation (D3). |
| `useOpenSpecActions.ts` | OpenSpec action callbacks. `handleOpenSpecRefresh`/`handleBulkArchive` send WS… → see `useOpenSpecActions.ts.AGENTS.md` |
| `useOpenSpecReader.ts` | Fetches OpenSpec change artifact content. `activeTab` derives from URL `initialArtifact` (single source of… → see `useOpenSpecReader.ts.AGENTS.md` |
| `useOpenSpecReconcile.ts` | New. Reconciliation pull (D7): sends one `openspec_get` per rendered cwd with no settled OpenSpec entry and no in-flight request; 15 s per-cwd timeout; clears in-flight on socket open. See change: fix-connect-snapshot-frame-loss. |
| `usePackageOperations.ts` | Subscriber over singleton `packageQueue`. Returns `operation`, `install`/`remove`/`update` (enqueue),… → see `usePackageOperations.ts.AGENTS.md` |
| `usePackageSearch.ts` | Debounced npm package search via `GET /api/packages/search?q=&type=`. → see `usePackageSearch.ts.AGENTS.md` |
| `usePendingPromptTimeout.ts` | Calls `onTimeout` after 30s if `hasPendingPrompt` stays true and `paused` is false. → see `usePendingPromptTimeout.ts.AGENTS.md` |
| `usePersistedBoolean.ts` | Exports `usePersistedBoolean(key)` → `[boolean|null, set]`. localStorage tri-state flag (null = never chosen); storage failure degrades to memory. See change: addons-hub-declutter. |
| `usePiChangelog.ts` | Lazy hook (enabled gate). Refetches on `pi_core_update_complete` WS event for matching `pkg`. Never throws. See change: pi-update-whats-new-panel. |
| `usePiCompatibility.ts` | NEW. Fetches `/api/health` on mount + every 60s (instance-scoped: invoke ONCE per panel, pass fields down). → see `usePiCompatibility.ts.AGENTS.md` |
| `usePiCoreVersions.ts` | Fetches `GET /api/pi-core/versions` into `status: PiCoreStatus` with `isLoading`/`error`/`refresh(force?)`. Polls every 30 min. Force-refreshes on `pi-core-event` `pi_core_update_complete`. |
| `usePiResourceFileFetch.ts` | Fetches `GET /api/pi-resource-file?path=` into `{ content, isLoading, error }`. → see `usePiResourceFileFetch.ts.AGENTS.md` |
| `usePiResources.ts` | Fetches `GET /api/pi-resources?cwd=&refresh=` into `data: PiResourcesResult` with… → see `usePiResources.ts.AGENTS.md` |
| `usePreviewExposure.ts` | `usePreviewExposure()`: `GET /api/live-server/policy`, re-read on WS push; fails closed (exposed) when unknown; exposes `{ready,exposed,epoch,promptingEnabled,refresh}`. See change: improve-canvas-html-and-url-ux. |
| `usePushSubscription.ts` | Web Push for this browser. Returns `{supported, secureContext, serverEnabled, status, subscribe, unsubscribe, sendTest}`. Fetches `/api/push/vapid-public-key` (non-ok → `serverEnabled:false`); re-registers an existing subscription on mount (idempotent); `subscribe` → permission + `pushManager.subscribe` + `POST /api/push/register {transport:"web-push"}` (failed register → browser unsubscribed, status stays `unsubscribed`); tokenId in localStorage `pi-dashboard.push.tokenId` for unsubscribe DELETE. See change: add-server-push-notifications. |
| `useRemoteAccessIndicator.ts` | Single owner of Remote access state: 30s `/api/tunnel-status` poll (+ gated detail), `useLiveReachability` broadcast, `pairingApprovalStore` pending count, `resolvedBindHost`-keyed `takeFreshRun` resume. Returns `{tone,label,state,pending,resumeRun,dialogOpen,openDialog(trigger),closeDialog}`; `closeDialog` returns focus to the opener or the first visible `connection-chip`. Called once, in `App`. See change: declutter-sidebar-header. |
| `useResizeDrag.ts` | `useResizeDrag({axis,cursor,onStart?,onPreview,onEnd})` → `{onPointerDown,onMouseDown}`. Shared drag lifecycle for split/rail/sidebar/diff-tree handles. Primary `pointerdown` only; module-level owner-token slot = one drag at a time. Window `pointermove/up/cancel` + handle `lostpointercapture` attached on start, removed on end. `onPreview` ≤1/frame (rAF). Lazy `z-lightbox` shield on first moved move. Ends on up / cancel / lostcapture / `buttons===0` move. Unmount tears down, no `onEnd`. Composes `useBodyDragStyle`. See change: fix-split-divider-drag. |
| `useResourceActivation.ts` | Owns the Resources-surface activation UX. `useResourceActivation(cwd?)` → `{isEnabled,… → see `useResourceActivation.ts.AGENTS.md` |
| `usePluginEnabledSet.ts` | Drives `registry.setEnabledSet(ids)` from `/api/health.plugins[]` snapshot on mount + on every… → see `usePluginEnabledSet.ts.AGENTS.md` |
| `usePluginToggle.tsx` | Exports `usePluginList`, `usePluginToggle`, `applyDesiredEnabled`. → see `usePluginToggle.tsx.AGENTS.md` |
| `usePopoverFlip.ts` | Shared viewport-anchored popover positioning hook. `usePopoverFlip(triggerRef, { open, estimatedHeight?,… → see `usePopoverFlip.ts.AGENTS.md` |
| `useProvidersReady.ts` | Polls `/api/providers` + `/api/provider-auth/status`, returns `ProvidersReadyState` (`loading`, `ready`,… → see `useProvidersReady.ts.AGENTS.md` |
| `useRecommendedExtensions.ts` | Fetches `GET /api/packages/recommended`, returns `EnrichedRecommendedExtension[]` +… → see `useRecommendedExtensions.ts.AGENTS.md` |
| `useRuntimeStatus.ts` | NEW. GET `/api/runtime/status` + `runtime-update-event` refresh/progress. Sequenced loads (stale response dropped), unmount-safe, fetch errors → `error`. Exports `useRuntimeStatus`, types `RuntimeStatus`/`RuntimeInfo`. See change: electron-runtime-overlay-updates. |
| `useServerCapabilities.ts` | Reads `/api/health` once: `{systemOpen, platform?}` (`platform` = server `process.platform`, string or `undefined`; labels the Reveal action). Defaults `{systemOpen:false}` on failure. See change: scope-anchor-editor-pane-controls (D10). |
| `useServices.ts` | `useServices({onMessage, ws, delayMs?, fetchList?})` → `{list, loading, error, refetch, canOperate}`. Refetches ONLY `GET /api/services`, after a random 100–400 ms delay (burst collapses; single-flight + one trailing), on `services_changed` and on reconnect; no timer polling. Tests: `__tests__/useServices.test.tsx`. See change: add-services-settings-ui. |
| `useSessionActions.ts` | Session action callbacks extracted from App.tsx. Sends… → see `useSessionActions.ts.AGENTS.md` Swaps hide/unhide for `handleArchiveSession` and `handleUnarchiveSession`. See change: archive-sessions-lazy-load. |
| `useSessionDiff.ts` | Fetches `GET /api/session-diff?sessionId=`, returns `SessionDiffResponse` + `isLoading`/`error`/`refresh`. Refetches on `sessionId` change. Exports `useSessionDiff`, `UseSessionDiffResult`. `refresh` returns a promise; `{auto:false}` leaves every fetch to the caller; a session change clears data and drops late responses of the previous session. See change: add-composer-dock. |
| `useDockDiff.ts` | Changes-lane data: `useDockDiff({sessionId,working,dirtyCount})` → `{files,outOfCwd,count,capped,totals,otherChangesCount,loaded,failed,retry,refreshOnExpand}` over `useSessionDiff({auto:false})`. Scheduler: first load immediate; turn-end + idle dirty-count triggers wait `DOCK_DIFF_SETTLE_MS` (1 s); ≤1 request in flight; trigger in flight / inside the window = ONE pending refetch; window 2 s, doubles per consecutive request slower than 300 ms (cap 30 s). Count/totals cover in-cwd owned files; exactly 200 = `capped` (`200+`); totals fall back to per-file sums then `null`. See change: add-composer-dock (4.2, 4.3). |
| `useSessionRouteResolution.ts` | `useSessionRouteResolution` derives the canonical held session id for `/session/:id[/diff\|/editor]` during render (`none\|pending\|ok\|ambiguous\|notFound\|vanished`), sticky per route visit across reconnects; one `GET /api/sessions?id=` lookup per route id per connection (also verifies a held PREFIX match against the full registry before committing; replies from a previous connection epoch are discarded), merged stripped into `sessions` only; 401/403 → auth-loss, network/5xx → `notFound`+retry. Also `useVanishedRedirect` (home, once) and `useCanonicalRouteUrl` (replace to canonical URL). See change: add-session-ui-deep-links-for-agents. |
| `useSessionState.ts` | Embed-side session-state accumulator. Exports `useSessionState(sessionId?)` (`{state, apply, reset}`) and the… → see `useSessionState.ts.AGENTS.md` |
| `useSidebarState.ts` | Persists sidebar `width` + `collapsed` to `localStorage` (`dashboard:sidebar-width`,… → see `useSidebarState.ts.AGENTS.md` |
| `useSideFlyoutPosition.ts` | Side placement for the session flyout: `computeSideFlyoutPosition` (card.right+8, clamp, maxHeight) + hook writing `left/top/maxHeight` through refs on capture-phase scroll (ignores the panel's own scroll), resize and card `ResizeObserver`. Anchor and point modes; never React state. See change: add-session-actions-flyout. |
| `useStaleToolReconcile.ts` | Session-scoped stale running-tool heal (survives transcript virtualization). → see `useStaleToolReconcile.ts.AGENTS.md` |
| `useSwipeBack.ts` | iOS-style left-edge swipe-back gesture. Touch listeners decide horizontal vs vertical after 10px, triggers… → see `useSwipeBack.ts.AGENTS.md` |
| `useTreeColumnWidth.ts` | Persisted width + drag lifecycle for the Instructions folder-tree column (peer of `useSidebarState`). → see `useTreeColumnWidth.ts.AGENTS.md` |
| `useTheme.ts` | Theme mode + named-theme state. Reads `dashboard:theme`/`dashboard:theme-name` from `localStorage`, resolves… → see `useTheme.ts.AGENTS.md` |
| `useToolFullResult.ts` | NEW. Fetch hook `useToolFullResult(sessionId, toolCallId) → { result?, error?, loading, fetchFull }`. → see `useToolFullResult.ts.AGENTS.md` |
| `useViewDispatcher.ts` | Sends `session_view`/`session_unview` on `viewedSessionId` transitions, re-sends `session_view` on every WebSocket (re)connect into `connected`. Exports `useViewDispatcher`, `UseViewDispatcherDeps`. |
| `useWebSocket.ts` | WebSocket lifecycle: connects `url`, parses `ServerToBrowserMessage`, exposes `send`/`onMessage`/`status`/`ws`… → see `useWebSocket.ts.AGENTS.md` |
| `useZoomPan.ts` | Re-export shim. Forwards `@blackbelt-technology/pi-dashboard-client-utils/useZoomPan` (moved in `complete-flows-plugin-migration` Layer 0). |
| `useAcpAgents.ts` | Configured ACP agents `{id,name}` from `GET /api/acp/agents`; module-cached; empty on failure. `useAcpAgents()`. See change: add-acp-session-driver. |
| `useAgentAwareSpawn.ts` | Wraps a `handleSpawnSession` callback to add the folder's REMEMBERED agent when none given (board / landing spawns). See change: add-acp-session-driver. |