1- import type { SessionInfo , SessionMessageAssistant , SessionMessageInfo , ShellInfo } from "@opencode/client/promise"
1+ import type { SessionInfo , SessionMessageInfo , ShellInfo } from "@opencode/client/promise"
22import { scanSubagentTranscript } from "@opencode/session-ui/subagent-transcript"
33import { Predicate } from "effect"
44import { createMemo } from "solid-js"
@@ -46,14 +46,13 @@ export function createSessionBackground(input: {
4646 ]
4747 } )
4848
49- const assistant = messages . reduce < SessionMessageAssistant | undefined > ( ( latest , message ) => {
50- if ( message . type === "synthetic ") return latest
49+ for ( const message of messages ) {
50+ if ( message . type !== "assistant ") continue
5151
52- if ( message . type !== "assistant" ) return latest
53- message . content . forEach ( ( part ) => {
54- if ( part . type !== "tool" || part . name !== "shell" ) return
52+ for ( const part of message . content ) {
53+ if ( part . type !== "tool" || part . name !== "shell" ) continue
5554
56- if ( part . state . status !== "completed" || part . state . metadata ?. status !== "running" ) return
55+ if ( part . state . status !== "completed" || part . state . metadata ?. status !== "running" ) continue
5756
5857 const shellID = part . state . metadata . shellID
5958 const command = part . state . input . command
@@ -65,36 +64,48 @@ export function createSessionBackground(input: {
6564 label : Predicate . isString ( command ) ? command : part . id ,
6665 } ,
6766 } )
68- } )
67+ }
68+ }
69+
70+ // Live foreground calls, from the shared scan so the header and the panel
71+ // agree on what counts as live. Legacy task parts surface as subagents.
72+ const blocking = [
73+ ...scan . calls . flatMap ( ( call ) => {
74+ if ( ! call . live || call . status !== "running" ) return [ ]
75+
76+ return [
77+ {
78+ type : "subagent" as const ,
79+ partID : call . partID ,
80+ id : call . childID ,
81+ label : call . description ,
82+ } ,
83+ ]
84+ } ) ,
85+ ...( scan . live ?. content . flatMap ( ( part ) => {
86+ if ( part . type !== "tool" || part . name !== "shell" || part . state . status !== "running" ) return [ ]
6987
70- return message . time . completed === undefined ? message : latest
71- } , undefined )
88+ const shellID = part . state . metadata . shellID
89+ const command = part . state . input . command
90+
91+ return [
92+ {
93+ type : "shell" as const ,
94+ partID : part . id ,
95+ id : Predicate . isString ( shellID ) ? shellID : undefined ,
96+ label : Predicate . isString ( command ) ? command : undefined ,
97+ } ,
98+ ]
99+ } ) ?? [ ] ) ,
100+ ]
72101
73102 return {
74103 // Backgrounded calls stay listed until their synthetic completion notice lands (filtered at construction).
75104 subagents,
76105 shells : shells . flatMap ( ( item ) =>
77106 ! completed . has ( item . partID ) && ! completed . has ( item . task . id ) ? [ item . task ] : [ ] ,
78107 ) ,
79- blocking :
80- assistant ?. content . flatMap ( ( part ) => {
81- if ( part . type !== "tool" || part . state . status !== "running" ) return [ ]
82-
83- if ( part . name !== "shell" && part . name !== "subagent" ) return [ ]
84- const value = part . name === "shell" ? part . state . metadata . shellID : part . state . metadata . sessionID
85- const label = part . name === "shell" ? part . state . input . command : part . state . input . description
86-
87- return [
88- {
89- // SAFETY: the guard above leaves only "shell" and "subagent" names.
90- // oxlint-disable-next-line anti-slop/require-safety-comment-for-type-assertion -- see SAFETY above
91- type : part . name as "shell" | "subagent" ,
92- partID : part . id ,
93- id : Predicate . isString ( value ) ? value : undefined ,
94- label : Predicate . isString ( label ) ? label : undefined ,
95- } ,
96- ]
97- } ) ?? [ ] ,
108+ blocking,
98109 }
99110 } )
100111
0 commit comments