(
sessionPath: string
)
| 140 | } |
| 141 | |
| 142 | async function parseClaudeSession( |
| 143 | sessionPath: string |
| 144 | ): Promise<ExtractedContext | null> { |
| 145 | // Read ALL lines — we need both the first messages (intent) and last messages (state) |
| 146 | const allLines = await readLastLines(sessionPath, 500); |
| 147 | |
| 148 | // Separate into first messages (intent) and last messages (current state) |
| 149 | const firstUserMessages: string[] = []; |
| 150 | const lastUserMessages: string[] = []; |
| 151 | const lastAssistantMessages: string[] = []; |
| 152 | |
| 153 | for (const line of allLines) { |
| 154 | try { |
| 155 | const entry = JSON.parse(line); |
| 156 | const text = extractMessageText(entry); |
| 157 | if (!text || text.length < 5) continue; |
| 158 | |
| 159 | if (entry.type === "user") { |
| 160 | // Collect first 3 user messages as intent |
| 161 | if (firstUserMessages.length < 3) { |
| 162 | firstUserMessages.push(text); |
| 163 | } |
| 164 | lastUserMessages.push(text); |
| 165 | } else if (entry.type === "assistant" && text.length > 20) { |
| 166 | lastAssistantMessages.push(text); |
| 167 | } |
| 168 | } catch { |
| 169 | // Skip malformed lines |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | if (firstUserMessages.length === 0) return null; |
| 174 | |
| 175 | // The FIRST user message is the intent — what they wanted to do |
| 176 | const intent = firstUserMessages[0]; |
| 177 | const intentFirstLine = intent.split("\n")[0].trim(); |
| 178 | // Use first line if short, or first 200 chars |
| 179 | const task = intentFirstLine.length < 300 ? intentFirstLine : intent.slice(0, 200); |
| 180 | |
| 181 | // Later user messages show what else was requested |
| 182 | const additionalRequests = firstUserMessages.slice(1).map((m) => { |
| 183 | const line = m.split("\n")[0].trim(); |
| 184 | return line.length < 200 ? line : line.slice(0, 200); |
| 185 | }); |
| 186 | |
| 187 | // Use assistant messages for decisions/approaches/state |
| 188 | const recentAssistant = lastAssistantMessages.slice(-10); |
| 189 | const decisions = extractDecisions(recentAssistant); |
| 190 | const approaches = extractApproaches(recentAssistant); |
| 191 | const currentState = extractState(recentAssistant); |
| 192 | const nextSteps = extractNextSteps(recentAssistant); |
| 193 | |
| 194 | return { |
| 195 | task, |
| 196 | approaches: [...additionalRequests.map(r => `User also asked: ${r}`), ...approaches], |
| 197 | decisions, |
| 198 | currentState: currentState || "Session data parsed from Claude Code", |
| 199 | nextSteps, |
no test coverage detected