feat(adopt): /adopt 会话选择卡片改用 relay 同款 V2 展示(可搜索/分页/信息全) - #703
feat(adopt): /adopt 会话选择卡片改用 relay 同款 V2 展示(可搜索/分页/信息全)#703xiaoxueSunn wants to merge 3 commits into
Conversation
## 如何发现 用户在新群 /adopt 时反馈「根本认不出该 load 哪一个」:卡片是两个 select_static 下拉,历史会话选项只拼「首句 prompt · 项目 · 时间」,而 codex 那几条 rollout 首句都以「你是一个只读诊断子 agent…」开头且被截到 40 字,前缀几乎一样 → 完全无法区分;也看不到 CLI 类型 / cwd / 会话 ID。 ## 改了什么 - buildAdoptSelectCard 从两个 select_static 下拉重写为 relay 同款 V2 卡片: 搜索框 + interactive_container 卡片列表(≤5/页)+ 分页 + 选中高亮 + 确认按钮。 - 运行中 / 历史两类源合并进同一个可搜索列表,用「来源」标签区分,选中/ 确认按来源分派 startAdoptSession(活进程)或 startResumeImportSession(磁盘)。 - 每条卡片展示:来源 / CLI / 路径(cwd) / 会话 ID / 时间(运行中=已运行, 历史=最近活动)。搜索覆盖标题/项目/cwd/CLI/会话 ID,知道 id 可直接搜到。 - 合成选择键 adoptLiveKey(live:tmux:<target>:<pid> / live:zellij:… / resume:<cliSessionId>),确定性可复现,re-render 重新发现也能对回。 - 新增 services/adopt-picker.ts:首次渲染快照候选并按 root 消息缓存(5min TTL), 搜索/翻页复用缓存、不再每次 re-shell-out 到 tmux;确认时才重新发现校验活进程 (走 discoverAdoptableSessionByTarget 快路径,守住飞书 3s 回调预算)。 - resume 上限保持 20(纯展示改造,非扩容);命中上限时卡片给出提示指向搜索。 - 卡片动作块移到 card-handler 的通用 `if (value?.action)` 兜底之前,否则 adopt_confirm 会被兜底吞掉。 ## 测试 - test/card-builder.test.ts:重写 buildAdoptSelectCard 用例(live/resume 卡片、 确认按钮门控、搜索过滤、分页、截断提示),+ 全 146 通过。 - test/session-adopt.test.ts:adopt_select 下拉用例改为 adopt_confirm,11 通过。 - 新增 test/adopt-picker-cache.test.ts:缓存 store/TTL/clear,4 通过。 - adopt-route / relay-picker / card-handler-relay-pickup / card-integration 回归通过。 - 全量 unit:仅 11 个失败,均为 pre-existing(*-cli 需构建 dist、grant-partial 在 pristine master 同样失败),与本改动无关。 Co-Authored-By: Claude <noreply@anthropic.com>
真机渲染发现:ResumableSession 不带 cliId,历史条目 CLI 列显示"—"。 resume 只会提供 bot 自己那种 CLI,调用方本就知道,于是把 bot 的 cliId 透传进 buildAdoptEntries / buildAdoptSelectCard,历史行显示「CLI: Codex」。 Co-Authored-By: Claude <noreply@anthropic.com>
6fb49a0 to
4124e3e
Compare
首审 (Claude) — 🔴 1 P1 blocker整体质量高:V2 卡片镜像 🔴 P1 — zellij 确认路径把
|
|
To use Codex here, create a Codex account and connect to github. |
接首审 review。修两处: 1) 🔴 P1 — adoptLiveKey 对 zellij 生成的 key 含 cliPid,确认路径只按 `adoptLiveKey(fresh) === entryKey` 匹配、无忽略 pid 的兜底,回退了 57dcbeb「点击候选改按 (session,paneId) 匹配」的专门修复:zellij pane 的 CLI pid 会在「渲染→确认」窗口内漂移(wrapper⇄native 塌缩 / re-fork), pid 进 key 导致确认时重新发现算出的 key 与卡片 entryKey 不一致 → find 落空 → 误报「目标 CLI 会话已退出」。那个 3 次重试救不了(每次稳定算出同 一个 pid 不同的坏 key,只是重复 miss)。 修:zellij 分支去掉 pid → `live:zellij:${session}/${paneId}`,(session, paneId) 已唯一标识 pane。tmux/herdr key 不变(tmux 本就含 pid,确认快路径 要解析尾部 pid;herdr key 无 pid)。加显式注释防再次塞回。 2) 🟡 P3 — 无匹配分支把用户原始 searchQuery 未转义插进 markdown 元素, `` 会渲染成图片(外链请求=追踪信标 / SSRF)。改走 escapeMd 中和 [ ] 等。(buildRelayPickerCard 同样回显 query 有同样隐患,单独跟踪。) 测试: - card-builder.test:新增 adoptLiveKey 不变量(zellij 同 (session,paneId) 异 pid → 同 key;tmux 保持 pid 敏感)+ 无匹配 query 转义用例。 变异验证:临时把 pid 塞回 zellij key,zellij 不变量用例即红。 - session-adopt.test:修正 adoptLiveKey mock 的 zellij 分支去 pid,与真实 实现一致。 - 隔离单跑 164 全绿;adopt/relay/card/cli-send-dispatch 全量回归 278 全绿; pnpm build 通过。
代作者修复(申晗授权)— head
|
deepcoldy
left a comment
There was a problem hiding this comment.
Codex 复审 — ✅ 通过(head 611c78da7)
本轮未发现新的阻塞项,首审的 P1 / P3 均已正确收口。
- P1 zellij key:独立回看了
57dcbebbb及当前完整链路。卡片确认严格执行adoptLiveKey(fresh) === entryKey;zellij 发现会从当前进程树重新解析cliPid,因此 snapshot PID 与 fresh PID 不同是合法窗口。旧写法会机械地产生不同 key,新写法只取(zellijSession, zellijPaneId),两侧稳定对齐;tmux 仍保留含 PID 的既有 key 与单 pane 快路径,herdr 语义未变。本机目前没有活跃可接管的 zellij session,因此未人为创建/扰动 live pane,但代码路径、历史修复和 PID 变异用例三者证据一致。 - P3 query 转义:
empty_filtered现经escapeMd转义[]、反斜杠、反引号和尖括号,不再能形成图片/链接;测试确实进入“有候选但过滤为空”分支,不是空列表短路假绿。 - 覆盖取舍:接受当前的
adoptLiveKey纯函数不变量作为本次 P1 的回归守卫;把 PID 加回会直接使该用例失败。为补一个 zellij confirm handler 用例而引入resetModules/静态依赖重构,收益不足以要求本 PR 扩面。现有 confirm 失效路径与 adopt/relay/card 回归也已通过。 - relay 同类隐患:是既有路径,建议单独跟踪并用小 PR 修复,不要求 #703 顺手扩面。
本地实际验证:
pnpm build✅pnpm vitest run test/card-builder.test.ts test/adopt-picker-cache.test.ts test/session-adopt.test.ts test/adopt-route.test.ts test/relay-picker.test.ts test/card-handler-relay-pickup.test.ts test/card-integration.test.ts test/cli-send-dispatch.test.ts→ 8 files / 278 tests 全绿 ✅git diff --check✅- 与当前
upstream/mastermerge-tree 无冲突;GitHub 当前未配置/未上报 CI checks。
影响面核对:改动限于飞书 /adopt picker 的候选采集、V2 卡片与 callback;覆盖 tmux / zellij / herdr、live / resume 和所有 bot CLI 的共同入口,未改 worker、PTY/Tmux backend 或其它 IM。保留“需真机飞书交互后再发布”的既有待验证项。
批准仅代表复审通过;按约定不执行合并,等待申晗最终确认。
如何发现
用户在新群
/adopt时反馈「根本认不出该 load 哪一个」。当前卡片是两个 select_static 下拉,历史会话选项只拼「首句 prompt · 项目 · 时间」,而 codex 的 rollout 首句都以「你是一个只读诊断子 agent…」开头且被截到 40 字 → 前缀几乎一样,完全无法区分;也看不到 CLI 类型 / cwd / 会话 ID。用户要求做成接力(relay)那种 V2 卡片,信息多一点。用户看到什么
/adopt打开选择卡改了什么
buildAdoptSelectCard从两个select_static下拉重写为 relay 同款 V2 卡片:搜索框 +interactive_container卡片列表(≤5/页)+ 分页 + 选中高亮 + 确认按钮。startAdoptSession或startResumeImportSession。adoptLiveKey(live:tmux:<target>:<pid>/live:zellij:…/resume:<cliSessionId>),确定性可复现,re-render 重新发现也能对回。services/adopt-picker.ts:首次渲染快照候选并按 root 消息缓存(5min TTL),搜索/翻页复用缓存、不再每次 re-shell-out 到 tmux;确认时才重新发现校验活进程(走discoverAdoptableSessionByTarget快路径,守住飞书 3s 回调预算)。if (value?.action)兜底之前,否则adopt_confirm会被兜底吞掉。观察到的修复结果(测试)
test/card-builder.test.ts:重写buildAdoptSelectCard用例(live/resume 卡片、确认按钮门控、搜索过滤、分页、截断提示)——146 通过。test/session-adopt.test.ts:adopt_select下拉用例改为adopt_confirm——11 通过。test/adopt-picker-cache.test.ts:缓存 store / TTL / clear——4 通过。仍未验证什么
/adopt交互pnpm build全量构建*-cli/workflow-c0需构建 dist;card-handler-grant-partial在 pristine master 同样失败🤖 Generated with Claude Code