@@ -8,7 +8,8 @@ import type { SessionState, WithParts } from "../state"
88import { sendIgnoredMessage } from "../ui/notification"
99import { formatTokenCount } from "../ui/utils"
1010import { loadAllSessionStats , type AggregatedStats } from "../state/persistence"
11- import { getCurrentParams } from "../strategies/utils"
11+ import { getCurrentParams } from "../token-utils"
12+ import { getActiveCompressionTargets } from "./compression-targets"
1213
1314export interface StatsCommandContext {
1415 client : any
@@ -20,8 +21,10 @@ export interface StatsCommandContext {
2021
2122function formatStatsMessage (
2223 sessionTokens : number ,
24+ sessionSummaryTokens : number ,
2325 sessionTools : number ,
2426 sessionMessages : number ,
27+ sessionDurationMs : number ,
2528 allTime : AggregatedStats ,
2629) : string {
2730 const lines : string [ ] = [ ]
@@ -30,11 +33,15 @@ function formatStatsMessage(
3033 lines . push ( "│ DCP Statistics │" )
3134 lines . push ( "╰───────────────────────────────────────────────────────────╯" )
3235 lines . push ( "" )
33- lines . push ( "Session :" )
36+ lines . push ( "Compression :" )
3437 lines . push ( "─" . repeat ( 60 ) )
35- lines . push ( ` Tokens pruned: ~${ formatTokenCount ( sessionTokens ) } ` )
36- lines . push ( ` Tools pruned: ${ sessionTools } ` )
37- lines . push ( ` Messages pruned: ${ sessionMessages } ` )
38+ lines . push (
39+ ` Tokens in|out: ~${ formatTokenCount ( sessionTokens ) } | ~${ formatTokenCount ( sessionSummaryTokens ) } ` ,
40+ )
41+ lines . push ( ` Ratio: ${ formatCompressionRatio ( sessionTokens , sessionSummaryTokens ) } ` )
42+ lines . push ( ` Time: ${ formatCompressionTime ( sessionDurationMs ) } ` )
43+ lines . push ( ` Messages: ${ sessionMessages } ` )
44+ lines . push ( ` Tools: ${ sessionTools } ` )
3845 lines . push ( "" )
3946 lines . push ( "All-time:" )
4047 lines . push ( "─" . repeat ( 60 ) )
@@ -46,11 +53,55 @@ function formatStatsMessage(
4653 return lines . join ( "\n" )
4754}
4855
56+ function formatCompressionRatio ( inputTokens : number , outputTokens : number ) : string {
57+ if ( inputTokens <= 0 ) {
58+ return "0:1"
59+ }
60+
61+ if ( outputTokens <= 0 ) {
62+ return "∞:1"
63+ }
64+
65+ const ratio = Math . max ( 1 , Math . round ( inputTokens / outputTokens ) )
66+ return `${ ratio } :1`
67+ }
68+
69+ function formatCompressionTime ( ms : number ) : string {
70+ const safeMs = Math . max ( 0 , Math . round ( ms ) )
71+ if ( safeMs < 1000 ) {
72+ return `${ safeMs } ms`
73+ }
74+
75+ const totalSeconds = safeMs / 1000
76+ if ( totalSeconds < 60 ) {
77+ return `${ totalSeconds . toFixed ( 1 ) } s`
78+ }
79+
80+ const wholeSeconds = Math . floor ( totalSeconds )
81+ const hours = Math . floor ( wholeSeconds / 3600 )
82+ const minutes = Math . floor ( ( wholeSeconds % 3600 ) / 60 )
83+ const seconds = wholeSeconds % 60
84+
85+ if ( hours > 0 ) {
86+ return `${ hours } h ${ minutes } m ${ seconds } s`
87+ }
88+
89+ return `${ minutes } m ${ seconds } s`
90+ }
91+
4992export async function handleStatsCommand ( ctx : StatsCommandContext ) : Promise < void > {
5093 const { client, state, logger, sessionId, messages } = ctx
5194
5295 // Session stats from in-memory state
5396 const sessionTokens = state . stats . totalPruneTokens
97+ const sessionSummaryTokens = Array . from ( state . prune . messages . blocksById . values ( ) ) . reduce (
98+ ( total , block ) => ( block . active ? total + block . summaryTokens : total ) ,
99+ 0 ,
100+ )
101+ const sessionDurationMs = getActiveCompressionTargets ( state . prune . messages ) . reduce (
102+ ( total , target ) => total + target . durationMs ,
103+ 0 ,
104+ )
54105
55106 const prunedToolIds = new Set < string > ( state . prune . tools . keys ( ) )
56107 for ( const block of state . prune . messages . blocksById . values ( ) ) {
@@ -72,15 +123,24 @@ export async function handleStatsCommand(ctx: StatsCommandContext): Promise<void
72123 // All-time stats from storage files
73124 const allTime = await loadAllSessionStats ( logger )
74125
75- const message = formatStatsMessage ( sessionTokens , sessionTools , sessionMessages , allTime )
126+ const message = formatStatsMessage (
127+ sessionTokens ,
128+ sessionSummaryTokens ,
129+ sessionTools ,
130+ sessionMessages ,
131+ sessionDurationMs ,
132+ allTime ,
133+ )
76134
77135 const params = getCurrentParams ( state , messages , logger )
78136 await sendIgnoredMessage ( client , sessionId , message , params , logger )
79137
80138 logger . info ( "Stats command executed" , {
81139 sessionTokens,
140+ sessionSummaryTokens,
82141 sessionTools,
83142 sessionMessages,
143+ sessionDurationMs,
84144 allTimeTokens : allTime . totalTokens ,
85145 allTimeTools : allTime . totalTools ,
86146 allTimeMessages : allTime . totalMessages ,
0 commit comments