Skip to content

Commit 9dec482

Browse files
committed
fix: clean PTY helpers before post-exit drain
1 parent f7ea00c commit 9dec482

1 file changed

Lines changed: 32 additions & 23 deletions

File tree

Sources/CodexBarCore/Host/PTY/TTYCommandRunner.swift

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -498,27 +498,6 @@ public struct TTYCommandRunner {
498498
}
499499
}
500500

501-
static func drainReadResult(for data: Data, terminalRead: Int, errno err: Int32) -> DrainReadResult {
502-
if !data.isEmpty {
503-
return .data(data)
504-
}
505-
506-
if terminalRead == 0 {
507-
return .closed
508-
}
509-
510-
if terminalRead < 0 {
511-
if err == EAGAIN || err == EWOULDBLOCK || err == EINTR {
512-
return .wouldBlock
513-
}
514-
if err == EIO {
515-
return .closed
516-
}
517-
}
518-
519-
return .closed
520-
}
521-
522501
static func locateBundledHelper(_ name: String) -> String? {
523502
let fm = FileManager.default
524503

@@ -671,6 +650,7 @@ public struct TTYCommandRunner {
671650
var cleanedUp = false
672651
var launchedProcess: SpawnedProcessGroup?
673652
var didExceedOutputLimit = false
653+
var didTerminateSynchronously = false
674654
/// Always tear down the PTY child (and its process group) even if we throw early
675655
/// while bootstrapping the CLI (e.g. when it prompts for login/telemetry).
676656
func cleanup() {
@@ -696,7 +676,9 @@ public struct TTYCommandRunner {
696676
try? primaryHandle.close()
697677
launchedProcess.abortSynchronously()
698678
} else {
699-
launchedProcess.terminateSynchronously()
679+
if !didTerminateSynchronously {
680+
launchedProcess.terminateSynchronously()
681+
}
700682
try? primaryHandle.close()
701683
}
702684
TTYCommandRunnerActiveProcessRegistry.unregister(pid: launchedProcess.pid)
@@ -952,7 +934,13 @@ public struct TTYCommandRunner {
952934

953935
let exitedBeforeDeadline = !stoppedEarly
954936
&& process.exitObservationDate.map { $0 <= deadline } == true
955-
let exitStatusBeforeDrain = exitedBeforeDeadline ? process.finishSynchronously() : nil
937+
let exitStatusBeforeDrain: Int32?
938+
if exitedBeforeDeadline {
939+
exitStatusBeforeDrain = process.terminateSynchronously()
940+
didTerminateSynchronously = true
941+
} else {
942+
exitStatusBeforeDrain = nil
943+
}
956944

957945
func drainNonCodexOutput(for duration: TimeInterval) throws -> Bool {
958946
let drainFor = max(0, duration)
@@ -1189,6 +1177,27 @@ public struct TTYCommandRunner {
11891177
}
11901178

11911179
extension TTYCommandRunner {
1180+
static func drainReadResult(for data: Data, terminalRead: Int, errno err: Int32) -> DrainReadResult {
1181+
if !data.isEmpty {
1182+
return .data(data)
1183+
}
1184+
1185+
if terminalRead == 0 {
1186+
return .closed
1187+
}
1188+
1189+
if terminalRead < 0 {
1190+
if err == EAGAIN || err == EWOULDBLOCK || err == EINTR {
1191+
return .wouldBlock
1192+
}
1193+
if err == EIO {
1194+
return .closed
1195+
}
1196+
}
1197+
1198+
return .closed
1199+
}
1200+
11921201
static func withIsolatedActiveProcessRegistryForTesting<T>(_ operation: () throws -> T) rethrows -> T {
11931202
try TTYCommandRunnerActiveProcessRegistry.withIsolatedStateForTesting(operation)
11941203
}

0 commit comments

Comments
 (0)