feat: add bookmarks panel for viewing pinned messages across sessions

Add a new BookmarksPanel accessible via Ctrl/Cmd+Shift+B or the
command palette (View Bookmarks). The panel lists all pinned messages
across all sessions globally, with:

- Click-to-navigate: switches session and scrolls to the message
- Inline unpin: remove bookmarks directly from the panel
- Keyboard navigation: arrow keys, Enter, Escape
- Empty state when no messages are pinned

New shared helper listPinnedMessages() in sessionLibrary.ts derives
pinned messages from the workspace state in the renderer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-30 16:05:08 +01:00
co-authored by Copilot
parent e37d69bd63
commit 770a0f3529
5 changed files with 271 additions and 1 deletions
+38
View File
@@ -395,6 +395,44 @@ export function editAndResendSessionRecord(
};
}
// ── Pinned messages ──
export interface PinnedMessageHit {
session: SessionRecord;
projectName: string;
message: ChatMessageRecord;
/** Truncated preview of the message content. */
snippet: string;
}
function extractMessageSnippet(content: string, maxLength = 120): string {
const collapsed = content.replace(/\n+/g, ' ').trim();
if (collapsed.length <= maxLength) return collapsed;
return collapsed.slice(0, maxLength) + '…';
}
export function listPinnedMessages(workspace: WorkspaceState): PinnedMessageHit[] {
const projectNames = new Map<string, string>(
workspace.projects.map((p) => [p.id, isScratchpadProject(p) ? 'Scratchpad' : p.name]),
);
return workspace.sessions
.filter((session) => !session.isArchived)
.flatMap((session) =>
session.messages
.filter((message) => message.isPinned && message.content)
.map((message) => ({
session,
projectName: projectNames.get(session.projectId) ?? 'Unknown',
message,
snippet: extractMessageSnippet(message.content),
})),
)
.sort((a, b) => b.message.createdAt.localeCompare(a.message.createdAt));
}
// ── Session query ──
export function querySessions(workspace: WorkspaceState, input: QuerySessionsInput): SessionQueryResult[] {
const projectsById = new Map<string, ProjectRecord>(workspace.projects.map((project) => [project.id, project]));
const patternsById = new Map<string, PatternDefinition>(workspace.patterns.map((pattern) => [pattern.id, pattern]));