(log: LogOption)
| 3031 | * If the log is already full or loading fails, returns the original log. |
| 3032 | */ |
| 3033 | export async function loadFullLog(log: LogOption): Promise<LogOption> { |
| 3034 | // If already full, return as-is |
| 3035 | if (!isLiteLog(log)) { |
| 3036 | return log |
| 3037 | } |
| 3038 | |
| 3039 | // Use the fullPath from the index entry directly |
| 3040 | const sessionFile = log.fullPath |
| 3041 | if (!sessionFile) { |
| 3042 | return log |
| 3043 | } |
| 3044 | |
| 3045 | try { |
| 3046 | const { |
| 3047 | messages, |
| 3048 | summaries, |
| 3049 | customTitles, |
| 3050 | tags, |
| 3051 | agentNames, |
| 3052 | agentColors, |
| 3053 | agentSettings, |
| 3054 | prNumbers, |
| 3055 | prUrls, |
| 3056 | prRepositories, |
| 3057 | modes, |
| 3058 | worktreeStates, |
| 3059 | goals, |
| 3060 | fileHistorySnapshots, |
| 3061 | attributionSnapshots, |
| 3062 | contentReplacements, |
| 3063 | contextCollapseCommits, |
| 3064 | contextCollapseSnapshot, |
| 3065 | leafUuids, |
| 3066 | } = await loadTranscriptFile(sessionFile) |
| 3067 | |
| 3068 | if (messages.size === 0) { |
| 3069 | const fallbackGoal = log.sessionId |
| 3070 | ? goals.get(log.sessionId as UUID) |
| 3071 | : undefined |
| 3072 | return fallbackGoal ? { ...log, goal: fallbackGoal } : log |
| 3073 | } |
| 3074 | |
| 3075 | // Find the most recent user/assistant leaf message from the transcript |
| 3076 | const mostRecentLeaf = findLatestMessage( |
| 3077 | messages.values(), |
| 3078 | msg => |
| 3079 | leafUuids.has(msg.uuid) && |
| 3080 | (msg.type === 'user' || msg.type === 'assistant'), |
| 3081 | ) |
| 3082 | if (!mostRecentLeaf) { |
| 3083 | const fallbackGoal = log.sessionId |
| 3084 | ? goals.get(log.sessionId as UUID) |
| 3085 | : undefined |
| 3086 | return fallbackGoal ? { ...log, goal: fallbackGoal } : log |
| 3087 | } |
| 3088 | |
| 3089 | // Build the conversation chain from this leaf |
| 3090 | const transcript = buildConversationChain(messages, mostRecentLeaf) |
no test coverage detected