@@ -24,14 +24,84 @@ function isSearchToolName(toolName: string | undefined): boolean {
2424 return SEARCH_TOOL_NAMES . has ( toolName . toLowerCase ( ) ) ;
2525}
2626
27+ function fileNameFromPath ( filePath : string ) : string {
28+ const parts = filePath . split ( "/" ) ;
29+ return parts [ parts . length - 1 ] ?? filePath ;
30+ }
31+
32+ function inputStr ( input : Record < string , unknown > | undefined , key : string ) : string | null {
33+ if ( ! input ) return null ;
34+ const value = input [ key ] ;
35+ return typeof value === "string" && value . trim ( ) . length > 0 ? value . trim ( ) : null ;
36+ }
37+
38+ function inputNum ( input : Record < string , unknown > | undefined , key : string ) : number | null {
39+ if ( ! input ) return null ;
40+ const value = input [ key ] ;
41+ return typeof value === "number" && Number . isFinite ( value ) ? value : null ;
42+ }
43+
44+ function inputFilePath ( input : Record < string , unknown > | undefined ) : string | null {
45+ return inputStr ( input , "file_path" ) ?? inputStr ( input , "filePath" ) ?? inputStr ( input , "path" ) ;
46+ }
47+
48+ function formatLineRange ( input : Record < string , unknown > | undefined ) : string | null {
49+ if ( ! input ) return null ;
50+ const offset = inputNum ( input , "offset" ) ;
51+ const limit = inputNum ( input , "limit" ) ;
52+ if ( offset !== null && limit !== null ) {
53+ return `L${ offset + 1 } –${ offset + limit } ` ;
54+ }
55+ if ( offset !== null ) {
56+ return `from L${ offset + 1 } ` ;
57+ }
58+ if ( limit !== null && limit < 2000 ) {
59+ return `first ${ limit } lines` ;
60+ }
61+ return null ;
62+ }
63+
2764function explorationEntryHeading ( entry : WorkLogEntry ) : string {
28- if ( entry . toolName ) {
29- const lower = entry . toolName . toLowerCase ( ) ;
30- if ( lower === "read" ) return `Read ${ extractFileName ( entry . detail ) } ` ;
31- if ( lower === "grep" ) return `Searched for ${ extractSearchSummary ( entry . detail ) } ` ;
32- if ( lower === "glob" ) return `Glob ${ extractSearchSummary ( entry . detail ) } ` ;
33- if ( lower === "list" || lower === "ls" ) return `Listed ${ extractPathSummary ( entry . detail ) } ` ;
34- if ( lower === "find" ) return `Found ${ extractPathSummary ( entry . detail ) } ` ;
65+ const input = entry . toolInput ;
66+ const lower = entry . toolName ?. toLowerCase ( ) ;
67+
68+ if ( lower === "read" ) {
69+ const filePath = inputFilePath ( input ) ;
70+ const fileName = filePath
71+ ? fileNameFromPath ( filePath )
72+ : extractFileNameFromDetail ( entry . detail ) ;
73+ const lineRange = formatLineRange ( input ) ;
74+ if ( fileName && lineRange ) return `Read ${ fileName } (${ lineRange } )` ;
75+ if ( fileName ) return `Read ${ fileName } ` ;
76+ return "Read file" ;
77+ }
78+
79+ if ( lower === "grep" ) {
80+ const pattern = inputStr ( input , "pattern" ) ;
81+ const path = inputFilePath ( input ) ;
82+ if ( pattern && path ) return `Searched for ${ pattern } in ${ fileNameFromPath ( path ) } ` ;
83+ if ( pattern ) return `Searched for ${ pattern } ` ;
84+ return `Searched ${ extractSearchSummaryFromDetail ( entry . detail ) } ` ;
85+ }
86+
87+ if ( lower === "glob" ) {
88+ const pattern = inputStr ( input , "pattern" ) ;
89+ const path = inputFilePath ( input ) ;
90+ if ( pattern && path ) return `Glob ${ pattern } in ${ fileNameFromPath ( path ) } ` ;
91+ if ( pattern ) return `Glob ${ pattern } ` ;
92+ return `Glob ${ extractSearchSummaryFromDetail ( entry . detail ) } ` ;
93+ }
94+
95+ if ( lower === "list" || lower === "ls" ) {
96+ const path = inputFilePath ( input ) ;
97+ if ( path ) return `Listed ${ fileNameFromPath ( path ) } ` ;
98+ return `Listed ${ extractPathSummaryFromDetail ( entry . detail ) } ` ;
99+ }
100+
101+ if ( lower === "find" ) {
102+ const path = inputFilePath ( input ) ;
103+ if ( path ) return `Found ${ fileNameFromPath ( path ) } ` ;
104+ return `Found ${ extractPathSummaryFromDetail ( entry . detail ) } ` ;
35105 }
36106
37107 const raw = ( entry . toolTitle ?? entry . label ) . trim ( ) ;
@@ -54,34 +124,59 @@ function isGenericLabel(label: string): boolean {
54124 ) ;
55125}
56126
57- function extractFileName ( detail : string | undefined ) : string {
127+ function stripToolPrefix ( value : string ) : string {
128+ return value . replace ( / ^ [ A - Z a - z _ ] + : \s * / , "" ) . trim ( ) ;
129+ }
130+
131+ function tryParseJson ( value : string ) : Record < string , unknown > | null {
132+ if ( ! value . startsWith ( "{" ) ) return null ;
133+ try {
134+ const parsed = JSON . parse ( value ) ;
135+ return parsed && typeof parsed === "object" ? ( parsed as Record < string , unknown > ) : null ;
136+ } catch {
137+ return null ;
138+ }
139+ }
140+
141+ function extractFilePathFromValue ( value : string ) : string | null {
142+ const parsed = tryParseJson ( value ) ;
143+ if ( parsed ) {
144+ const path =
145+ typeof parsed . file_path === "string"
146+ ? parsed . file_path
147+ : typeof parsed . filePath === "string"
148+ ? parsed . filePath
149+ : typeof parsed . path === "string"
150+ ? parsed . path
151+ : null ;
152+ return path ;
153+ }
154+ if ( value . includes ( "/" ) ) return value . trim ( ) ;
155+ return null ;
156+ }
157+
158+ function extractFileNameFromDetail ( detail : string | undefined ) : string {
58159 if ( ! detail ) return "" ;
59160 const cleaned = stripToolPrefix ( detail ) ;
60161 const filePath = extractFilePathFromValue ( cleaned ) ;
61- if ( filePath ) {
62- const parts = filePath . split ( "/" ) ;
63- return parts [ parts . length - 1 ] ?? filePath ;
64- }
162+ if ( filePath ) return fileNameFromPath ( filePath ) ;
65163 return "" ;
66164}
67165
68- function extractSearchSummary ( detail : string | undefined ) : string {
166+ function extractSearchSummaryFromDetail ( detail : string | undefined ) : string {
69167 if ( ! detail ) return "" ;
70168 const cleaned = stripToolPrefix ( detail ) ;
71169 const parsed = tryParseJson ( cleaned ) ;
72170 if ( parsed ) {
73171 const pattern = typeof parsed . pattern === "string" ? parsed . pattern : null ;
74172 const path = typeof parsed . path === "string" ? parsed . path : null ;
75- if ( pattern && path ) {
76- const shortPath = path . split ( "/" ) . pop ( ) ?? path ;
77- return `${ pattern } in ${ shortPath } ` ;
78- }
173+ if ( pattern && path ) return `${ pattern } in ${ fileNameFromPath ( path ) } ` ;
79174 if ( pattern ) return pattern ;
80175 }
81176 return cleaned . slice ( 0 , 120 ) ;
82177}
83178
84- function extractPathSummary ( detail : string | undefined ) : string {
179+ function extractPathSummaryFromDetail ( detail : string | undefined ) : string {
85180 if ( ! detail ) return "" ;
86181 const cleaned = stripToolPrefix ( detail ) ;
87182 const filePath = extractFilePathFromValue ( cleaned ) ;
@@ -92,44 +187,10 @@ function extractPathSummary(detail: string | undefined): string {
92187 return cleaned . slice ( 0 , 120 ) ;
93188}
94189
95- function stripToolPrefix ( value : string ) : string {
96- return value . replace ( / ^ [ A - Z a - z _ ] + : \s * / , "" ) . trim ( ) ;
97- }
98-
99- function extractFilePathFromValue ( value : string ) : string | null {
100- const parsed = tryParseJson ( value ) ;
101- if ( parsed ) {
102- const path =
103- typeof parsed . file_path === "string"
104- ? parsed . file_path
105- : typeof parsed . filePath === "string"
106- ? parsed . filePath
107- : typeof parsed . path === "string"
108- ? parsed . path
109- : null ;
110- return path ;
111- }
112- if ( value . includes ( "/" ) ) return value . trim ( ) ;
113- return null ;
114- }
115-
116- function tryParseJson ( value : string ) : Record < string , unknown > | null {
117- if ( ! value . startsWith ( "{" ) ) return null ;
118- try {
119- const parsed = JSON . parse ( value ) ;
120- return parsed && typeof parsed === "object" ? ( parsed as Record < string , unknown > ) : null ;
121- } catch {
122- return null ;
123- }
124- }
125-
126190function cleanDetailAsHeading ( detail : string ) : string {
127191 const cleaned = stripToolPrefix ( detail ) ;
128192 const filePath = extractFilePathFromValue ( cleaned ) ;
129- if ( filePath ) {
130- const fileName = filePath . split ( "/" ) . pop ( ) ?? filePath ;
131- return `Read ${ fileName } ` ;
132- }
193+ if ( filePath ) return `Read ${ fileNameFromPath ( filePath ) } ` ;
133194 return cleaned . slice ( 0 , 80 ) ;
134195}
135196
0 commit comments