git:20261019.a95630f to git:20261022.c655001

3 added, 0 removed. Audit A to A.

# DOX — packages/client/src/lib/session
Files in this directory. One row per source file. See change: fold-oversized-agents-directories.
| File | Purpose |
|------|---------|
| `group-by-migration.ts` | One-shot retirement of localStorage urgency toggle (`LEGACY_FOLDER_URGENCY_SORT_KEY` = `dashboard:folder-urgency-sort`). `runUrgencyMigration(prefs, setFolderGroupBy, sent)`: no-op until prefs known; sends `status` once per page load for legacy folders w/o explicit mode; explicit modes kept; key removed only when echoed prefs confirm every folder (dropped socket → retry next load). Exports `readLegacyUrgencyFolders`, `clearLegacyUrgencyFolders`, `decideUrgencyMigration`. See change: session-list-group-by. |
| `card-section-meta.ts` | Private `CARD_SECTION_META` (id, group builtin/plugin/lines, plugin `slot`, i18n label/description) + `useOfferedCardSections()` (plugin rows only when `useSlotHasAnyClaims(slot)`). Shared by Directory Settings page + global Settings block. See change: configurable-session-card-sections. See change: align-ui-with-theme-tokens: spawn-section description "Quick new-session and new-worktree buttons.". `CardSectionGroup` widens to builtin/plugin/lines/directory/effects; `fx-*` rows carry `globalOnly` (no folder override). Per-plugin rows are GENERATED from live slot claims (never a static table): `badge-*`/`actionbar-*` land in the plugin group, `pill-*` in the directory group, display names resolved from the context `pluginNames` map. See change: add-focus-mode-and-card-block-toggles. |
+ | `held-ended.ts` | `heldEndedByGroup(sessions, pinned, lookupOnlyIds?)`: ended count per group key; lookup-merged ids excluded so paging is not suppressed. See change: add-session-ui-deep-links-for-agents. |
+ | `lookup-merge.ts` | `stripLookupRow` (drops `notifyLog`/`uiUrl`/`diffUrl`), `mergeLookupRows` (Map overwrite by id), `addLookupOnly`/`removeLookupOnly` (reference-stable Set updates). See change: add-session-ui-deep-links-for-agents. |
| `prompt-desync.ts` | Pending-prompt desync detector (D10): pure `isPromptDesync(gates+heldMs)` + `promptDesyncCondition` + `promptDesyncGatesFromState(state, replayInFlight)` over 5 gates (`ask_user` · no pending request · not ended · no replay · held ≥ `PROMPT_DESYNC_GRACE_MS` 5000 ms); `usePromptDesync(gates, scope?)` owns the held-duration timer — resets on every failing gate AND on `scope` (session) switch. See change: fix-pending-prompt-lost-on-replay. |
+ | `resolve-session-route-id.ts` | `resolveSessionRouteId(routeId, ids)` → `match\|ambiguous\|none`: raw exact wins, else case-insensitive exact, else unique prefix >= 8 chars; returns the held live-cased id. See change: add-session-ui-deep-links-for-agents. |
| `retry-projection.ts` | Pure projection of per-session `retryState` into the card-side pair `{ retrySessionIds, retryAttemptMap }`. Exports `deriveRetryProjection(sessionStates)`, `RetryProjection`. Membership is `retryState` alone — NOT gated on `!lastError`, which excluded the common retry-while-errored case. See change: unify-retry-visibility. |
| `selectedSessionId.ts` | Pure derivation of selected session id from wouter route matches. → see `selectedSessionId.ts.AGENTS.md` |
| `selectViewedSessionId.ts` | Pure selector for currently-viewed session id from `/session/:id` route. → see `selectViewedSessionId.ts.AGENTS.md` |
| `session-card-time.ts` | Pure picker of session-card relative-time badge anchor timestamp. Exports `selectBadgeTimestamp(session)`. → see `session-card-time.ts.AGENTS.md` |
| `session-display-name.ts` | Pure derivation of session display name. Exports `getSessionDisplayName(session)` → name → firstMessage (truncated 50 chars) → cwd last segment → ID prefix (8 chars). |
| `session-filter-storage.ts` | localStorage persistence for session-list filter state. Exports `removeLegacyHiddenSessions`, `getIncludeArchive`, `setIncludeArchive`,… → see `session-filter-storage.ts.AGENTS.md`. See change: archive-sessions-lazy-load. |
| `session-grouping.ts` | Pure session grouping/sorting/filtering utilities. Exports `DirectoryGroup`, `WorkspaceGroup`,… → see `session-grouping.ts.AGENTS.md` Adds optional `stubGroupCwds` (empty groups sort last) on both groupers. See change: fix-connect-snapshot-frame-loss. |
| `session-lanes.ts` | Pure lane logic. `classifyStatusLane(s, flags)` wraps `deriveStatusShape` (compacting→working ahead of notice/unread, unread idle / notice→review, ended→null); `classifyLocationLane` (gitWorktree→worktrees else main); `partitionIntoLanes(sessions, mode, order, assign?)` stable partition via `sortSessionsByOrder`, empty lanes omitted, none→one lane (laneId null); `mergeLaneOrder` slot-preserving merge; `resolveLaneDrop` (reject cross-lane / reorder same-lane / flat for ended); `completeStoredOrder(stored, loadedIds)` (merge base keeps paged-out ids); `explicitGroupBy`/`resolveEffectiveGroupBy` (override > default > none, pathKey lookup); `isLaneCollapsed`; `laneFingerprint` (lane-relevant fields only). See change: session-list-group-by. `laneFingerprint` includes `awaitingFileAccess`. See change: ask-agent-file-access-in-chat. |
| `session-list-scroll.ts` | Pure helper producing stable scroll-fingerprint of selected session card's position-affecting state. → see `session-list-scroll.ts.AGENTS.md` |
| `session-menu-items.ts` | Pure `deriveSessionMenu(session, ctx)` → `NEXT·SESSION·OPENSPEC·GIT·VIEW` groups (PLUGINS is hosted by the menu). Composes `deriveOpenSpecActions`, `deriveWorktreeActions`, `isMergePrimary` (via ctx), attachment resolution, readiness gate (`openspecGroupMode`). One emphasised NEXT item; `partitionRare` folds ≥ 2 rare items behind `More…`. Types `SessionMenuItem`/`SessionMenuGroup`/`SessionMenuActions`/`SessionDialogKind`. See change: add-session-actions-flyout. `SessionMenuItem.tone` (UiTone); `OPENSPEC_TONE` map; NEXT copy strips tone. See change: colorize-actions-menus. |
| `session-origin-view.ts` | Pure view predicates over a session's ORIGIN and MOVE state: `isRemoteOrigin(session)` (`originDeviceId` present; ABSENT MEANS LOCAL, which every pre-existing session relies on) and `hasMovedAway(session)` (`movedTo` present). Consumed by `SessionCard.tsx` (moved badge + origin chip), `SessionHeader.tsx` and `MobileActionMenu.tsx` to gate resume/fork — a remote-origin session's files are on another host and the server refuses the resume with 409. See change: add-pi-gateway-transport-identity. Adds `metaChipsVisible(session)` = moved ∨ remote-origin ∨ ACP (meta-row gate shared with the chips). See change: compact-session-card-header. |
| `session-status-visuals.ts` | Shared session-status visual primitives. Exports `statusColors`, `sourceIcons`, `sourceLabels`,… → see `session-status-visuals.ts.AGENTS.md` `floatAskUserFirst` DELETED (urgency toggle retired; Status mode Needs-you lane supersedes). See change: session-list-group-by. |
| `SessionAssetsContext.tsx` | Per-session image-asset registry context resolving `pi-asset:<hash>` srcs in `MarkdownContent` |