makecindy / makecindy/cindy

bug(desktop/codex): Playwright CLI named sessions leak orphan headless system Chrome on macOS

Open
#2,842 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
401
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 问题概述

Cindy 托管的 Codex Agent 使用 Playwright CLI 创建命名浏览器会话后,在任务完成、会话结束及 Cindy 重启时没有回收这些会话。Playwright 的 detached `cliDaemon.js` 与它启动的 headless 系统 Chrome 会跨任务、跨 Cindy 进程继续存活,最终成为 `PPID=1` 的孤儿进程。

在 macOS 上,这些进程使用系统 `/Applications/Google Chrome.app`,与用户日常 Chrome 共享 `com.google.Chrome` 应用身份。它们没有普通窗口,Dock 无法正常打开/关闭;同时可能放大 #1854 中普通外部链接被投递到自动化 Chrome 实例的问题。

这不是项目脚本或用户手动启动的浏览器:本机 Cindy Codex session rollout 明确记录了 Agent 的 Playwright CLI 工具调用,且任务正常完成后没有对应的 `close`。

## 环境

- Cindy: 0.1.50
- macOS: 26.6.1 (25G76), arm64
- Google Chrome: 151.0.7922.138
- `@playwright/cli`: 0.1.18
- `playwright-core`: 1.63.0-alpha-2026-08-05

## 本机证据与时间线

2026-08-15,Cindy 托管的 Codex 在 MarkGrove 浏览器验收中依次执行:

```text
playwright_cli.sh -s=prod2 open http://127.0.0.1:4173/
playwright_cli.sh -s=dev2 open http://127.0.0.1:5173/
playwright_cli.sh -s=prod3 open http://127.0.0.1:4173/
playwright_cli.sh -s=dragaudit open http://127.0.0.1:5173/
```

对应 rollout 中记录了各会话成功启动:

```text
Browser prod2 opened with pid 74632
Browser dev2 opened with pid 75856
Browser prod3 opened with pid 76312
Browser dragaudit opened with pid 78706
```

之后相关 turn 均正常进入 `task_complete`,但 session 记录中没有任何对应命令:

```text
-s= close
close-all
kill-all
```

到 2026-08-17,这些进程仍在:

```text
node .../playwright-core/lib/entry/cliDaemon.js prod2
node .../playwright-core/lib/entry/cliDaemon.js dev2
node .../playwright-core/lib/entry/cliDaemon.js prod3
node .../playwright-core/lib/entry/cliDaemon.js dragaudit
```

四个 daemon 均为 `PPID=1`,每个都维持一个使用临时 `playwright_chromiumdev_profile-*` 的系统 Chrome,Chrome 参数包括:

```text
--headless
--no-startup-window
--remote-debugging-pipe
--user-data-dir=.../playwright_chromiumdev_profile-...
```

Cindy 在此期间已经重启,因此这些进程已脱离原 Cindy/Codex 生命周期。

执行 Playwright 官方清理命令后:

```sh
playwright-cli close-all
playwright-cli list
```

结果变为 `(no browsers)`,所有 `cliDaemon.js` 和 `playwright_chromiumdev_profile-*` 进程消失。

## 预期行为

- Cindy/Agent 创建的 Playwright 会话在不再需要时正常关闭。
- Cindy 退出、异常终止或下一次启动时,可以识别并处理仅由 Cindy 拥有的 stale Playwright sessions。
- 不留下无窗口、无法从 Dock 管理的系统 Chrome。
- 不影响用户从其他终端、IDE 或项目自行启动的 Playwright sessions。

## 实际行为

- Agent 创建命名会话后只完成业务任务,没有配对执行 `close`。
- Playwright CLI daemon 按设计 detached,原调用方退出后继续存活。
- Cindy 没有记录会话所有权,也没有任务/应用生命周期兜底。
- macOS 看到的是仍在运行但无窗口的 Google Chrome;普通 URL 路由还可能与 #1854 叠加。

## 根因判断

Playwright CLI 的命名 session 持久化本身是公开设计;其文档明确要求调用方在完成后执行 `close` / `close-all`,僵尸状态使用 `kill-all`。因此主要缺陷不应描述为“Playwright 随机无法退出”,而是:

1. Cindy 托管 Agent 的 Playwright workflow 没有保证 open/close 配对;
2. Cindy Host 没有为 Agent 创建的 Playwright session 建立所有权与退出恢复;
3. headless 自动化使用系统 Google Chrome,使孤儿实例在 macOS 上与日常 Chrome 共享应用身份。

## 与 #1854 的关系

- #1854:Cindy 外置浏览器使用系统 Chrome + 独立 profile,普通外部 URL 可能进入 Cindy profile。
- 本 Issue:Cindy 托管 Codex 创建的 Playwright CLI 命名会话未回收,daemon/headless Chrome 跨任务、跨 Cindy 重启残留。

两者机制不同,不是重复 Issue;但都会受到 macOS 上相同 Chrome bundle identity/URL 投递行为影响,应交叉回归。

## 建议修复

不要在 Cindy 退出时直接全局执行 `playwright-cli kill-all`,这可能误杀用户在其他终端或项目启动的会话。

建议按所有权清理:

1. Cindy 为 Agent 创建的 Playwright session 使用包含 Cindy instance/dialogue/turn 标识的 session 名。
2. Host 记录本实例创建的 session 与 daemon/browser PID。
3. 正常任务结束时对临时验收会话执行对应 `close`。
4. Cindy 退出时只关闭本实例拥有的 session;崩溃后下次启动按 ownership marker 清理 stale session。
5. Cindy-side Playwright Skill 明确要求 `open` 必须与 `close` 配对,并在异常路径使用 finally-style cleanup。
6. macOS headless 自动化优先使用 Playwright Chromium/Chrome for Testing 或独立 bundle identity,避免系统日常 Chrome 的 URL routing。
7. 增加测试:正常完成、Agent error/abort、Cindy quit/restart、多个 workspace 并行、外部非 Cindy Playwright session 不被误杀。

## 验收标准

- Agent 浏览器验收结束后,Cindy 创建的命名 session 不再出现在 `playwright-cli list`。
- Cindy 重启后不存在属于上一实例的 `cliDaemon.js` / headless Chrome。
- 用户自行启动的 Playwright session 保持不受影响。
- Cindy 自动化运行期间及结束后,普通外部链接始终进入用户日常默认浏览器。

Contributor guide

Open the contributing guide

Research direction

Start by tracing the Cindy-hosted Playwright CLI workflow around the recorded open commands and the playwright-core/lib/entry/cliDaemon.js process. Review how session ownership and task or application lifecycle are currently represented, then run the normal-completion, abort, quit/restart, parallel-workspace, and external-session cases described in the acceptance criteria. Done means Cindy-owned sessions are cleaned up without affecting user-owned sessions or external URL routing.

Written by the indexing model from the issue text.

Assessment

Tech stack
electron, macos, playwright, typescript
Domain
desktop, testing-qa
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.