@@ -7,71 +7,26 @@ import { useTheme } from '../../hooks/use-theme'
77import type { ToolRenderConfig } from './types'
88
99type PatchOperation =
10- | { type : 'add' ; path : string }
11- | { type : 'delete' ; path : string }
12- | { type : 'update' ; path : string ; moveTo ?: string ; hunks : string }
13-
14- function parsePatchOperations ( rawPatch : string ) : PatchOperation [ ] {
15- const normalized = rawPatch . replace ( / \r \n / g, '\n' )
16- const lines = normalized . split ( '\n' )
17- if ( lines . length < 2 ) return [ ]
18- if ( lines [ 0 ] !== '*** Begin Patch' ) return [ ]
19-
20- const ops : PatchOperation [ ] = [ ]
21- let i = 1
22- const endIndex = lines . length - 1
23-
24- while ( i < endIndex ) {
25- const line = lines [ i ]
26- if ( ! line ) {
27- i ++
28- continue
29- }
30-
31- if ( line . startsWith ( '*** Add File: ' ) ) {
32- const filePath = line . slice ( '*** Add File: ' . length )
33- i ++
34- while ( i < endIndex && ! lines [ i ] . startsWith ( '*** ' ) ) {
35- i ++
36- }
37- ops . push ( { type : 'add' , path : filePath } )
38- continue
39- }
40-
41- if ( line . startsWith ( '*** Delete File: ' ) ) {
42- const filePath = line . slice ( '*** Delete File: ' . length )
43- ops . push ( { type : 'delete' , path : filePath } )
44- i ++
45- continue
46- }
47-
48- if ( line . startsWith ( '*** Update File: ' ) ) {
49- const filePath = line . slice ( '*** Update File: ' . length )
50- i ++
51-
52- let moveTo : string | undefined
53- if ( i < endIndex && lines [ i ] . startsWith ( '*** Move to: ' ) ) {
54- moveTo = lines [ i ] . slice ( '*** Move to: ' . length )
55- i ++
56- }
57-
58- const hunkLines : string [ ] = [ ]
59- while ( i < endIndex && ! lines [ i ] . startsWith ( '*** ' ) ) {
60- if ( lines [ i ] !== '*** End of File' ) {
61- hunkLines . push ( lines [ i ] )
62- }
63- i ++
64- }
65-
66- const hunks = hunkLines . join ( '\n' ) . trim ( )
67- ops . push ( { type : 'update' , path : filePath , moveTo, hunks } )
68- continue
69- }
70-
71- i ++
10+ | { type : 'create_file' ; path : string ; diff : string }
11+ | { type : 'update_file' ; path : string ; diff : string }
12+ | { type : 'delete_file' ; path : string }
13+
14+ function parseOperation ( input : unknown ) : PatchOperation | null {
15+ if ( ! input || typeof input !== 'object' ) return null
16+ const op = ( input as { operation ?: unknown } ) . operation
17+ if ( ! op || typeof op !== 'object' ) return null
18+ const { type, path, diff } = op as Record < string , unknown >
19+ if ( typeof type !== 'string' || typeof path !== 'string' ) return null
20+ if ( type === 'create_file' && typeof diff === 'string' ) {
21+ return { type : 'create_file' , path, diff }
7222 }
73-
74- return ops
23+ if ( type === 'update_file' && typeof diff === 'string' ) {
24+ return { type : 'update_file' , path, diff }
25+ }
26+ if ( type === 'delete_file' ) {
27+ return { type : 'delete_file' , path }
28+ }
29+ return null
7530}
7631
7732interface EditHeaderProps {
@@ -101,24 +56,19 @@ interface PatchOperationItemProps {
10156}
10257
10358const PatchOperationItem = ( { operation } : PatchOperationItemProps ) => {
104- if ( operation . type === 'add ' ) {
59+ if ( operation . type === 'create_file ' ) {
10560 return < EditHeader name = "Create" filePath = { operation . path } />
10661 }
10762
108- if ( operation . type === 'delete ' ) {
63+ if ( operation . type === 'delete_file ' ) {
10964 return < EditHeader name = "Delete" filePath = { operation . path } />
11065 }
11166
112- const destination =
113- operation . moveTo && operation . moveTo !== operation . path
114- ? `${ operation . path } → ${ operation . moveTo } `
115- : operation . path
116-
11767 return (
11868 < box style = { { flexDirection : 'column' , width : '100%' } } >
119- < EditHeader name = "Edit" filePath = { destination } />
69+ < EditHeader name = "Edit" filePath = { operation . path } />
12070 < box style = { { paddingLeft : 2 , width : '100%' } } >
121- < DiffViewer diffText = { operation . hunks } />
71+ < DiffViewer diffText = { operation . diff } />
12272 </ box >
12373 </ box >
12474 )
@@ -128,31 +78,18 @@ export const ApplyPatchComponent = defineToolComponent({
12878 toolName : 'apply_patch' ,
12979
13080 render ( toolBlock ) : ToolRenderConfig {
131- const patch =
132- toolBlock . input &&
133- typeof toolBlock . input === 'object' &&
134- 'patch' in toolBlock . input &&
135- typeof ( toolBlock . input as { patch ?: unknown } ) . patch === 'string'
136- ? ( toolBlock . input as { patch : string } ) . patch
137- : ''
138-
139- const operations = patch ? parsePatchOperations ( patch ) : [ ]
81+ const operation = parseOperation ( toolBlock . input )
14082
141- if ( operations . length === 0 ) {
83+ if ( ! operation ) {
14284 return { content : null }
14385 }
14486
14587 return {
14688 content : (
14789 < box style = { { flexDirection : 'column' , gap : 0 , width : '100%' } } >
148- { operations . map ( ( operation , index ) => (
149- < PatchOperationItem
150- key = { `${ operation . type } -${ operation . path } -${ index } ` }
151- operation = { operation }
152- />
153- ) ) }
90+ < PatchOperationItem operation = { operation } />
15491 </ box >
15592 ) ,
15693 }
15794 } ,
158- } )
95+ } )
0 commit comments