@@ -6,6 +6,11 @@ import { getCurrentParams } from "../strategies/utils"
66import { saveSessionState } from "../state/persistence"
77import { sendIgnoredMessage } from "../ui/notification"
88import { formatTokenCount } from "../ui/utils"
9+ import {
10+ getActiveCompressionTargets ,
11+ resolveCompressionTarget ,
12+ type CompressionTarget ,
13+ } from "./compression-targets"
914
1015export interface DecompressCommandContext {
1116 client : any
@@ -31,13 +36,6 @@ function parseBlockIdArg(arg: string): number | null {
3136 return Number . isInteger ( parsed ) && parsed > 0 ? parsed : null
3237}
3338
34- function getAvailableBlocks ( messagesState : PruneMessagesState ) : CompressionBlock [ ] {
35- return Array . from ( messagesState . activeBlockIds )
36- . map ( ( blockId ) => messagesState . blocksById . get ( blockId ) )
37- . filter ( ( block ) : block is CompressionBlock => ! ! block && block . active )
38- . sort ( ( a , b ) => a . blockId - b . blockId )
39- }
40-
4139function findActiveParentBlockId (
4240 messagesState : PruneMessagesState ,
4341 block : CompressionBlock ,
@@ -71,6 +69,20 @@ function findActiveParentBlockId(
7169 return null
7270}
7371
72+ function findActiveAncestorBlockId (
73+ messagesState : PruneMessagesState ,
74+ target : CompressionTarget ,
75+ ) : number | null {
76+ for ( const block of target . blocks ) {
77+ const activeAncestorBlockId = findActiveParentBlockId ( messagesState , block )
78+ if ( activeAncestorBlockId !== null ) {
79+ return activeAncestorBlockId
80+ }
81+ }
82+
83+ return null
84+ }
85+
7486function snapshotActiveMessages ( messagesState : PruneMessagesState ) : Map < string , number > {
7587 const activeMessages = new Map < string , number > ( )
7688 for ( const [ messageId , entry ] of messagesState . byMessageId ) {
@@ -82,14 +94,17 @@ function snapshotActiveMessages(messagesState: PruneMessagesState): Map<string,
8294}
8395
8496function formatDecompressMessage (
85- targetBlockId : number ,
97+ target : CompressionTarget ,
8698 restoredMessageCount : number ,
8799 restoredTokens : number ,
88100 reactivatedBlockIds : number [ ] ,
89101) : string {
90102 const lines : string [ ] = [ ]
91103
92- lines . push ( `Restored compression ${ targetBlockId } .` )
104+ lines . push ( `Restored compression ${ target . displayId } .` )
105+ if ( target . runId !== target . displayId || target . grouped ) {
106+ lines . push ( `Tool call label: Compression #${ target . runId } .` )
107+ }
93108 if ( reactivatedBlockIds . length > 0 ) {
94109 const refs = reactivatedBlockIds . map ( ( id ) => String ( id ) ) . join ( ", " )
95110 lines . push ( `Also restored nested compression(s): ${ refs } .` )
@@ -106,22 +121,25 @@ function formatDecompressMessage(
106121 return lines . join ( "\n" )
107122}
108123
109- function formatAvailableBlocksMessage ( availableBlocks : CompressionBlock [ ] ) : string {
124+ function formatAvailableBlocksMessage ( availableTargets : CompressionTarget [ ] ) : string {
110125 const lines : string [ ] = [ ]
111126
112127 lines . push ( "Usage: /dcp decompress <n>" )
113128 lines . push ( "" )
114129
115- if ( availableBlocks . length === 0 ) {
130+ if ( availableTargets . length === 0 ) {
116131 lines . push ( "No compressions are available to restore." )
117132 return lines . join ( "\n" )
118133 }
119134
120135 lines . push ( "Available compressions:" )
121- const entries = availableBlocks . map ( ( block ) => {
122- const topic = block . topic . replace ( / \s + / g, " " ) . trim ( ) || "(no topic)"
123- const label = `${ block . blockId } (${ formatTokenCount ( block . compressedTokens ) } )`
124- return { label, topic }
136+ const entries = availableTargets . map ( ( target ) => {
137+ const topic = target . topic . replace ( / \s + / g, " " ) . trim ( ) || "(no topic)"
138+ const label = `${ target . displayId } (${ formatTokenCount ( target . compressedTokens ) } )`
139+ const details = target . grouped
140+ ? `Compression #${ target . runId } - ${ target . blocks . length } messages`
141+ : `Compression #${ target . runId } `
142+ return { label, topic : `${ details } - ${ topic } ` }
125143 } )
126144
127145 const labelWidth = Math . max ( ...entries . map ( ( entry ) => entry . label . length ) ) + 4
@@ -153,8 +171,8 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
153171 const messagesState = state . prune . messages
154172
155173 if ( ! targetArg ) {
156- const availableBlocks = getAvailableBlocks ( messagesState )
157- const message = formatAvailableBlocksMessage ( availableBlocks )
174+ const availableTargets = getActiveCompressionTargets ( messagesState )
175+ const message = formatAvailableBlocksMessage ( availableTargets )
158176 await sendIgnoredMessage ( client , sessionId , message , params , logger )
159177 return
160178 }
@@ -171,8 +189,8 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
171189 return
172190 }
173191
174- const targetBlock = messagesState . blocksById . get ( targetBlockId )
175- if ( ! targetBlock ) {
192+ const target = resolveCompressionTarget ( messagesState , targetBlockId )
193+ if ( ! target ) {
176194 await sendIgnoredMessage (
177195 client ,
178196 sessionId ,
@@ -183,13 +201,14 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
183201 return
184202 }
185203
186- if ( ! targetBlock . active ) {
187- const activeAncestorBlockId = findActiveParentBlockId ( messagesState , targetBlock )
204+ const activeBlocks = target . blocks . filter ( ( block ) => block . active )
205+ if ( activeBlocks . length === 0 ) {
206+ const activeAncestorBlockId = findActiveAncestorBlockId ( messagesState , target )
188207 if ( activeAncestorBlockId !== null ) {
189208 await sendIgnoredMessage (
190209 client ,
191210 sessionId ,
192- `Compression ${ targetBlockId } is inside compression ${ activeAncestorBlockId } . Restore compression ${ activeAncestorBlockId } first.` ,
211+ `Compression ${ target . displayId } is inside compression ${ activeAncestorBlockId } . Restore compression ${ activeAncestorBlockId } first.` ,
193212 params ,
194213 logger ,
195214 )
@@ -199,7 +218,7 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
199218 await sendIgnoredMessage (
200219 client ,
201220 sessionId ,
202- `Compression ${ targetBlockId } is not active.` ,
221+ `Compression ${ target . displayId } is not active.` ,
203222 params ,
204223 logger ,
205224 )
@@ -208,11 +227,14 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
208227
209228 const activeMessagesBefore = snapshotActiveMessages ( messagesState )
210229 const activeBlockIdsBefore = new Set ( messagesState . activeBlockIds )
230+ const deactivatedAt = Date . now ( )
211231
212- targetBlock . active = false
213- targetBlock . deactivatedByUser = true
214- targetBlock . deactivatedAt = Date . now ( )
215- targetBlock . deactivatedByBlockId = undefined
232+ for ( const block of target . blocks ) {
233+ block . active = false
234+ block . deactivatedByUser = true
235+ block . deactivatedAt = deactivatedAt
236+ block . deactivatedByBlockId = undefined
237+ }
216238
217239 syncCompressionBlocks ( state , logger , messages )
218240
@@ -236,15 +258,16 @@ export async function handleDecompressCommand(ctx: DecompressCommandContext): Pr
236258 await saveSessionState ( state , logger )
237259
238260 const message = formatDecompressMessage (
239- targetBlockId ,
261+ target ,
240262 restoredMessageCount ,
241263 restoredTokens ,
242264 reactivatedBlockIds ,
243265 )
244266 await sendIgnoredMessage ( client , sessionId , message , params , logger )
245267
246268 logger . info ( "Decompress command completed" , {
247- targetBlockId,
269+ targetBlockId : target . displayId ,
270+ targetRunId : target . runId ,
248271 restoredMessageCount,
249272 restoredTokens,
250273 reactivatedBlockIds,
0 commit comments