mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-12 20:37:08 -07:00
131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import {
|
|
cleanMessage,
|
|
type SessionInfo,
|
|
type TextMatch,
|
|
} from '../../../utils/sessionUtils.js';
|
|
|
|
/**
|
|
* Sorts an array of sessions by the specified criteria.
|
|
* @param sessions - Array of sessions to sort
|
|
* @param sortBy - Sort criteria: 'date' (lastUpdated), 'messages' (messageCount), or 'name' (displayName)
|
|
* @param reverse - Whether to reverse the sort order (ascending instead of descending)
|
|
* @returns New sorted array of sessions
|
|
*/
|
|
export const sortSessions = (
|
|
sessions: SessionInfo[],
|
|
sortBy: 'date' | 'messages' | 'name',
|
|
reverse: boolean,
|
|
): SessionInfo[] => {
|
|
const sorted = [...sessions].sort((a, b) => {
|
|
switch (sortBy) {
|
|
case 'date':
|
|
return (
|
|
new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime()
|
|
);
|
|
case 'messages':
|
|
return b.messageCount - a.messageCount;
|
|
case 'name':
|
|
return a.displayName.localeCompare(b.displayName);
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
return reverse ? sorted.reverse() : sorted;
|
|
};
|
|
|
|
/**
|
|
* Finds all text matches for a search query within conversation messages.
|
|
* Creates TextMatch objects with context (10 chars before/after) and role information.
|
|
* @param messages - Array of messages to search through
|
|
* @param query - Search query string (case-insensitive)
|
|
* @returns Array of TextMatch objects containing match context and metadata
|
|
*/
|
|
export const findTextMatches = (
|
|
messages: Array<{ role: 'user' | 'assistant'; content: string }>,
|
|
query: string,
|
|
): TextMatch[] => {
|
|
if (!query.trim()) return [];
|
|
|
|
const lowerQuery = query.toLowerCase();
|
|
const matches: TextMatch[] = [];
|
|
|
|
for (const message of messages) {
|
|
const m = cleanMessage(message.content);
|
|
const lowerContent = m.toLowerCase();
|
|
let startIndex = 0;
|
|
|
|
while (true) {
|
|
const matchIndex = lowerContent.indexOf(lowerQuery, startIndex);
|
|
if (matchIndex === -1) break;
|
|
|
|
const contextStart = Math.max(0, matchIndex - 10);
|
|
const contextEnd = Math.min(m.length, matchIndex + query.length + 10);
|
|
|
|
const snippet = m.slice(contextStart, contextEnd);
|
|
const relativeMatchStart = matchIndex - contextStart;
|
|
const relativeMatchEnd = relativeMatchStart + query.length;
|
|
|
|
let before = snippet.slice(0, relativeMatchStart);
|
|
const match = snippet.slice(relativeMatchStart, relativeMatchEnd);
|
|
let after = snippet.slice(relativeMatchEnd);
|
|
|
|
if (contextStart > 0) before = '…' + before;
|
|
if (contextEnd < m.length) after = after + '…';
|
|
|
|
matches.push({ before, match, after, role: message.role });
|
|
startIndex = matchIndex + 1;
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
};
|
|
|
|
/**
|
|
* Filters sessions based on a search query, checking titles, IDs, and full content.
|
|
* Also populates matchSnippets and matchCount for sessions with content matches.
|
|
* @param sessions - Array of sessions to filter
|
|
* @param query - Search query string (case-insensitive)
|
|
* @returns Filtered array of sessions that match the query
|
|
*/
|
|
export const filterSessions = (
|
|
sessions: SessionInfo[],
|
|
query: string,
|
|
): SessionInfo[] => {
|
|
if (!query.trim()) {
|
|
return sessions.map((session) => ({
|
|
...session,
|
|
matchSnippets: undefined,
|
|
matchCount: undefined,
|
|
}));
|
|
}
|
|
|
|
const lowerQuery = query.toLowerCase();
|
|
return sessions.filter((session) => {
|
|
const titleMatch =
|
|
session.displayName.toLowerCase().includes(lowerQuery) ||
|
|
session.id.toLowerCase().includes(lowerQuery) ||
|
|
session.firstUserMessage.toLowerCase().includes(lowerQuery);
|
|
|
|
const contentMatch = session.fullContent
|
|
?.toLowerCase()
|
|
.includes(lowerQuery);
|
|
|
|
if (titleMatch || contentMatch) {
|
|
if (session.messages) {
|
|
session.matchSnippets = findTextMatches(session.messages, query);
|
|
session.matchCount = session.matchSnippets.length;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
};
|