Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [1.1.58]

### Changed
- Enhanced cleanup process in stdio-runner with better handling of client disconnections and process termination
- Added safety timeout for transport cleanup operations to ensure process termination

## [1.1.57]

### Changed
Expand Down
6 changes: 1 addition & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@
"tsx": "^4.19.2",
"typescript": "^5.0.0"
},
"files": [
"dist",
"README.md",
"package.json"
],
"files": ["dist", "README.md", "package.json"],
"exports": {
".": {
"import": "./dist/index.js"
Expand Down
70 changes: 63 additions & 7 deletions src/commands/run/stdio-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,11 @@ export const createStdioRunner = async (
// Only treat it as unexpected if we're ready and haven't started cleanup
if (isReady && !isShuttingDown) {
console.error("[Runner] Process terminated unexpectedly while running")
process.exit(1)
handleExit().catch((error) => {
console.error("[Runner] Error during exit cleanup:", error)
process.exit(1)
})
}
process.exit(0)
}

transport.onerror = (err) => {
Expand All @@ -180,7 +182,10 @@ export const createStdioRunner = async (
} else if (err.message.includes("permission")) {
console.error("[Runner] Permission error when running child process")
}
process.exit(1)
handleExit().catch((error) => {
console.error("[Runner] Error during error cleanup:", error)
process.exit(1)
})
}

await transport.start()
Expand All @@ -190,19 +195,44 @@ export const createStdioRunner = async (
}

const cleanup = async () => {
// Prevent recursive cleanup calls
if (isShuttingDown) {
console.error("[Runner] Cleanup already in progress, skipping...")
return
}

console.error("[Runner] Starting cleanup...")
isShuttingDown = true

// Close transport gracefully
if (transport) {
isShuttingDown = true
await transport.close()
try {
console.error("[Runner] Attempting to close transport...")
await Promise.race([
transport.close(),
new Promise((_, reject) =>
setTimeout(
() => reject(new Error("Transport close timeout")),
3000,
),
),
])
console.error("[Runner] Transport closed successfully")
} catch (error) {
console.error("[Runner] Error during transport cleanup:", error)
}
transport = null
}

console.error("[Runner] Cleanup completed")
}

const handleExit = async () => {
console.error("[Runner] Shutting down STDIO Runner...")
console.error("[Runner] Exit handler triggered, starting shutdown...")
await cleanup()
process.exit(0)
if (!isShuttingDown) {
process.exit(0)
}
}

// Setup event handlers
Expand All @@ -212,7 +242,33 @@ export const createStdioRunner = async (
process.on("exit", () => {
// Synchronous cleanup for exit event
console.error("[Runner] Final cleanup on exit")
// Additional logging if needed
// console.error("[Runner] Final cleanup on exit", {
// transportExists: !!transport,
// isShuttingDown,
// stdinIsTTY: process.stdin.isTTY,
// stdinIsRaw: process.stdin.isRaw,
// hasStdinListeners: process.stdin.listenerCount('data') > 0
// })
})

// Handle STDIN closure (client disconnect)
process.stdin.on("end", () => {
console.error("[Runner] STDIN closed (client disconnected)")
handleExit().catch((error) => {
console.error("[Runner] Error during stdin close cleanup:", error)
process.exit(1)
})
})

process.stdin.on("error", (error) => {
console.error("[Runner] STDIN error:", error)
handleExit().catch((error) => {
console.error("[Runner] Error during stdin error cleanup:", error)
process.exit(1)
})
})

process.stdin.on("data", (data) =>
processMessage(data).catch((error) =>
handleError(error, "Error processing message"),
Expand Down