( sessionId: UUID, )
| 3867 | } |
| 3868 | |
| 3869 | export async function getLastSessionLog( |
| 3870 | sessionId: UUID, |
| 3871 | ): Promise<LogOption | null> { |
| 3872 | // Single read: load all session data at once instead of reading the file twice |
| 3873 | const { |
| 3874 | messages, |
| 3875 | summaries, |
| 3876 | customTitles, |
| 3877 | tags, |
| 3878 | agentSettings, |
| 3879 | worktreeStates, |
| 3880 | fileHistorySnapshots, |
| 3881 | attributionSnapshots, |
| 3882 | contentReplacements, |
| 3883 | contextCollapseCommits, |
| 3884 | contextCollapseSnapshot, |
| 3885 | } = await loadSessionFile(sessionId) |
| 3886 | if (messages.size === 0) return null |
| 3887 | // Prime getSessionMessages cache so recordTranscript (called after REPL |
| 3888 | // mount on --resume) skips a second full file load. -170~227ms on large sessions. |
| 3889 | // Guard: only prime if cache is empty. Mid-session callers (e.g. IssueFeedback) |
| 3890 | // may call getLastSessionLog on the current session — overwriting a live cache |
| 3891 | // with a stale disk snapshot would lose unflushed UUIDs and break dedup. |
| 3892 | if (!getSessionMessages.cache.has(sessionId)) { |
| 3893 | getSessionMessages.cache.set( |
| 3894 | sessionId, |
| 3895 | Promise.resolve(new Set(messages.keys())), |
| 3896 | ) |
| 3897 | } |
| 3898 | |
| 3899 | // Find the most recent non-sidechain message |
| 3900 | const lastMessage = findLatestMessage(messages.values(), m => !m.isSidechain) |
| 3901 | if (!lastMessage) return null |
| 3902 | |
| 3903 | // Build the transcript chain from the last message |
| 3904 | const transcript = buildConversationChain(messages, lastMessage) |
| 3905 | |
| 3906 | const summary = summaries.get(lastMessage.uuid) |
| 3907 | const customTitle = customTitles.get(lastMessage.sessionId as UUID) |
| 3908 | const tag = tags.get(lastMessage.sessionId as UUID) |
| 3909 | const agentSetting = agentSettings.get(sessionId) |
| 3910 | return { |
| 3911 | ...convertToLogOption( |
| 3912 | transcript, |
| 3913 | 0, |
| 3914 | summary, |
| 3915 | customTitle, |
| 3916 | buildFileHistorySnapshotChain(fileHistorySnapshots, transcript), |
| 3917 | tag, |
| 3918 | getTranscriptPathForSession(sessionId), |
| 3919 | buildAttributionSnapshotChain(attributionSnapshots, transcript), |
| 3920 | agentSetting, |
| 3921 | contentReplacements.get(sessionId) ?? [], |
| 3922 | ), |
| 3923 | worktreeSession: worktreeStates.get(sessionId), |
| 3924 | contextCollapseCommits: contextCollapseCommits.filter( |
| 3925 | e => e.sessionId === sessionId, |
| 3926 | ), |
no test coverage detected