Explorar o código

Merge remote-tracking branch 'origin/master' into codex/ask-user-question

# Conflicts:
#	packages/bash/bash-local/tests/executor.spec.ts
#	packages/bash/bash-local/tests/run.spec.ts
Yichen Jiang hai 3 meses
pai
achega
db9437a50e

+ 2 - 2
packages/bash/bash-local/tests/executor.spec.ts

@@ -92,8 +92,8 @@ describe('LocalBashExecutor.run', () => {
 
   it('kill escalation uses the configured graceMs (a TERM-trapping task dies by SIGKILL)', async () => {
     const { bash } = await setup() // setup pins graceMs: 200 via config
-    const task = bash.start(bash.resolve({ command: 'trap \'\' TERM; echo trap-ready; sleep 60' }))
-    await readUntil(bash, task.id, 'trap-ready')
+    const task = bash.start(bash.resolve({ command: 'trap \'\' TERM; echo ready; while :; do sleep 60 & wait $!; done' }))
+    await readUntil(bash, task.id, 'ready\n')
     bash.kill(task.id)
     await task.done
     expect(task.signal).toBe('SIGKILL')

+ 11 - 7
packages/bash/bash-local/tests/run.spec.ts

@@ -1,4 +1,4 @@
-import { existsSync, mkdtempSync, readFileSync, statSync } from 'node:fs'
+import { mkdtempSync, readFileSync, statSync } from 'node:fs'
 import { tmpdir } from 'node:os'
 import { dirname, join } from 'node:path'
 import { describe, expect, it, vi } from 'vitest'
@@ -56,13 +56,18 @@ async function waitForStdout(running: RunningBash, expected: string, timeoutMs =
   throw new Error(`stdout did not include ${JSON.stringify(expected)} after ${timeoutMs}ms`)
 }
 
-async function waitForFile(file: string, timeoutMs = 5_000): Promise<void> {
+async function waitForPidFile(path: string, timeoutMs = 5_000): Promise<number> {
   const deadline = Date.now() + timeoutMs
   while (Date.now() < deadline) {
-    if (existsSync(file)) return
+    try {
+      const pid = Number(readFileSync(path, 'utf8').trim())
+      if (Number.isSafeInteger(pid) && pid > 0) return pid
+    } catch {
+      // The child shell has not written the pid file yet.
+    }
     await new Promise(resolve => setTimeout(resolve, 20))
   }
-  throw new Error(`${file} did not exist after ${timeoutMs}ms`)
+  throw new Error(`pid file ${path} was not written after ${timeoutMs}ms`)
 }
 
 describe('runBash', () => {
@@ -116,7 +121,7 @@ describe('runBash', () => {
   })
 
   it('escalates to SIGKILL when SIGTERM is trapped', async () => {
-    const running = runBash(spec('trap \'\' TERM; echo ready; sleep 60', { graceMs: 200 }))
+    const running = runBash(spec('trap \'\' TERM; echo ready; while :; do sleep 60 & wait $!; done', { graceMs: 200 }))
     await waitForStdout(running, 'ready\n')
     running.kill()
     const result = await running.done
@@ -128,8 +133,7 @@ describe('runBash', () => {
     // group must take the sleep down with bash.
     const pidFile = join(spillDir, `grandchild-${Date.now()}.pid`)
     const running = runBash(spec(`sleep 60 & echo $! > ${pidFile}; wait`))
-    await waitForFile(pidFile)
-    const grandchild = Number(readFileSync(pidFile, 'utf8').trim())
+    const grandchild = await waitForPidFile(pidFile)
     expect(grandchild).toBeGreaterThan(0)
 
     running.kill()