(log: LogOption)
| 3127 | * If the log is already full or loading fails, returns the original log. |
| 3128 | */ |
| 3129 | export async function loadFullLog(log: LogOption): Promise<LogOption> { |
| 3130 | // If already full, return as-is |
| 3131 | if (!isLiteLog(log)) { |
| 3132 | return log |
| 3133 | } |
| 3134 | |
| 3135 | // Use the fullPath from the index entry directly |
| 3136 | const sessionFile = log.fullPath |
| 3137 | if (!sessionFile) { |
| 3138 | return log |
| 3139 | } |
| 3140 | |
| 3141 | try { |
| 3142 | const { |
| 3143 | messages, |
| 3144 | summaries, |
| 3145 | customTitles, |
| 3146 | tags, |
| 3147 | agentNames, |
| 3148 | agentColors, |
| 3149 | agentSettings, |
| 3150 | prNumbers, |
| 3151 | prUrls, |
| 3152 | prRepositories, |
| 3153 | modes, |
| 3154 | worktreeStates, |
| 3155 | fileHistorySnapshots, |
| 3156 | attributionSnapshots, |
| 3157 | contentReplacements, |
| 3158 | contextCollapseCommits, |
| 3159 | contextCollapseSnapshot, |
| 3160 | leafUuids, |
| 3161 | } = await loadTranscriptFile(sessionFile) |
| 3162 | |
| 3163 | if (messages.size === 0) { |
| 3164 | return log |
| 3165 | } |
| 3166 | |
| 3167 | // Find the most recent user/assistant leaf message from the transcript |
| 3168 | const mostRecentLeaf = findLatestMessage( |
| 3169 | messages.values(), |
| 3170 | msg => |
| 3171 | leafUuids.has(msg.uuid) && |
| 3172 | (msg.type === 'user' || msg.type === 'assistant'), |
| 3173 | ) |
| 3174 | if (!mostRecentLeaf) { |
| 3175 | return log |
| 3176 | } |
| 3177 | |
| 3178 | // Build the conversation chain from this leaf |
| 3179 | const transcript = buildConversationChain(messages, mostRecentLeaf, { |
| 3180 | includeLogicalParents: true, |
| 3181 | }) |
| 3182 | // Leaf's sessionId — forked sessions copy chain[0] from the source, but |
| 3183 | // metadata entries (custom-title etc.) are keyed by the current session. |
| 3184 | const sessionId = mostRecentLeaf.sessionId as UUID | undefined |
| 3185 | return { |
| 3186 | ...log, |
no test coverage detected