fix(session-notification): use node:child_process to avoid Bun shell GC crash (#543)
Replace Bun shell template literals (ctx.$) with node:child_process.spawn to work around Bun's ShellInterpreter garbage collection bug on Windows. This bug causes segmentation faults in deinitFromFinalizer during heap sweeping when shell operations are used repeatedly over time. Bug references: - oven-sh/bun#23177 (closed incomplete) - oven-sh/bun#24368 (still open) - Pending fix: oven-sh/bun#24093 The fix applies to all platforms for consistency and safety.
This commit is contained in:
committed by
GitHub
parent
204ea319cb
commit
4a38e70fa8
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
||||
import { describe, expect, test, beforeEach, afterEach, spyOn, mock } from "bun:test"
|
||||
import { EventEmitter } from "node:events"
|
||||
import * as childProcess from "node:child_process"
|
||||
|
||||
import { createSessionNotification } from "./session-notification"
|
||||
import { setMainSession, subagentSessions } from "../features/claude-code-session-state"
|
||||
@@ -6,20 +8,11 @@ import * as utils from "./session-notification-utils"
|
||||
|
||||
describe("session-notification", () => {
|
||||
let notificationCalls: string[]
|
||||
let spawnMock: ReturnType<typeof spyOn>
|
||||
|
||||
function createMockPluginInput() {
|
||||
return {
|
||||
$: async (cmd: TemplateStringsArray | string, ...values: any[]) => {
|
||||
// #given - track notification commands (osascript, notify-send, powershell)
|
||||
const cmdStr = typeof cmd === "string"
|
||||
? cmd
|
||||
: cmd.reduce((acc, part, i) => acc + part + (values[i] ?? ""), "")
|
||||
|
||||
if (cmdStr.includes("osascript") || cmdStr.includes("notify-send") || cmdStr.includes("powershell")) {
|
||||
notificationCalls.push(cmdStr)
|
||||
}
|
||||
return { stdout: "", stderr: "", exitCode: 0 }
|
||||
},
|
||||
$: async () => ({ stdout: "", stderr: "", exitCode: 0 }),
|
||||
client: {
|
||||
session: {
|
||||
todo: async () => ({ data: [] }),
|
||||
@@ -32,6 +25,18 @@ describe("session-notification", () => {
|
||||
beforeEach(() => {
|
||||
notificationCalls = []
|
||||
|
||||
// Mock spawn to track notification commands
|
||||
// Uses node:child_process.spawn instead of Bun shell to avoid GC crash
|
||||
spawnMock = spyOn(childProcess, "spawn").mockImplementation((cmd: string, args?: string[]) => {
|
||||
// Track notification commands (osascript, notify-send, powershell)
|
||||
if (cmd.includes("osascript") || cmd.includes("notify-send") || cmd.includes("powershell")) {
|
||||
notificationCalls.push(`${cmd} ${(args ?? []).join(" ")}`)
|
||||
}
|
||||
const emitter = new EventEmitter()
|
||||
setTimeout(() => emitter.emit("close", 0), 0)
|
||||
return emitter as any
|
||||
})
|
||||
|
||||
spyOn(utils, "getOsascriptPath").mockResolvedValue("/usr/bin/osascript")
|
||||
spyOn(utils, "getNotifySendPath").mockResolvedValue("/usr/bin/notify-send")
|
||||
spyOn(utils, "getPowershellPath").mockResolvedValue("powershell")
|
||||
|
||||
Reference in New Issue
Block a user