Repository navigation
Closed
Description
更新:根因已定位(附完整证据链)
在 stock 官方版与纯 seam 层复现后,崩溃机制已修正——之前报告中的归因(os.kill(pid, 0) 走 TerminateProcess)不准确,实际是 Ctrl+C 控制台广播。以下是完整证据与修正后的根因分析。
复现矩阵(全部实测)
| 环境 | 结果 |
|---|---|
桌面版(dataelement/dsh-desktop)执行 _pid_is_alive(os.getpid()) |
崩溃(两次,需重启) |
stock 官方 dsh web(0.1.1-rc.2,独立 DSH_HOME,不经桌面壳)执行同命令 |
崩溃(两次),无任何 stderr 输出 |
纯 seam 脚本:直接调用 @deepseek-ai/dsh-subprocess-local spawn 自杀 python(不经 web/agent/桌面壳) |
宿主 node 进程静默退出,无任何事件/日志 |
| 同控制台的 PowerShell | 后续命令也被打断(Ctrl+C 广播波及) |
_pid_is_alive(17576) / _pid_is_alive(999999999)(PID 不存在) |
正常返回 False,无任何影响 |
python --version(正常退出的子进程) |
完全正常,宿主存活 |
关键退出码
纯 seam 脚本宿主进程的 $LASTEXITCODE = -1073741510 = 0xC000013A = STATUS_CONTROL_C_EXIT(被 Ctrl+C 终止)。第二次运行时连 PowerShell 命令行的后续命令都被打断——证明 Ctrl+C 事件广播到了整个共享控制台。
根因链
- Python 侧(触发方):Windows 上
os.kill(pid, 0)的sig=0恰好等于signal.CTRL_C_EVENT(已实测:CTRL_C_EVENT = 0)。Python 对CTRL_C_EVENT/CTRL_BREAK_EVENT走GenerateConsoleCtrlEvent(sig, pid)分支(TerminateProcess只用于其他 sig 值)。因此os.kill(pid, 0)的真实语义是:向与 pid 共享同一控制台的所有进程广播 Ctrl+C,而不是 POSIX 的"存活探测"。 - DSH 侧:
@deepseek-ai/dsh-subprocess-local的spawn在 Windows 上使用detached: false(lib/index.js:805:detached: platform !== "win32")→ 子进程与宿主共享同一控制台。子进程执行os.kill(自己的pid, 0)时,Ctrl+C 广播直接命中宿主。 - 宿主侧:node 默认的 Ctrl+C 处理是立即退出且无任何日志——这正是此前所有"静默崩溃"(无 stderr)现象的原因。
结论与修复建议(更新)
- 维持 weijiafu14 / denial123789 的意见:不加全局
uncaughtException/unhandledRejection兜底(那是最后边界,不是修复手段)。 - 根因修复候选:
- DSH
spawn在 Windows 上为子进程创建独立进程组/控制台(CREATE_NEW_PROCESS_GROUP/detached: true),使子进程的GenerateConsoleCtrlEvent无法波及宿主; - 或宿主进程调用
SetConsoleCtrlHandler(NULL, TRUE)忽略CTRL_C_EVENT(适用于可控场景); - 子进程输出流的
'error'监听与句柄清理仍建议补(EPIPE 路径),但不是本问题的根因。
- DSH
- 触发方(douyin-sparkflow 的
launcher.py):os.kill(pid, 0)存活探测在 Windows 上不可用(语义=Ctrl+C 广播),应改用OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION)+GetExitCodeProcess,或 psutil。此坑会单独提交到其仓库。
对维护者的请求
- 确认 Windows 上
spawn的控制台共享策略(detached: false)是有意设计还是疏忽; - 现有的 Host-survival 回归门(19 项)似乎未覆盖"子进程向共享控制台广播 Ctrl+C"这一场景,建议补充。
四层进程身份记录(按 denial123789 的建议)
- 第三方 child(python,venv 解释器):退出(Ctrl+C 广播同时命中自身)
- 官方 DSH Host(纯 seam 脚本 node 进程,PID 448 / 11376):退出码
0xC000013A(STATUS_CONTROL_C_EXIT)静默退出 - 桌面 main process(dataelement/dsh-desktop):崩溃(退出码未捕获,用户观察)
- renderer:断连(用户观察)
Metadata
Metadata
Assignees
Labels
No labels
Activity
yyang8891 commentedon Aug 27, 2026
这种问题vs code都会出现,是模型的问题,不是桌面端工具的问题
[-]子进程异常终止(被强杀)导致 DSH Desktop 整个崩溃(Windows)[/-][+]已定位:子进程 os.kill(pid,0) 广播 Ctrl+C 导致宿主整体退出(Windows)[/+]djs326 commentedon Aug 27, 2026
更新(2026-08-27):stock 官方版复现完成,归属与根因已修正。
按维护者的建议,我们在 stock 官方
dsh(0.1.1-rc.2,npm 全局安装,独立DSH_HOME,不经桌面壳)上复现了同一条命令——stock 同样崩溃。随后用独立 Node 脚本直接调用官方 seam(@deepseek-ai/dsh-subprocess-local)spawn 自杀子进程,宿主 node 进程以退出码0xC000013A(STATUS_CONTROL_C_EXIT,被 Ctrl+C 终止)静默退出,同控制台的 PowerShell 命令行也被打断。根因修正(之前报告写的"
os.kill走TerminateProcess"不准确):signal.CTRL_C_EVENT = 0,因此os.kill(pid, 0)的 sig=0 恰好等于CTRL_C_EVENT,Python 走的是GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)——向共享同一控制台的所有进程广播 Ctrl+C;dsh-subprocess-local在 Windows 上spawn使用detached: false(lib/index.js:805),子进程与宿主共享控制台,广播一发即中,宿主被 Ctrl+C 静默杀死。回应 @yyang8891 的评论:这不是"模型的问题"——模型只是执行了命令;根因是 Python 在 Windows 的
os.killAPI 语义坑 + 宿主未做控制台隔离。VS Code 也会出现类似现象,恰好说明这是 Windows 共享控制台的共性问题;但对一个承诺"宿主存活、子进程失败只是单次工具结果"的运行时,这仍是值得修的健壮性缺口。归属结论:问题在 DSH 本体的 subprocess seam,不在桌面壳。完整证据链、四层进程身份记录与修复建议已更新至官方仓库的讨论(deepseek-ai/deepseek-harness discussion #4713)。
yaojin3616 commentedon Aug 27, 2026
@yaojin3616
fix(windows): detach the Harness process so Ctrl+C broadcasts cannot …
merge: 合并 origin/main 上游改动(2026-08-27~28,12 commits)
fix(windows): give the console-less Harness a hidden console (#289)