@@ -14,6 +14,7 @@ import {
1414 isSessionArchiveArtifactName ,
1515 isSilentReplyPayloadText ,
1616 isUsageCountedSessionTranscriptFileName ,
17+ parseUsageCountedSessionIdFromFileName ,
1718 resolveSessionTranscriptsDirForAgent ,
1819 stripInboundMetadata ,
1920 stripInternalRuntimeContext ,
@@ -82,6 +83,15 @@ function shouldSkipTranscriptFileForDreaming(absPath: string): boolean {
8283 return false ;
8384}
8485
86+ function isUsageCountedSessionArchiveTranscriptPath ( absPath : string ) : boolean {
87+ const fileName = path . basename ( absPath ) ;
88+ return (
89+ isUsageCountedSessionTranscriptFileName ( fileName ) &&
90+ isSessionArchiveArtifactName ( fileName ) &&
91+ parseUsageCountedSessionIdFromFileName ( fileName ) !== null
92+ ) ;
93+ }
94+
8595function isDreamingNarrativeBootstrapRecord ( record : unknown ) : boolean {
8696 if ( ! record || typeof record !== "object" || Array . isArray ( record ) ) {
8797 return false ;
@@ -150,6 +160,30 @@ function isDreamingNarrativeSessionStoreKey(sessionKey: string): boolean {
150160 return sessionSegment . startsWith ( DREAMING_NARRATIVE_RUN_PREFIX ) ;
151161}
152162
163+ function hasCronRunSessionKey ( value : unknown ) : boolean {
164+ return typeof value === "string" && isCronRunSessionKey ( value ) ;
165+ }
166+
167+ function isCronRunGeneratedRecord ( record : unknown ) : boolean {
168+ if ( ! record || typeof record !== "object" || Array . isArray ( record ) ) {
169+ return false ;
170+ }
171+ const candidate = record as {
172+ sessionKey ?: unknown ;
173+ data ?: unknown ;
174+ } ;
175+ if ( hasCronRunSessionKey ( candidate . sessionKey ) ) {
176+ return true ;
177+ }
178+ if ( ! candidate . data || typeof candidate . data !== "object" || Array . isArray ( candidate . data ) ) {
179+ return false ;
180+ }
181+ const nested = candidate . data as {
182+ sessionKey ?: unknown ;
183+ } ;
184+ return hasCronRunSessionKey ( nested . sessionKey ) ;
185+ }
186+
153187function normalizeComparablePath ( pathname : string ) : string {
154188 const resolved = path . resolve ( pathname ) ;
155189 return process . platform === "win32" ? resolved . toLowerCase ( ) : resolved ;
@@ -242,11 +276,20 @@ function classifySessionTranscriptFromSessionStore(absPath: string): {
242276} {
243277 const sessionsDir = path . dirname ( absPath ) ;
244278 const normalizedAbsPath = normalizeComparablePath ( absPath ) ;
279+ const primarySessionId = parseUsageCountedSessionIdFromFileName ( path . basename ( absPath ) ) ;
280+ const normalizedPrimaryPath =
281+ primarySessionId && isSessionArchiveArtifactName ( path . basename ( absPath ) )
282+ ? normalizeComparablePath ( path . join ( sessionsDir , `${ primarySessionId } .jsonl` ) )
283+ : null ;
245284 const classification = loadSessionTranscriptClassificationForSessionsDir ( sessionsDir ) ;
285+ const hasClassifiedPath = ( paths : ReadonlySet < string > ) =>
286+ paths . has ( normalizedAbsPath ) ||
287+ ( normalizedPrimaryPath !== null && paths . has ( normalizedPrimaryPath ) ) ;
246288 return {
247- generatedByDreamingNarrative :
248- classification . dreamingNarrativeTranscriptPaths . has ( normalizedAbsPath ) ,
249- generatedByCronRun : classification . cronRunTranscriptPaths . has ( normalizedAbsPath ) ,
289+ generatedByDreamingNarrative : hasClassifiedPath (
290+ classification . dreamingNarrativeTranscriptPaths ,
291+ ) ,
292+ generatedByCronRun : hasClassifiedPath ( classification . cronRunTranscriptPaths ) ,
250293 } ;
251294}
252295
@@ -264,8 +307,20 @@ export async function listSessionFilesForAgent(agentId: string): Promise<string[
264307 }
265308}
266309
310+ function extractAgentIdFromSessionPath ( absPath : string ) : string | null {
311+ const parts = path . normalize ( path . resolve ( absPath ) ) . split ( path . sep ) . filter ( Boolean ) ;
312+ const sessionsIndex = parts . lastIndexOf ( "sessions" ) ;
313+ if ( sessionsIndex < 2 || parts [ sessionsIndex - 2 ] !== "agents" ) {
314+ return null ;
315+ }
316+ return parts [ sessionsIndex - 1 ] || null ;
317+ }
318+
267319export function sessionPathForFile ( absPath : string ) : string {
268- return path . join ( "sessions" , path . basename ( absPath ) ) . replace ( / \\ / g, "/" ) ;
320+ const agentId = extractAgentIdFromSessionPath ( absPath ) ;
321+ return path
322+ . join ( "sessions" , ...( agentId ? [ agentId ] : [ ] ) , path . basename ( absPath ) )
323+ . replace ( / \\ / g, "/" ) ;
269324}
270325
271326async function logSessionFileReadFailure ( absPath : string , err : unknown ) : Promise < void > {
@@ -495,8 +550,10 @@ export async function buildSessionEntry(
495550 opts . generatedByDreamingNarrative ??
496551 sessionStoreClassification ?. generatedByDreamingNarrative ??
497552 false ;
498- const generatedByCronRun =
553+ let generatedByCronRun =
499554 opts . generatedByCronRun ?? sessionStoreClassification ?. generatedByCronRun ?? false ;
555+ const allowArchiveContentCronClassification =
556+ isUsageCountedSessionArchiveTranscriptPath ( absPath ) ;
500557 for ( let jsonlIdx = 0 ; jsonlIdx < lines . length ; jsonlIdx ++ ) {
501558 const line = lines [ jsonlIdx ] ;
502559 if ( ! line . trim ( ) ) {
@@ -511,6 +568,16 @@ export async function buildSessionEntry(
511568 if ( ! generatedByDreamingNarrative && isDreamingNarrativeGeneratedRecord ( record ) ) {
512569 generatedByDreamingNarrative = true ;
513570 }
571+ if (
572+ ! generatedByCronRun &&
573+ allowArchiveContentCronClassification &&
574+ isCronRunGeneratedRecord ( record )
575+ ) {
576+ generatedByCronRun = true ;
577+ collected . length = 0 ;
578+ lineMap . length = 0 ;
579+ messageTimestampsMs . length = 0 ;
580+ }
514581 if (
515582 ! record ||
516583 typeof record !== "object" ||
@@ -534,6 +601,16 @@ export async function buildSessionEntry(
534601 if ( rawText === null ) {
535602 continue ;
536603 }
604+ if (
605+ ! generatedByCronRun &&
606+ allowArchiveContentCronClassification &&
607+ isGeneratedCronPromptMessage ( normalizeSessionText ( rawText ) , message . role )
608+ ) {
609+ generatedByCronRun = true ;
610+ collected . length = 0 ;
611+ lineMap . length = 0 ;
612+ messageTimestampsMs . length = 0 ;
613+ }
537614 const text = sanitizeSessionText ( rawText , message . role ) ;
538615 if ( ! text ) {
539616 // Assistant-side machinery (silent replies, system wrappers) is already
0 commit comments