@@ -15,7 +15,6 @@ const TURN_NEEDLE = Buffer.from('turn_context');
1515const MODEL_RE = / " m o d e l " \s * : \s * " ( [ ^ " \\ ] * (?: \\ .[ ^ " \\ ] * ) * ) " / ;
1616const FIND_FIELD_SEPARATOR = '\x1f' ;
1717const FIND_RECORD_SEPARATOR = '\x1e' ;
18- const PRUNE_SAFETY_MS = 48 * 60 * 60 * 1000 ;
1918const DEFAULT_MAX_CACHE_BYTES = 64 * 1024 * 1024 ;
2019
2120export function defaultCacheFile ( ) {
@@ -30,7 +29,8 @@ export async function collectUsage(options = {}) {
3029 const timezone = safeTimeZone ( options . timezone ) ;
3130 const since = normalizeDate ( options . since ) ;
3231 const until = normalizeDate ( options . until ) ;
33- const pruneBeforeMs = since ? Date . parse ( `${ since } T00:00:00.000Z` ) - PRUNE_SAFETY_MS : undefined ;
32+ const pruneBeforeDate = since ? addDaysToDateKey ( since , - 2 ) : undefined ;
33+ const pruneAfterDate = until ? addDaysToDateKey ( until , 2 ) : undefined ;
3434 const cacheFile = options . cacheFile ?? defaultCacheFile ( ) ;
3535 const useCache = options . useCache !== false ;
3636 const saveCache = useCache && options . saveCache !== false ;
@@ -69,17 +69,17 @@ export async function collectUsage(options = {}) {
6969 stats . filesSeen += 1 ;
7070 stats . bytesSeen += st . size ;
7171
72- if ( pruneBeforeMs !== undefined && st . mtimeMs < pruneBeforeMs ) {
73- stats . filesSkippedByMtime += 1 ;
74- stats . bytesSkippedByMtime += st . size ;
72+ const sessionInfo = makeSessionInfo ( file , sessionsDir ) ;
73+ if ( shouldSkipBySessionPathDate ( sessionInfo . directory , pruneBeforeDate , pruneAfterDate ) ) {
74+ stats . filesSkippedByPathDate += 1 ;
75+ stats . bytesSkippedByPathDate += st . size ;
7576 const oldEntry = useCache ? cache . files [ file ] : undefined ;
7677 if ( oldEntry && sameFile ( st , oldEntry ) ) {
7778 nextFiles [ file ] = oldEntry ;
7879 }
7980 continue ;
8081 }
8182
82- const sessionInfo = makeSessionInfo ( file , sessionsDir ) ;
8383 const oldEntry = useCache ? cache . files [ file ] : undefined ;
8484 let entry ;
8585
@@ -604,7 +604,7 @@ function buildReport(aggregate, stats, nextFiles) {
604604 addUsage ( totals , day ) ;
605605 }
606606
607- const filesEligibleForCache = stats . filesSeen - stats . filesSkippedByMtime ;
607+ const filesEligibleForCache = stats . filesSeen - stats . filesSkippedByMtime - stats . filesSkippedByPathDate ;
608608 return {
609609 daily,
610610 monthly,
@@ -776,6 +776,7 @@ function createStats(cache, timezone, billingThresholds = DEFAULT_BILLING_THRESH
776776 billingThresholds,
777777 filesSeen : 0 ,
778778 filesSkippedByMtime : 0 ,
779+ filesSkippedByPathDate : 0 ,
779780 filesFromCache : 0 ,
780781 filesScannedFull : 0 ,
781782 filesScannedTail : 0 ,
@@ -787,6 +788,7 @@ function createStats(cache, timezone, billingThresholds = DEFAULT_BILLING_THRESH
787788 bytesSeen : 0 ,
788789 bytesRead : 0 ,
789790 bytesSkippedByMtime : 0 ,
791+ bytesSkippedByPathDate : 0 ,
790792 bytesSkippedByCache : 0 ,
791793 bytesSkippedByTailCache : 0 ,
792794 cacheEntriesLoaded : Object . keys ( cache . files ) . length ,
@@ -867,9 +869,45 @@ export function isWithinRange(dateKey, since, until) {
867869 return true ;
868870}
869871
872+ function shouldSkipBySessionPathDate ( directory , pruneBeforeDate , pruneAfterDate ) {
873+ if ( ! pruneBeforeDate && ! pruneAfterDate ) {
874+ return false ;
875+ }
876+ const dateKey = sessionPathDateKey ( directory ) ;
877+ if ( ! dateKey ) {
878+ return false ;
879+ }
880+ if ( pruneBeforeDate && dateKey < pruneBeforeDate ) {
881+ return true ;
882+ }
883+ if ( pruneAfterDate && dateKey > pruneAfterDate ) {
884+ return true ;
885+ }
886+ return false ;
887+ }
888+
889+ function sessionPathDateKey ( directory ) {
890+ const match = String ( directory ) . match ( / (?: ^ | \/ ) ( \d { 4 } ) \/ ( \d { 2 } ) \/ ( \d { 2 } ) (?: \/ | $ ) / ) ;
891+ if ( ! match ) {
892+ return null ;
893+ }
894+ const dateKey = `${ match [ 1 ] } -${ match [ 2 ] } -${ match [ 3 ] } ` ;
895+ try {
896+ return normalizeDate ( dateKey ) ;
897+ } catch {
898+ return null ;
899+ }
900+ }
901+
902+ function addDaysToDateKey ( dateKey , days ) {
903+ const [ year , month , day ] = dateKey . split ( '-' ) . map ( Number ) ;
904+ const date = new Date ( Date . UTC ( year , month - 1 , day + days ) ) ;
905+ return `${ date . getUTCFullYear ( ) } -${ String ( date . getUTCMonth ( ) + 1 ) . padStart ( 2 , '0' ) } -${ String ( date . getUTCDate ( ) ) . padStart ( 2 , '0' ) } ` ;
906+ }
907+
870908export function safeTimeZone ( timezone ) {
871909 if ( timezone == null || String ( timezone ) . trim ( ) === '' ) {
872- return Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ?? 'UTC' ;
910+ return 'UTC' ;
873911 }
874912 try {
875913 Intl . DateTimeFormat ( 'en-US' , { timeZone : timezone } ) ;
0 commit comments