11import { z } from "zod"
22import type { Logger } from "./logger"
3- import type { StateManager } from "./state"
3+ import type { StateManager , SessionStats } from "./state"
44import { buildAnalysisPrompt } from "./prompt"
55import { selectModel , extractModelFromSession } from "./model-selector"
66import { estimateTokensBatch , formatTokenCount } from "./tokenizer"
@@ -268,12 +268,16 @@ export class Janitor {
268268 // Calculate token savings once (used by both notification and log)
269269 const tokensSaved = await this . calculateTokensSaved ( finalNewlyPrunedIds , toolOutputs )
270270
271+ // Accumulate session stats (for showing cumulative totals in UI)
272+ const sessionStats = await this . stateManager . addStats ( sessionID , finalNewlyPrunedIds . length , tokensSaved )
273+
271274 if ( this . pruningMode === "auto" ) {
272275 await this . sendAutoModeNotification (
273276 sessionID ,
274277 deduplicatedIds ,
275278 deduplicationDetails ,
276- tokensSaved
279+ tokensSaved ,
280+ sessionStats
277281 )
278282 } else {
279283 await this . sendSmartModeNotification (
@@ -282,7 +286,8 @@ export class Janitor {
282286 deduplicationDetails ,
283287 llmPrunedIds ,
284288 toolMetadata ,
285- tokensSaved
289+ tokensSaved ,
290+ sessionStats
286291 )
287292 }
288293
@@ -451,14 +456,20 @@ export class Janitor {
451456 private async sendMinimalNotification (
452457 sessionID : string ,
453458 totalPruned : number ,
454- tokensSaved : number
459+ tokensSaved : number ,
460+ sessionStats : SessionStats
455461 ) {
456462 if ( totalPruned === 0 ) return
457463
458464 const tokensFormatted = formatTokenCount ( tokensSaved )
459465 const toolText = totalPruned === 1 ? 'tool' : 'tools'
460466
461- const message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ totalPruned } ${ toolText } pruned)`
467+ let message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ totalPruned } ${ toolText } pruned)`
468+
469+ // Add session totals if there's been more than one pruning run
470+ if ( sessionStats . totalToolsPruned > totalPruned ) {
471+ message += ` │ Session: ${ sessionStats . totalToolsPruned } tools, ~${ formatTokenCount ( sessionStats . totalTokensSaved ) } tokens`
472+ }
462473
463474 await this . sendIgnoredMessage ( sessionID , message )
464475 }
@@ -470,7 +481,8 @@ export class Janitor {
470481 sessionID : string ,
471482 deduplicatedIds : string [ ] ,
472483 deduplicationDetails : Map < string , any > ,
473- tokensSaved : number
484+ tokensSaved : number ,
485+ sessionStats : SessionStats
474486 ) {
475487 if ( deduplicatedIds . length === 0 ) return
476488
@@ -479,15 +491,21 @@ export class Janitor {
479491
480492 // Send minimal notification if configured
481493 if ( this . pruningSummary === 'minimal' ) {
482- await this . sendMinimalNotification ( sessionID , deduplicatedIds . length , tokensSaved )
494+ await this . sendMinimalNotification ( sessionID , deduplicatedIds . length , tokensSaved , sessionStats )
483495 return
484496 }
485497
486498 // Otherwise send detailed notification
487499 const tokensFormatted = formatTokenCount ( tokensSaved )
488500
489501 const toolText = deduplicatedIds . length === 1 ? 'tool' : 'tools'
490- let message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ deduplicatedIds . length } duplicate ${ toolText } removed)\n`
502+ let message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ deduplicatedIds . length } duplicate ${ toolText } removed)`
503+
504+ // Add session totals if there's been more than one pruning run
505+ if ( sessionStats . totalToolsPruned > deduplicatedIds . length ) {
506+ message += ` │ Session: ${ sessionStats . totalToolsPruned } tools, ~${ formatTokenCount ( sessionStats . totalTokensSaved ) } tokens`
507+ }
508+ message += '\n'
491509
492510 // Group by tool type
493511 const grouped = new Map < string , Array < { count : number , key : string } > > ( )
@@ -530,7 +548,8 @@ export class Janitor {
530548 deduplicationDetails : Map < string , any > ,
531549 llmPrunedIds : string [ ] ,
532550 toolMetadata : Map < string , any > ,
533- tokensSaved : number
551+ tokensSaved : number ,
552+ sessionStats : SessionStats
534553 ) {
535554 const totalPruned = deduplicatedIds . length + llmPrunedIds . length
536555 if ( totalPruned === 0 ) return
@@ -540,14 +559,20 @@ export class Janitor {
540559
541560 // Send minimal notification if configured
542561 if ( this . pruningSummary === 'minimal' ) {
543- await this . sendMinimalNotification ( sessionID , totalPruned , tokensSaved )
562+ await this . sendMinimalNotification ( sessionID , totalPruned , tokensSaved , sessionStats )
544563 return
545564 }
546565
547566 // Otherwise send detailed notification
548567 const tokensFormatted = formatTokenCount ( tokensSaved )
549568
550- let message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ totalPruned } tool${ totalPruned > 1 ? 's' : '' } pruned)\n`
569+ let message = `🧹 DCP: Saved ~${ tokensFormatted } tokens (${ totalPruned } tool${ totalPruned > 1 ? 's' : '' } pruned)`
570+
571+ // Add session totals if there's been more than one pruning run
572+ if ( sessionStats . totalToolsPruned > totalPruned ) {
573+ message += ` │ Session: ${ sessionStats . totalToolsPruned } tools, ~${ formatTokenCount ( sessionStats . totalTokensSaved ) } tokens`
574+ }
575+ message += '\n'
551576
552577 // Section 1: Deduplicated tools
553578 if ( deduplicatedIds . length > 0 && deduplicationDetails ) {
0 commit comments