bug: 插件沙箱(ghost node utility 进程)内 native 子进程等待失效,CLI 动作结果丢失并可能重复触发提交
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
## 问题描述 / What happened
**实际行为**:ghost 插件通过插件沙箱的 Node 工作进程调用本机 CLI 时(复现用插件为一件github第三方市场插件,二级分派型 `list_tools` / `call_tool`),启动器 `pwsh` 在启动子进程 exe 后**约 1 秒**就以 `exit code 0` 结束,而 exe 实际仍在后台运行;启动器因此读不到结果文件,打印「结果文件不存在」并把该段文本当作工具结果返回给 Agent。结果文件会在插件调用返回后几秒,才由**孤儿 exe** 写出 —— Agent 已经拿不到了。
**期望行为**:`pwsh` 对 native 子进程的同步等待语义可靠(等 exe 真正退出后再读结果文件),或为插件提供官方 CLI 执行通道,能返回真实的 `exitCode` / `stdout` / `stderr`。
**结论**:插件 Node 工作进程运行在 Electron `utilityProcess`(Chromium utility 进程,实测 `--type=utility --utility-sub-type=node.mojom.NodeService`)中,该托管层破坏了 native 子进程的等待/退出语义。**完全相同**的调用链在宿主普通 Node 进程中执行时一切正常。
### 最小复现(只读动作,无副作用)
```
ghost_call({
ghost_id: "",
tool: "call_tool",
args: {
name: "",
args: { tool: "self-test", changelist: "0", workspace_root: "" }
}
})
```
插件通道实际返回(连续 3 次一致):
```
self-test CL=0 client= root=
cwd= p4= exit=0 elapsed=1s
工具:self-test
...
命令:
/submitter-check.exe --request-file ... --result-file ...
结果文件不存在:/cli_requests/0_self-test_result.json(请查看 stdout 与日志确认执行情况。)
变更列表工具 'self-test' 已完成。
```
期望返回:
```
执行结果:success=True code=SELF_TEST_OK
消息:The functional submit-check executable is working.
```
## 环境 / Environment
- Cindy 版本或 commit: 0.1.82(`sourceCommit=58870ddd5f12c63f6cc66568e7548dee3dfd0ea4`,`builtAt=2026-09-15T00:39:02+08:00`)
- 平台与版本: Windows 11 专业版 10.0.26100(win32 x64)
- 安装方式: 官方安装包(`C:/Program Files/Cindy`)
- 相关插件: 一件随包 Node 工作进程的官方市场插件(1.6.3,二级分派型 `list_tools` / `call_tool`)
- 子进程链: `Cindy.exe --type=utility --utility-sub-type=node.mojom.NodeService --service-sandbox-type=none` → `pwsh.exe`(7.6.6)→ 插件随包启动器 `.ps1` → `submitter-check.exe`(实测 PE subsystem = 3,即 CONSOLE,PowerShell 本应同步等待)
## 复现步骤 / Steps to reproduce
1. 在 Windows 上安装并启用该插件(任一在 ghost Node 工作进程里调用本机 CLI 的插件均可复现)。
2. 用插件通道执行上面的只读 `self-test` 调用。
3. 观察返回值:`exit=0 elapsed=1s` + 「结果文件不存在」;而 `/cli_requests/0_self-test_result.json` 在几秒后才出现(1763 字节)。
4. 对照实验(宿主普通 Node 进程,spawn 方式与插件 worker 完全一致):
- `spawn('pwsh', ['-NoProfile','-ExecutionPolicy','Bypass','-Command', <同一份启动器 self-test>])` → `exit=0 elapsed=3682ms`,结果文件同步生成、输出完整;
- `spawn('pwsh', [... 'Start-Sleep -Seconds 4' ...])` → `elapsed=4334ms`,正常等待。
即:同一台机器、同一个 exe、同一份脚本、同样的 spawn 参数,只有「在插件沙箱的 Node 工作进程里执行」这一项不同,结果就完全不同。
详细证据(进程采样时间线、根因分析、影响面与修复建议)见下一条评论。
Contributor guide
Research direction
Start at the ghost_call path and the plugin Node worker running as an Electron utilityProcess, then compare its native child-process spawn behavior with the ordinary Node reproduction described in the issue. Reproduce the Windows self-test and verify that the launcher waits for the executable, reads the result file, returns the real exit code and output, and does not trigger duplicate submissions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, nodejs, powershell, typescript
- Domain
- desktop, operating-systems, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100