(
query: string,
options?: { limit?: number; exact?: boolean },
)
| 3245 | * Searches across same-repo worktrees by default. |
| 3246 | */ |
| 3247 | export async function searchSessionsByCustomTitle( |
| 3248 | query: string, |
| 3249 | options?: { limit?: number; exact?: boolean }, |
| 3250 | ): Promise<LogOption[]> { |
| 3251 | const { limit, exact } = options || {} |
| 3252 | // Use worktree-aware loading to search across same-repo sessions |
| 3253 | const worktreePaths = await getWorktreePaths(getOriginalCwd()) |
| 3254 | const allStatLogs = await getStatOnlyLogsForWorktrees(worktreePaths) |
| 3255 | // Enrich all logs to access customTitle metadata |
| 3256 | const { logs } = await enrichLogs(allStatLogs, 0, allStatLogs.length) |
| 3257 | const normalizedQuery = query.toLowerCase().trim() |
| 3258 | |
| 3259 | const matchingLogs = logs.filter(log => { |
| 3260 | const title = log.customTitle?.toLowerCase().trim() |
| 3261 | if (!title) return false |
| 3262 | return exact ? title === normalizedQuery : title.includes(normalizedQuery) |
| 3263 | }) |
| 3264 | |
| 3265 | // Deduplicate by sessionId - multiple logs can have the same sessionId |
| 3266 | // if they're different branches of the same conversation. Keep most recent. |
| 3267 | const sessionIdToLog = new Map<UUID, LogOption>() |
| 3268 | for (const log of matchingLogs) { |
| 3269 | const sessionId = getSessionIdFromLog(log) |
| 3270 | if (sessionId) { |
| 3271 | const existing = sessionIdToLog.get(sessionId) |
| 3272 | if (!existing || log.modified > existing.modified) { |
| 3273 | sessionIdToLog.set(sessionId, log) |
| 3274 | } |
| 3275 | } |
| 3276 | } |
| 3277 | const deduplicated = Array.from(sessionIdToLog.values()) |
| 3278 | |
| 3279 | // Sort by recency |
| 3280 | deduplicated.sort((a, b) => b.modified.getTime() - a.modified.getTime()) |
| 3281 | |
| 3282 | // Apply limit if specified |
| 3283 | if (limit) { |
| 3284 | return deduplicated.slice(0, limit) |
| 3285 | } |
| 3286 | |
| 3287 | return deduplicated |
| 3288 | } |
| 3289 | |
| 3290 | /** |
| 3291 | * Metadata entry types that can appear before a compact boundary but must |
no test coverage detected