fix(shell): add debug logging for tab tracking and WebSocket state

Track which tab messages belong to via _tabId field to ensure AI
responses are sent to the correct terminal tab. Add console.log in
initTerminal, sendToTerminal for troubleshooting tab lifecycle issues.

💘 Generated with Crush

Assisted-by: MiniMax-M2.7 via Crush <crush@charm.land>
This commit is contained in:
Augustin
2026-04-24 15:53:13 +02:00
parent 183dd27407
commit a905f22f1a

View File

@@ -408,9 +408,11 @@ export default function Shell({ api }) {
const bufferSaveInterval = setInterval(() => { if (!disposed) saveBuffer() }, 5000)
console.log(`[Shell] initTerminal tab=${tabId} type=${tab.type} container=${!!container}`)
tabsRef.current[tabId] = { term, fitAddon, ws, resizeObserver, onResize, bufferSaveInterval, saveBuffer, disposed: () => disposed }
const origDispose = () => { disposed = true }
tabsRef.current[tabId]._markDisposed = origDispose
console.log(`[Shell] initTerminal tab=${tabId} done, tabsRef keys:`, Object.keys(tabsRef.current))
}, [])
useEffect(() => {
@@ -601,13 +603,14 @@ export default function Shell({ api }) {
const targetId = tabId || activeTab
const entry = tabsRef.current[targetId]
if (!entry) {
console.warn('sendToTerminal: no terminal initialized for tab', targetId)
console.warn(`[Shell] sendToTerminal: tab ${targetId} not in tabsRef. Available:`, Object.keys(tabsRef.current), 'activeTab:', activeTab, 'requested tabId:', tabId)
return
}
if (!entry.ws || entry.ws.readyState !== WebSocket.OPEN) {
console.warn('sendToTerminal: WebSocket not ready for tab', targetId)
console.warn(`[Shell] sendToTerminal: WebSocket not ready for tab ${targetId}, state:`, entry.ws?.readyState)
return
}
console.log(`[Shell] sendToTerminal: sending code to tab ${targetId} (${code.length} chars)`)
entry.ws.send(JSON.stringify({ type: 'input', data: code + '\r' }))
}, [activeTab])
@@ -646,7 +649,8 @@ export default function Shell({ api }) {
return
}
setAiMessages(prev => [...prev, { role: 'user', content: trimmed }])
const currentTab = activeTab
setAiMessages(prev => [...prev, { role: 'user', content: trimmed, _tabId: currentTab }])
setAiLoading(true)
try {
@@ -655,13 +659,13 @@ export default function Shell({ api }) {
accumulated = partial
setAiMessages(prev => {
const filtered = prev.filter(m => !m._streaming)
return [...filtered, { role: 'assistant', content: partial, _streaming: true }]
return [...filtered, { role: 'assistant', content: partial, _streaming: true, _tabId: currentTab }]
})
})
setAiMessages(prev => {
const filtered = prev.filter(m => !m._streaming)
return [...filtered, { role: 'assistant', content: accumulated }]
return [...filtered, { role: 'assistant', content: accumulated, _tabId: currentTab }]
})
api.getShellChatHistory().then(d => {
setAiTokens(d.tokens || 0)
@@ -858,7 +862,7 @@ export default function Shell({ api }) {
</div>
<div className="ai-panel-messages" ref={aiMessagesRef}>
{aiMessages.map((msg, i) => (
<ShellAIMessage key={i} msg={msg} sendToTerminal={sendToTerminal} terminalTabId={activeTab} />
<ShellAIMessage key={i} msg={msg} sendToTerminal={sendToTerminal} terminalTabId={msg._tabId || activeTab} />
))}
{aiLoading && <div style={{ textAlign: 'center', padding: 8 }}><span className="spinner" /></div>}
</div>