@@ -181,6 +181,88 @@ process.stdin.on('end', () => {
181181 }
182182} ) ;
183183
184+ test ( 'maps Claude structured output deltas to response progress' , async ( ) => {
185+ const directory = await mkdtemp ( join ( tmpdir ( ) , 'codiff-claude-structured-progress-' ) ) ;
186+ const fakeClaudePath = join ( directory , 'claude' ) ;
187+ const previousClaudePath = process . env . CODIFF_CLAUDE_PATH ;
188+ const events = [
189+ {
190+ event : {
191+ content_block : { signature : '' , thinking : '' , type : 'thinking' } ,
192+ type : 'content_block_start' ,
193+ } ,
194+ type : 'stream_event' ,
195+ } ,
196+ {
197+ event : {
198+ delta : { thinking : 'Planning' , type : 'thinking_delta' } ,
199+ type : 'content_block_delta' ,
200+ } ,
201+ type : 'stream_event' ,
202+ } ,
203+ {
204+ event : {
205+ content_block : {
206+ id : 'toolu_1' ,
207+ input : { } ,
208+ name : 'StructuredOutput' ,
209+ type : 'tool_use' ,
210+ } ,
211+ type : 'content_block_start' ,
212+ } ,
213+ type : 'stream_event' ,
214+ } ,
215+ {
216+ event : {
217+ delta : { partial_json : '{"version":1}' , type : 'input_json_delta' } ,
218+ type : 'content_block_delta' ,
219+ } ,
220+ type : 'stream_event' ,
221+ } ,
222+ {
223+ is_error : false ,
224+ result : '{"version":1}' ,
225+ structured_output : { version : 1 } ,
226+ type : 'result' ,
227+ } ,
228+ ] ;
229+
230+ try {
231+ await writeFile (
232+ fakeClaudePath ,
233+ `#!/usr/bin/env node
234+ process.stdin.resume();
235+ process.stdin.on('end', () => {
236+ process.stdout.write(${ JSON . stringify ( events . map ( ( event ) => JSON . stringify ( event ) ) . join ( '\n' ) ) } );
237+ });
238+ ` ,
239+ ) ;
240+ await chmod ( fakeClaudePath , 0o755 ) ;
241+ process . env . CODIFF_CLAUDE_PATH = fakeClaudePath ;
242+ const phases : Array < string > = [ ] ;
243+
244+ await expect (
245+ runClaude ( directory , 'prompt' , { type : 'object' } , 'walkthrough.json' , 'Timed out.' , {
246+ onProgress : ( phase ) => phases . push ( phase ) ,
247+ } ) ,
248+ ) . resolves . toBe ( '{"version":1}' ) ;
249+
250+ expect ( phases ) . toEqual ( [
251+ 'agent-generation' ,
252+ 'agent-generation' ,
253+ 'response-received' ,
254+ 'response-received' ,
255+ ] ) ;
256+ } finally {
257+ if ( previousClaudePath == null ) {
258+ delete process . env . CODIFF_CLAUDE_PATH ;
259+ } else {
260+ process . env . CODIFF_CLAUDE_PATH = previousClaudePath ;
261+ }
262+ await rm ( directory , { force : true , recursive : true } ) ;
263+ }
264+ } ) ;
265+
184266test ( 'supports per-call Claude Code timeouts' , async ( ) => {
185267 const directory = await mkdtemp ( join ( tmpdir ( ) , 'codiff-claude-timeout-' ) ) ;
186268 const fakeClaudePath = join ( directory , 'claude' ) ;
0 commit comments