Skip to content

fix: hook command grandchildren hold stdio pipes and hang triggers forever #500

Description

@LeXwDeX

Why

深度审计确认(2026-09-02,资源泄露审计):execShellpackages/opencode/src/hook/settings.ts:1054-1094)用 Node spawntimeout 选项执行用户配置的 command hook。timeout 到点只对直接子进程(/bin/sh -c 包装)发 SIGTERM;hook 命令派生的孙进程若继承 stdio 管道且比 shell 活得久,Node 的 close 事件(要求进程退出 stdio 流全部关闭)永不发射,Promise 永不 resolve,commandHandlerEffect.promise 无 AbortSignal——整个 PreToolUse/Stop 等 hook trigger 无限挂起,阻塞会话。

Scope

  • packages/opencode/src/hook/settings.tsexecShell(约 1054-1094 行)
  • 消费点 commandHandler(约 1380-1384 行)

Approach

  • 超时/命令结束后改用「exit 事件 + 流关闭」分离等待:Promise.all([exited, streamsClosed]) 外加有界超时兜底,超时后对进程组 kill(复用 packages/core/src/cross-spawn-spawner.ts 已实现的 killGroup 语义:detached + 负 PID / Windows taskkill /T),kill 后仍等待 exit 完成收割
  • 不改变 hook 的既有超时配置语义与 stdout/stderr 聚合行为

Acceptance

  • 新增回归测试:hook 命令派生持有 stdout 管道的孙进程并超时 → execShell 在超时窗口(非永久)内返回,孙进程被终止
  • 既有 hook 测试全绿;bun run test:dag-core 不受影响
  • 用户环境实证命令(PreToolUse hook 派生 sleep 300 & 类后台进程)不再挂死 trigger

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions