fix: sync run button state with terminal process via centralized exit tracking
Centralize terminal process lifecycle in terminal-context as single
source of truth. TerminalView reports exit/failure via callback,
context maintains exitedTerminals set, command-dropdown reacts to it.
Removes redundant polling and per-component exit event subscriptions
that raced with deferred spawn introduced in b2d10fa.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { TerminalTabBar } from "./terminal-tab-bar"
|
||||
import { TerminalView } from "./terminal-view"
|
||||
|
||||
export function TerminalPanel() {
|
||||
const { isOpen, tabs, activeTabId } = useTerminalContext()
|
||||
const { isOpen, tabs, activeTabId, markTerminalExited } = useTerminalContext()
|
||||
|
||||
return (
|
||||
<section
|
||||
@@ -22,6 +22,7 @@ export function TerminalPanel() {
|
||||
initialCommand={tab.initialCommand}
|
||||
isActive={tab.id === activeTabId}
|
||||
isVisible={isOpen}
|
||||
onProcessExited={markTerminalExited}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -95,6 +95,7 @@ interface TerminalViewProps {
|
||||
initialCommand?: string
|
||||
isActive: boolean
|
||||
isVisible: boolean
|
||||
onProcessExited?: (terminalId: string) => void
|
||||
}
|
||||
|
||||
export function TerminalView({
|
||||
@@ -103,6 +104,7 @@ export function TerminalView({
|
||||
initialCommand,
|
||||
isActive,
|
||||
isVisible,
|
||||
onProcessExited,
|
||||
}: TerminalViewProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const fitAddonRef = useRef<{ fit: () => void } | null>(null)
|
||||
@@ -110,6 +112,7 @@ export function TerminalView({
|
||||
const lastResizeRef = useRef<{ cols: number; rows: number } | null>(null)
|
||||
const isActiveRef = useRef(isActive)
|
||||
const isVisibleRef = useRef(isVisible)
|
||||
const onProcessExitedRef = useRef(onProcessExited)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -117,6 +120,10 @@ export function TerminalView({
|
||||
isVisibleRef.current = isVisible
|
||||
}, [isActive, isVisible])
|
||||
|
||||
useEffect(() => {
|
||||
onProcessExitedRef.current = onProcessExited
|
||||
}, [onProcessExited])
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
let cleanup: (() => void) | undefined
|
||||
@@ -188,6 +195,7 @@ export function TerminalView({
|
||||
const unlistenExit = await subscribe<TerminalEvent>(
|
||||
`terminal://exit/${terminalId}`,
|
||||
() => {
|
||||
onProcessExitedRef.current?.(terminalId)
|
||||
term.write("\r\n\x1b[90m[Process exited]\x1b[0m\r\n")
|
||||
}
|
||||
)
|
||||
@@ -206,6 +214,7 @@ export function TerminalView({
|
||||
try {
|
||||
await terminalSpawn(workingDir, initialCommand, terminalId)
|
||||
} catch (err) {
|
||||
onProcessExitedRef.current?.(terminalId)
|
||||
term.write(`\r\n\x1b[31m[Failed to start terminal: ${err}]\x1b[0m\r\n`)
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false)
|
||||
|
||||
Reference in New Issue
Block a user