feat(sessions): Batch 1 PR-2 — pinned zone + manual hide
Merged
GR
4mo ago+827+827+012345678901234567890123456789-13-13-01234567890123456789
Summary
Session-finding Batch 1 PR-2 — pins & manual hide (plan: docs/session-finding-plan.md §4.4). Follows PR #132; design confirmed with the user (pinned-section model chosen over a separate favorites view — zero mode-switch for the highest-frequency path).
📌 Pins
- Pinned zone at the top of the Sessions list: collapsible header (
▾ 📌 Pinned (N)), collapsed state remembered (localStorage). Rows fully reuse the existing session row — status dots, badges, PR links, snippets all work. - Dual placement: a pinned session also keeps its chronological spot in the timeline, marked with a gold ★ — the zone is a shortcut, not a move.
- Pin/unpin: hover 📌 icon on the selected row, or ⌘D.
- Works for any displayed row, including deep-search matches beyond the loaded ~100: the zone resolves those via the new
get-sessions-by-idsIPC (reads the full session cache) and lazily enriches them. - While searching, the zone steps aside — results are one unified list (★ still marks pinned matches).
⊘ Manual hide (C1's missing piece)
- Hover ⊘ icon or ⇧⌘D: forces the session into the minor-sessions fold regardless of its stats. Reversible from inside the expanded fold (the icon shows as active); hidden sessions remain searchable (search always shows everything).
- Pin and hide are mutually exclusive: pinning unhides, hiding unpins (encoded in the pure transition helpers).
Store
~/.config/codev/session-marks.json — single cross-account file next to the accounts registry (JSON on purpose: tiny data, human-debuggable, no SQLite features needed):
{ "version": 1,
"pins": { "<sessionId>": { "pinnedAt": "…", "cwd": "…", "accountLabel": "…", "group": null } },
"hidden": ["<sessionId>"] }
- fs.watch (parent-dir watch, filename-filtered — the atomic temp+rename write replaces the inode, which would detach a file watcher) → debounced push to the renderer, same pattern as the status files.
- IPC responses also return the updated marks for instant UI feedback (watch push is the backup path).
- sessionIds are resume-stable (verified on Claude Code 2.1.207:
--resume/--continuereuse the id; only--fork-sessionforks), so plain sessionId keying needs no migration logic.groupfield reserved for v2 named groups.
Tests
- 7 new unit tests (
session-marks.test.ts): normalize (garbage/defaults/dedupe), pin↔hide mutual exclusion, idempotent removals, input immutability, tmpdir file roundtrip incl. corrupt-file recovery and no temp leftovers — 52 total pass;tsc --noEmitclean.
Out of scope
- Named pin groups (v2; schema field reserved), drag reordering.
/pinin-session slash command (Batch 3, plan §6).- Expired-session badge for pinned-but-cleaned transcripts (#135).
🤖 On behalf of @grimmerk — generated with Claude Code
Summary by cubic
Adds session pins and manual hide with a collapsible 📌 Pinned zone. Pinned sessions live only in the zone while browsing, remain searchable, and marks sync across accounts via ~/.config/codev/session-marks.json.
-
New Features
- Collapsible 📌 Pinned zone; collapse state remembered. New pins append to the bottom.
- Pin/unpin via hover 📌 or Cmd+D. Hide/unhide via Shift+Cmd+D; pin and hide are mutually exclusive.
- While searching, the zone hides; results are one list with a ★ on pinned matches.
- Deep-search pins resolve via
getSessionsByIds+ lazy enrichment; unresolved pins render placeholders with '… msgs' so Pinned(N) stays stable. - Zone rows include Hide (unpin + fold). Hidden rows show a dim ⊘; the minor fold label adds “N hidden.”
-
Bug Fixes
- Marks watcher closes on error, self-heals with bounded backoff, and logs retries; extracted path-based
watchMarksFile; new test covers the watcher error path (53 tests total). webContents.sendguarded withisDestroyed(); marks listener returns an unsubscribe and cleans up; all marks IPC calls.catcherrors; audit logs added for pin/unpin/hide.- Stale
getSessionsByIdsresponses are dropped; collapsing the pinned zone snaps selection to the top. - Suppress hover re-selection during pin/hide layout shifts; selection re-anchors to the same session; Cmd+D requires an explicit selection; keyboard shortcuts keep working after clicking icons/folds.
- Marks watcher closes on error, self-heals with bounded backoff, and logs retries; extracted path-based
Summary by CodeRabbit
- New Features
- Added a collapsible 📌 Pinned sessions zone with per-session ordering (★), remembered collapse state, and a minor-sessions hide fold.
- Pin/hide uses keyboard shortcuts and row hover controls, enforces pin/hide mutual exclusivity, and keeps pinned results included during search (with placeholders for unresolved pins).
- Persisted pin/hide state in
~/.config/codev/session-marks.json, shared across accounts, with live sync when the file changes.
- Documentation
- Updated the session switching documentation with the new pin/hide workflows and shortcuts.
- Tests
- Added unit coverage for marks normalization, pin/hide transitions, file roundtrips, and watcher error recovery.