From 972c637716b54ec09c7fe42b16ce41d829a7c61d Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sat, 25 Jul 2026 15:36:23 +0800 Subject: [PATCH] docs: define local cdp association task --- docs/02-requirements.md | 8 ++++-- docs/04-architecture.md | 9 ++++--- docs/06-tasks.md | 1 + docs/07-user-stories.md | 5 ++++ docs/08-interaction-checklist.md | 8 +++--- docs/api.md | 8 +++--- docs/current-state.md | 7 +++--- docs/tasks/T-302.md | 43 ++++++++++++++++++++++++++++++++ docs/ui/browser-manager.html | 23 +++++++++-------- 9 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 docs/tasks/T-302.md diff --git a/docs/02-requirements.md b/docs/02-requirements.md index da45d0e..0407098 100644 --- a/docs/02-requirements.md +++ b/docs/02-requirements.md @@ -12,12 +12,16 @@ | BR-008 | 只允许管理工具注册且经过身份校验的 PID。 | P0 | | BR-009 | 支持本地配置持久化,绝不保存浏览器凭证。 | P1 | | BR-010 | 提供 CLI 或本地 API,供脚本启动、查询和关闭实例。 | P1 | -| BR-011 | 可选启用本地 CDP,用于读取窗口/tab 信息;默认关闭。 | P2 | +| BR-011 | Chub 启动的 Chrome/Edge 必须启用仅限 loopback 的本地 CDP;端口从设置的起始端口分配,空值默认 9666。 | P1 | +| BR-012 | 同一 user data dir 被外部浏览器占用时,只能在其 CDP 端点可验证时关联为外部实例;不得接管生命周期。 | P1 | ## 验收标准 - 两个不同 user data dir 可以并行启动,互不阻塞。 - 同一 user data dir 的第二次启动被拒绝,并显示已知 PID/来源。 +- 新启动实例使用 `127.0.0.1` 上的远程调试端口;从默认或已保存的起始端口开始递增,并在列表显示实际关联端口。 +- 外部实例只有在其 `DevToolsActivePort` 和本地 CDP 端点均通过浏览器类型校验时才显示“外部已关联”;关联后不得显示关闭、强制关闭或重启入口。 +- 外部实例未启用 CDP、端点失效或权限不足时,显示“外部占用”或“未知占用”,且不得再次使用同一目录启动浏览器。 - 关闭操作不会影响其他 Chrome/Edge 实例。 - 工具重启后,无法确认身份的外部进程只能报告 UNKNOWN,不得被关闭。 - 异常退出后状态在合理时间内变为 EXITED/FAILED。 @@ -26,4 +30,4 @@ ## 不做 -全局杀 Chrome/Edge、自动登录、页面操作、验证码处理、平台 API 集成、远程控制和跨用户权限提升。 +全局杀 Chrome/Edge、自动登录、页面操作、验证码处理、平台 API 集成、远程控制和跨用户权限提升;通过 CDP 管理或关闭外部实例。 diff --git a/docs/04-architecture.md b/docs/04-architecture.md index 375aa76..d7c6d8b 100644 --- a/docs/04-architecture.md +++ b/docs/04-architecture.md @@ -12,6 +12,8 @@ Platform Windows ├─ graceful close / force kill ├─ Job Object └─ profile occupancy inspector + ├─ loopback CDP endpoint inspector + └─ remote-debug port allocator ↓ Chrome / Edge processes ``` @@ -20,7 +22,7 @@ UI/CLI 不直接操作 `exec.Cmd`、Win32 handle 或数据库。Application 层 ## 实例身份 -每个实例至少记录 `instance_id`、browser kind、executable、root PID、user data dir、profile directory、非敏感参数摘要、创建时间、状态和退出码。 +每个实例至少记录 `instance_id`、browser kind、executable、root PID、user data dir、profile directory、非敏感参数摘要、关联的 loopback CDP 端口、归属(托管或外部关联)、创建时间、状态和退出码。 进程身份校验至少比较 PID 存活、executable、命令行中的规范化 `--user-data-dir` 和注册记录。无法确认身份时只能报告 UNKNOWN,不允许关闭。 @@ -28,13 +30,14 @@ UI/CLI 不直接操作 `exec.Cmd`、Win32 handle 或数据库。Application 层 `CREATED -> STARTING -> RUNNING -> STOPPING -> EXITED`;启动失败为 `FAILED`,无法确认的外部实例为 `UNKNOWN`。 -- Start:规范化路径和参数,检查 user data dir,占用检查通过后注册 pending,再启动。 +- Start:规范化路径和参数,先检查 user data dir。未占用时从配置的起始端口选择可用 loopback 端口,注册 pending 后以受控的 `--remote-debugging-address=127.0.0.1` 和 `--remote-debugging-port` 启动,并以 `DevToolsActivePort` 与 `/json/version` 验证实际端点。 +- 外部关联:目录被占用时只检查该目录中的 `DevToolsActivePort` 和其 loopback `/json/version`;端点与浏览器类型均匹配才报告 `EXTERNAL_ASSOCIATED`,不注册、关闭、重启或强制终止该 PID。无法验证时保持 `UNKNOWN`/占用并拒绝启动。 - Stop:校验身份,优先窗口关闭/浏览器协议,超时后经明确授权强制终止。 - Force stop:使用实例 Job Object 或已校验进程树,不按名称全局终止。 - Restart:旧实例退出或完成超时处理后重新执行同一配置。 - App shutdown:取消监控,不默认终止用户浏览器。 -Chrome 和 Edge 共用大部分 Chromium 参数,但 executable 默认路径、进程名称和安装方式不同,通过 `BrowserDefinition` 封装差异。 +Chrome 和 Edge 共用大部分 Chromium 参数,但 executable 默认路径、进程名称和安装方式不同,通过 `BrowserDefinition` 封装差异。CDP 端点只绑定 `127.0.0.1`;端口号和 `/json/version` 是诊断数据,WebSocket URL 不进入持久化、事件或普通 UI 文案。 ## 风险 diff --git a/docs/06-tasks.md b/docs/06-tasks.md index d8bb6a6..14f2406 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -37,6 +37,7 @@ | ID | 任务 | 依赖 | 状态 | | --- | --- | --- | --- | | T-301 | 接入 GUI 启动操作与实例删除确认 | T-204,T-208 | DONE | +| T-302 | 本地 CDP 启动、外部关联与实例端口展示 | T-102,T-301 | DOING | ## Backlog diff --git a/docs/07-user-stories.md b/docs/07-user-stories.md index 65189b2..9d4aa51 100644 --- a/docs/07-user-stories.md +++ b/docs/07-user-stories.md @@ -8,6 +8,7 @@ | US-004 | 用户可以优雅关闭实例;无响应时在确认后强制终止。 | P0 | | US-005 | 用户可以重启指定实例,并确认旧实例已经退出。 | P0 | | US-006 | 用户可以通过 CLI/API 查询、启动和关闭实例。 | P1 | +| US-007 | 用户可以看到实例关联的本地调试端口;同目录外部浏览器已启用调试时,Chub 只关联并展示状态。 | P1 | ## 验收场景 @@ -22,3 +23,7 @@ ### US-006 CLI/API CLI/API 返回稳定错误码和结构化数据;未知 PID、身份不匹配和权限不足必须拒绝操作并给出恢复建议。 + +### US-007 本地 CDP 与外部关联 + +给定未占用的 user data dir,启动时从设置中的起始端口分配一个 loopback CDP 端口,并显示实际端口。给定同目录已由外部浏览器占用,只有 `DevToolsActivePort` 与 `/json/version` 可验证时才显示“外部已关联”;否则拒绝第二次启动。无论哪种外部状态,Chub 都不提供生命周期控制。 diff --git a/docs/08-interaction-checklist.md b/docs/08-interaction-checklist.md index d48d290..7c65c7d 100644 --- a/docs/08-interaction-checklist.md +++ b/docs/08-interaction-checklist.md @@ -2,11 +2,12 @@ | ID | 页面/组件 | 交互 | 状态覆盖 | 优先级 | | --- | --- | --- | --- | --- | -| IX-001 | 实例列表 | 新建、启动、刷新、查看详情 | 加载、空、运行、退出、失败 | P0 | +| IX-001 | 实例列表 | 新建、启动、刷新、查看详情 | 加载、空、托管运行、外部已关联、外部占用、退出、失败 | P0 | | IX-002 | 启动表单 | 浏览器类型、路径、user data dir、URL、参数校验 | 默认、校验错误、提交中、成功 | P0 | | IX-003 | 实例详情 | 优雅关闭、强制终止、重启 | 运行中、关闭中、超时确认、权限错误 | P0 | -| IX-004 | 占用提示 | 查看 PID/来源并重试 | 被占用、身份未知、已释放 | P0 | -| IX-005 | 设置 | 默认路径、日志和数据目录 | 保存成功、路径无效、权限拒绝 | P1 | +| IX-004 | 占用提示 | 查看 PID/来源和关联端口并重试 | 外部已关联、被占用、身份未知、已释放 | P0 | +| IX-005 | 设置 | 默认路径、日志、数据目录和远程调试起始端口 | 保存成功、路径无效、端口无效、权限拒绝 | P1 | +| IX-006 | 本地 CDP 启动 | 从起始端口分配、校验端点、展示实际端口 | 分配中、已关联、端口冲突、端点失效、外部不接管 | P1 | ## 通用规则 @@ -16,3 +17,4 @@ - 关闭完成后焦点回到实例行;失败时保留表单和用户输入。 - 验证 960x640、600x500、100%–200% 缩放、键盘、深色和高对比度回退。 - 不依赖悬停或触控手势完成关键任务。 +- 实例列表使用外层边框、文字状态和图标区分归属;端口为空时显示“—”,外部关联时操作区不显示关闭或重启。 diff --git a/docs/api.md b/docs/api.md index a5a7ee4..f37cd2a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,7 +4,9 @@ MVP 首先提供本地 Go application service 和 CLI;是否增加 loopback HT ## 核心类型 -代码权威类型位于 `internal/domain/browser.go`:`BrowserKind`、`LaunchSpec`、`InstanceStatus`、`InstanceView`、`BrowserEvent` 和稳定错误码。`LaunchSpec.Normalize()` 负责当前已确定的 browser kind、绝对 user data dir,以及非空时的 http/https URL 校验;空 URL 表示打开浏览器默认页。 +代码权威类型位于 `internal/domain/browser.go`:`BrowserKind`、`LaunchSpec`、`InstanceStatus`、`InstanceView`、`BrowserEvent` 和稳定错误码。`LaunchSpec.Normalize()` 负责 browser kind、绝对 user data dir、受控的 loopback remote debugging port,以及非空时的 http/https URL 校验;空 URL 表示打开浏览器默认页。 + +`LaunchSpec` 使用已分配的 `RemoteDebugPort`;端口分配不属于 UI,也不允许由 `ExtraArgs` 覆盖。`InstanceView` 返回实际关联端口、PID、占用来源和归属。外部关联只公开经 `DevToolsActivePort` 与 `/json/version` 验证的端口,不公开 CDP WebSocket URL。 ## Application service @@ -22,7 +24,7 @@ type BrowserManager interface { 平台实现通过实例级 `StopProfile(userDataDir, force)` 执行关闭;force 只对已注册并经过身份绑定的实例生效。 -参数数组由 `internal/platform/browser.BuildArgs` 生成;Chrome/Edge executable 由同包 `Discoverer.Resolve` 解析。二者都不接收 shell 命令行字符串。 +参数数组由 `internal/platform/browser.BuildArgs` 生成;Chrome/Edge executable 由同包 `Discoverer.Resolve` 解析。二者都不接收 shell 命令行字符串。CDP 端点检测和端口分配均通过 platform port 执行,UI 只消费 DTO 结果。 ## CLI 当前合约 @@ -43,7 +45,7 @@ chub events | 事件 | 触发 | 负载 | | --- | --- | --- | | `browser.started` | 新实例完成启动 | InstanceView | -| `browser.status.changed` | 状态变化 | instance_id、status、pid、error_code | +| `browser.status.changed` | 状态变化 | instance_id、status、pid、remote_debug_port、ownership、error_code | | `browser.exited` | 进程退出 | instance_id、exit_code | 事件禁止携带密码、Cookie、Token、完整代理认证信息或原始系统堆栈。 diff --git a/docs/current-state.md b/docs/current-state.md index 4641a54..b8da99c 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -2,12 +2,13 @@ ## 快照 -- 日期:2026-07-22 -- 阶段:Phase 3 真实实例操作(T-301 已完成;T-201 至 T-208 已完成) +- 日期:2026-07-25 +- 阶段:Phase 3 真实实例操作(T-302 进行中;T-301 已完成;T-201 至 T-208 已完成) - 代码:已建立 Go module `chub`、`cmd/chub` 入口、logging 测试基座、浏览器 domain/application 合约、Chrome/Edge 参数/发现模块、启动 registry、Windows 身份/占用检查、优雅关闭、Job Object、真实 Chrome/Edge smoke、JSON 配置存储、启动恢复、CLI JSON 合约、应用内事件总线、UI 状态测试和 Windows smoke 脚本,T-001 至 T-003、T-101 至 T-104、T-201 至 T-208、T-301 已完成 - UI:Gio 双页 Shell 使用左侧“实例/设置”导航;实例列表固定显示实例名称、浏览器类型、用户数据目录、状态和紧凑启动/删除图标。启动通过异步回调接到 Windows 浏览器启动器,并显示启动中、运行中或失败;删除使用确认弹层,只删除 Chub 实例配置而不删除 User Data Dir。新建和删除实例会保存到本地配置;四个设置路径有独立异步可取消搜索,切换页面后输入和任务状态保留;新建实例表单使用 Label、Windows 原生目录选择器和 Chrome/Edge RadioButton;CLI `list/events` 已可用,`start/stop/restart` 等待 BrowserManager adapter - 浏览器核心:设计参考来自 `D:\OPC\shop_helm\internal\platform\chrome`,尚未复制或接入本项目 -- blocker:无;下一步可接入关闭、重启、退出状态回传和 CLI BrowserManager adapter。 +- 当前任务:T-302 正在为托管实例接入 loopback CDP 端口分配、同目录外部浏览器的只读关联、实例列表端口字段和设置中的远程调试起始端口;外部关联不接管进程生命周期。 +- blocker:无;T-302 完成后可继续接入关闭、重启、退出状态回传和 CLI BrowserManager adapter。 ## 当前目录 diff --git a/docs/tasks/T-302.md b/docs/tasks/T-302.md new file mode 100644 index 0000000..45028ea --- /dev/null +++ b/docs/tasks/T-302.md @@ -0,0 +1,43 @@ +--- +id: T-302 +title: 本地 CDP 启动、外部关联与实例端口展示 +phase: 3 +deps: [T-102, T-301] +status: DOING +created: 2026-07-25 +owner: codex +--- + +## 需求与背景 + +Chub 需要为新启动的 Chrome/Edge 分配仅限 loopback 的 remote debugging port;设置中的起始端口留空时使用 `9666`。实例列表需要展示实际关联端口并使用清晰的边框分组。 + +如果其他程序已经使用同一规范化 User Data Dir 启动浏览器,Chub 不得再次启动同目录浏览器。只有该目录中的 `DevToolsActivePort` 与 `127.0.0.1:/json/version` 可验证为同类浏览器时,Chub 才能将其标为“外部已关联”;此关联不赋予关闭、强制关闭、重启或其他 CDP 页面控制权限。 + +## 方案与边界 + +- `LaunchSpec` 将 remote debugging port 作为受控领域字段;`BuildArgs` 固定生成 `--remote-debugging-address=127.0.0.1` 和 `--remote-debugging-port=`,额外参数继续不得覆盖。 +- 平台端从保存的起始端口开始,在最多 100 个端口范围中探测可用候选;启动后等待 `DevToolsActivePort` 并请求 loopback `/json/version`,只有验证成功才把该端口写入运行时结果。端口探测与浏览器绑定之间存在竞争时,不自动杀死或重复启动浏览器。 +- 启动前先合并 Chub launcher registry 与 Windows 外部 profile inspector 结果。目录被外部占用时,只读取该目录的 `DevToolsActivePort`,不扫描全系统 Chrome/Edge 进程或端口。 +- 外部端点验证失败、端口文件过期、权限不足或浏览器类型不匹配时,保守报告外部/未知占用并拒绝启动;不得借此接管外部 PID。 +- Gio 设置增加带 Label 和帮助文本的“远程调试起始端口”数字输入;空值在保存时归一化为 `9666`,有效值为 `1024` 至 `65535`。 +- Gio 实例列表增加“调试端口”字段及 1dp 外层边框、圆角和表头分隔;端口值为实际关联端口、检测中或 `—`。行级启动结果沿现有异步 channel 回到 UI 线程,避免阻塞 frame。 +- 托管运行、外部已关联、外部占用和启动失败使用不同文字状态;外部已关联只保留“重新检测”语义,不成为可关闭/重启的托管实例。 + +## 验收要点 + +- 启动 Chrome/Edge 时实际追加 loopback remote debugging 参数,默认从 `9666` 选择;首个端口占用时尝试后续端口,并在实例列表显示已验证的实际端口。 +- 同一规范化 User Data Dir 的外部 Chrome/Edge 若存在有效 `DevToolsActivePort`,启动操作不创建新进程,列表显示“外部已关联”、PID、来源和端口。 +- 外部浏览器未启用 CDP 或无法验证时,不创建新进程,列表显示外部/未知占用与可恢复说明。 +- 端口输入可保存、恢复、校验和取消;空值恢复为 `9666`,非法端口在字段附近显示错误。 +- 实例列表外框、表头和紧凑端口列在默认窗口宽度下不挤压启动/删除图标;端口为空显示 `—`。 +- 外部关联没有关闭、重启、强制终止或全局按进程名操作;CDP WebSocket URL 不进入配置、日志、事件或 UI。 +- `go test ./...`、`go vet ./...`、Windows build、真实 Chrome/Edge CDP/外部关联 smoke 和既有 Windows smoke 通过。 + +## 执行记录 + +- 状态:DOING +- 变更:已建立需求、架构、API、交互、原型和任务契约;待实现。 +- 验证:文档待实现验证。 +- 阻塞:无。 +- 残余风险:Chrome 默认用户目录可能忽略 remote debugging 开关;端口预探测存在不可消除的短暂竞争,最终以端点验证为准。 diff --git a/docs/ui/browser-manager.html b/docs/ui/browser-manager.html index fc89b43..d7dff71 100644 --- a/docs/ui/browser-manager.html +++ b/docs/ui/browser-manager.html @@ -117,6 +117,7 @@ .status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; } .status.running { color: var(--success); background: var(--success-soft); } .status.starting { color: var(--accent-strong); background: var(--accent-soft); } + .status.associated { color: var(--warning); background: var(--warning-soft); } .status.occupied { color: var(--warning); background: var(--warning-soft); } .status.exited { color: var(--muted); background: var(--surface-3); } .row-actions { display: flex; justify-content: flex-end; gap: 6px; opacity: .7; } @@ -237,8 +238,8 @@
-
-
浏览器实例列表
实例名称浏览器类型用户数据目录状态启动
没有匹配的实例尝试清除筛选,或新建一个浏览器实例。
+
+
浏览器实例列表
实例名称浏览器类型用户数据目录调试端口状态操作
没有匹配的实例尝试清除筛选,或新建一个浏览器实例。
@@ -256,7 +257,7 @@
- + @@ -269,10 +270,10 @@