@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
22import os from "node:os" ;
33import path from "node:path" ;
44import { afterEach , describe , expect , it } from "vitest" ;
5+ import { SessionManager } from "../sessions/session-manager.js" ;
56import { prepareSessionManagerForRun } from "./session-manager-init.js" ;
67
78const tempPaths : string [ ] = [ ] ;
@@ -205,4 +206,60 @@ describe("prepareSessionManagerForRun", () => {
205206 ] ) ;
206207 expect ( sessionManager . flushed ) . toBe ( true ) ;
207208 } ) ;
209+
210+ it ( "keeps recovered user-only transcripts through open and run preparation" , async ( ) => {
211+ const sessionFile = await makeTempFile ( ) ;
212+ const userEntry = {
213+ type : "message" ,
214+ id : "user-1" ,
215+ parentId : null ,
216+ timestamp : "2026-05-27T00:00:01.000Z" ,
217+ message : { role : "user" , content : "persisted prompt" } ,
218+ } ;
219+ await fs . writeFile (
220+ sessionFile ,
221+ [ '{"type":"session","id":"broken"' , JSON . stringify ( userEntry ) ] . join ( "\n" ) + "\n" ,
222+ "utf-8" ,
223+ ) ;
224+
225+ const sessionManager = SessionManager . open ( sessionFile , path . dirname ( sessionFile ) , "/old/cwd" ) ;
226+
227+ await prepareSessionManagerForRun ( {
228+ sessionManager,
229+ sessionFile,
230+ hadSessionFile : true ,
231+ sessionId : "new-session" ,
232+ cwd : "/tmp/task-repo" ,
233+ } ) ;
234+ sessionManager . appendMessage ( {
235+ role : "assistant" ,
236+ content : [ { type : "text" , text : "response" } ] ,
237+ api : "messages" ,
238+ provider : "anthropic" ,
239+ model : "sonnet-4.6" ,
240+ usage : {
241+ input : 0 ,
242+ output : 0 ,
243+ cacheRead : 0 ,
244+ cacheWrite : 0 ,
245+ totalTokens : 0 ,
246+ cost : { input : 0 , output : 0 , cacheRead : 0 , cacheWrite : 0 , total : 0 } ,
247+ } ,
248+ stopReason : "stop" ,
249+ timestamp : Date . now ( ) ,
250+ } ) ;
251+
252+ const entries = ( await fs . readFile ( sessionFile , "utf-8" ) )
253+ . trim ( )
254+ . split ( "\n" )
255+ . map (
256+ ( line ) => JSON . parse ( line ) as { type : string ; id ?: string ; message ?: { role ?: string } } ,
257+ ) ;
258+ expect ( entries . map ( ( entry ) => entry . type ) ) . toEqual ( [ "session" , "message" , "message" ] ) ;
259+ expect ( entries [ 0 ] ) . toEqual (
260+ expect . objectContaining ( { type : "session" , id : "new-session" , cwd : "/tmp/task-repo" } ) ,
261+ ) ;
262+ expect ( entries [ 1 ] ) . toEqual ( userEntry ) ;
263+ expect ( entries [ 2 ] ?. message ?. role ) . toBe ( "assistant" ) ;
264+ } ) ;
208265} ) ;
0 commit comments