/**
* Terminal metadata mirrored from terminal_* events: the terminals store the
* panel renders, plus live output attached to the matching pending tool card.
*/
export function createTerminalTracking(state) {
const { terminals, streamingMsg } = state
function onTerminalOpened(data) {
const name = data.terminal_name
if (!name) return
const prev = terminals.value[name] || {}
terminals.value = { ...terminals.value, [name]: { ...prev, name, closed: false } }
}
function onTerminalOutput(data) {
const name = data.terminal_name
if (!name) return
const prev = terminals.value[name] || { output: '' }
const next = {
...prev,
output: (prev.output || '') + (data.delta || ''),
}
terminals.value = { ...terminals.value, [name]: next }
// Also try to attach live output to the matching pending tool card
const msg = streamingMsg.value
if (msg) {
for (let i = msg.tools.length - 1; i >= 0; i--) {
const t = msg.tools[i]
if (t.kind === 'tool' && t.name === 'terminal' && t.terminalName === name) {
t.terminalOutput = next.output
break
}
}
}
}
function onTerminalClosed(data) {
const name = data.terminal_name
if (!name) return
const prev = terminals.value[name] || {}
const next = {
...prev,
closed: true,
closeReason: data.reason || 'unknown',
}
terminals.value = { ...terminals.value, [name]: next }
// Mark matching pending tool card as no longer running
const msg = streamingMsg.value
if (msg) {
for (let i = msg.tools.length - 1; i >= 0; i--) {
const t = msg.tools[i]
if (t.kind === 'tool' && t.name === 'terminal' && t.terminalName === name && t.pending) {
t.pending = false
t.success = data.reason !== 'error'
break
}
}
}
}
return { onTerminalOpened, onTerminalOutput, onTerminalClosed }
}