11"use client" ;
22
33import { useParams , useSearchParams , useRouter } from "next/navigation" ;
4+ import { useMemo , useState } from "react" ;
45import { useRealtimeRun , useRealtimeStream } from "@trigger.dev/react-hooks" ;
6+ import { Streamdown } from "streamdown" ;
7+ import { ArrowLeft , AlertCircle , Calendar , Copy , Check } from "lucide-react" ;
58import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card" ;
69import { Button } from "@/components/ui/button" ;
710import { Alert , AlertDescription } from "@/components/ui/alert" ;
8- import { ArrowLeft , AlertCircle , Calendar , Copy , Check } from "lucide-react" ;
911import { changelogStream } from "@/trigger/changelog-stream" ;
10- import { useState } from "react" ;
11- import { Streamdown } from "streamdown" ;
12-
13- interface ToolCall {
14- tool : string ;
15- input : string ;
16- timestamp : string ;
17- }
18-
19- interface AgentState {
20- phase : string ;
21- turns : number ;
22- toolCalls : ToolCall [ ] ;
23- diffsInvestigated : string [ ] ;
24- commitCount ?: number ;
25- currentDiff ?: string ;
26- startedAt : string ;
27- completedAt ?: string ;
28- durationMs ?: number ;
29- }
30-
31- interface Summary {
32- diffsChecked : number ;
33- agentTurns : number ;
34- durationSec : number ;
35- }
3612
3713interface RunMetadata {
38- progress ?: number ;
39- status ?: string ;
4014 repository ?: string ;
4115 commitCount ?: number ;
4216 error ?: string ;
43- agent ?: AgentState ;
44- summary ?: Summary ;
17+ agent ?: {
18+ phase : string ;
19+ turns : number ;
20+ toolCalls : { tool : string ; input : string } [ ] ;
21+ diffsInvestigated : string [ ] ;
22+ } ;
23+ summary ?: {
24+ durationSec : number ;
25+ } ;
4526}
4627
4728function parseChangelogSections (
@@ -106,13 +87,12 @@ export default function ResponsePage() {
10687 const params = useParams ( ) ;
10788 const searchParams = useSearchParams ( ) ;
10889 const router = useRouter ( ) ;
109- const [ isAborting , setIsAborting ] = useState ( false ) ;
90+ const [ copiedIndex , setCopiedIndex ] = useState < number | null > ( null ) ;
11091
11192 const runId = params . runId as string ;
11293 const accessToken = searchParams . get ( "accessToken" ) || "" ;
11394 const startDate = searchParams . get ( "startDate" ) || "" ;
11495 const endDate = searchParams . get ( "endDate" ) || "" ;
115- const [ copiedIndex , setCopiedIndex ] = useState < number | null > ( null ) ;
11696
11797 const { run, error : runError } = useRealtimeRun ( runId , { accessToken } ) ;
11898
@@ -141,6 +121,10 @@ export default function ResponsePage() {
141121 } ;
142122
143123 const combinedText = parts ?. join ( "" ) || "" ;
124+ const sections = useMemo (
125+ ( ) => parseChangelogSections ( combinedText ) ,
126+ [ combinedText ]
127+ ) ;
144128
145129 const getStatus = ( ) => {
146130 if ( runError || streamError ) return "error" ;
@@ -181,7 +165,7 @@ export default function ResponsePage() {
181165 </ Button >
182166
183167 < h1 className = "text-2xl font-bold tracking-tight" >
184- Changelog generation
168+ Changelog entries
185169 </ h1 >
186170 </ header >
187171
@@ -203,7 +187,7 @@ export default function ResponsePage() {
203187 < CardHeader >
204188 < div className = "flex items-center justify-between" >
205189 < CardTitle className = "text-muted-foreground font-medium" >
206- Claudey is cooking...
190+ Claude is cooking...
207191 </ CardTitle >
208192 < span className = "text-sm text-muted-foreground" >
209193 { metadata ?. agent ?. phase || "Initializing..." }
@@ -259,71 +243,65 @@ export default function ResponsePage() {
259243
260244 { /* Changelog Cards */ }
261245 { combinedText . trim ( ) && (
262- < div className = "mt-8 space-y-4" >
263- { parseChangelogSections ( combinedText ) . map ( ( section , i ) => (
246+ < div className = "mt-8 pb-4 space-y-4" >
247+ { sections . map ( ( section , i ) => (
264248 < Card key = { i } >
265- < CardHeader >
266- < div className = "flex items-start justify-between gap-4" >
267- < div className = "space-y-1 " >
249+ < CardHeader className = "flex gap-4" >
250+ < div className = "flex items-center w-full justify-between gap-4 shrink-0 " >
251+ < div className = "gap-3 flex items-center " >
268252 { section . category && (
269253 < span className = "text-xs font-medium text-muted-foreground bg-secondary px-2 py-0.5 rounded" >
270254 { section . category }
271255 </ span >
272256 ) }
273- < CardTitle > { section . title } </ CardTitle >
274- </ div >
275- < div className = "flex items-center gap-4 shrink-0" >
276257 { section . date && (
277258 < span className = "text-xs text-muted-foreground" >
278259 { section . date }
279260 </ span >
280261 ) }
281- < Button
282- variant = "ghost"
283- size = "sm"
284- onClick = { ( ) => handleCopySection ( section , i ) }
285- className = "text-xs text-muted-foreground hover:text-foreground"
286- >
287- { copiedIndex === i ? (
288- < >
289- < Check className = "w-3 h-3 mr-1" />
290- Copied
291- </ >
292- ) : (
293- < >
294- < Copy className = "w-3 h-3 mr-1" />
295- Copy MDX
296- </ >
297- ) }
298- </ Button >
299262 </ div >
263+
264+ < Button
265+ variant = "ghost"
266+ size = "sm"
267+ onClick = { ( ) => handleCopySection ( section , i ) }
268+ className = "text-xs text-muted-foreground hover:text-foreground"
269+ >
270+ { copiedIndex === i ? (
271+ < >
272+ < Check className = "w-3 h-3 mr-1" />
273+ Copied
274+ </ >
275+ ) : (
276+ < >
277+ < Copy className = "w-3 h-3 mr-1" />
278+ Copy MDX
279+ </ >
280+ ) }
281+ </ Button >
300282 </ div >
283+ < CardTitle > { section . title } </ CardTitle >
301284 </ CardHeader >
302285 < CardContent >
303286 < Streamdown
304- isAnimating = {
305- isStreaming &&
306- i === parseChangelogSections ( combinedText ) . length - 1
307- }
287+ isAnimating = { isStreaming && i === sections . length - 1 }
308288 mode = "streaming"
289+ shikiTheme = { [ "github-dark" , "github-dark" ] }
309290 >
310291 { section . content }
311292 </ Streamdown >
312293 </ CardContent >
313294 </ Card >
314295 ) ) }
315296
316- { /* Streaming placeholder */ }
317- { isStreaming &&
318- parseChangelogSections ( combinedText ) . length === 0 && (
319- < Card >
320- < CardContent className = "pt-5" >
321- < Streamdown isAnimating = { isStreaming } mode = "streaming" >
322- { combinedText }
323- </ Streamdown >
324- </ CardContent >
325- </ Card >
326- ) }
297+ { /* Thinking text - shown before changelog sections appear */ }
298+ { isStreaming && sections . length === 0 && (
299+ < div className = "text-xs font-mono text-muted-foreground/70 leading-relaxed" >
300+ < Streamdown isAnimating = { isStreaming } mode = "streaming" >
301+ { combinedText }
302+ </ Streamdown >
303+ </ div >
304+ ) }
327305 </ div >
328306 ) }
329307
0 commit comments