Skip to content

fix(adapter): cursor/copilot/kimi 恢复缺 cliSessionId 时新起会话,杜绝 --continue 串用兄弟会话上下文 - #927

Open
ITcathyh wants to merge 4 commits into
deepcoldy:masterfrom
ITcathyh:fix-topic-context-leak
Open

fix(adapter): cursor/copilot/kimi 恢复缺 cliSessionId 时新起会话,杜绝 --continue 串用兄弟会话上下文#927
ITcathyh wants to merge 4 commits into
deepcoldy:masterfrom
ITcathyh:fix-topic-context-leak

Conversation

@ITcathyh

Copy link
Copy Markdown
Contributor

优先级:P1

根因

cursor、copilot、kimi 以及遗漏的 grok 在 worker 恢复但缺少精确 cliSessionId 时回退到 --continue。该参数恢复的是 CLI 全局最近会话;同一 bot 的多个 botmux 会话共享 CLI 配置目录,因此最近活跃的兄弟会话可能被错误加载,造成话题群、群聊或私聊之间的上下文泄漏。

改动

  • cursor、copilot、kimi、grok 缺少精确 session id 时不再使用 --continue,而是新建干净会话;有 id 时继续精确恢复。
  • cursor 在缺 id 新起会话时重新启用 session 观测和持久化,确保捕获新的 chat id,避免后续恢复始终缺 id。
  • 在 copilot/kimi 适配器中明确记录当前缺少 session id 捕获能力,因此安全策略会牺牲跨 worker 重启的上下文连续性。
  • 同步清理 cursor 适配器中已失效的 --continue 注释。

影响面

仅影响四个 CLI 在 worker 重启且 cliSessionId 缺失的恢复路径;正常新建和有精确 id 的恢复不变。安全取舍是宁可丢失该轮跨重启上下文,也不加载其他 botmux 会话。

验证

  • cli-adapters 362/362、cursor-resume-policy 5/5、cursor-transcript 22/22、event-dispatcher 294/294、session-resume 39/39、write-input 136/136 均通过。
  • 回归覆盖四个适配器缺 id 不使用 --continue、有 id 精确恢复、fresh 启动不受影响,以及 cursor 缺 id 时恢复观测。
  • pnpm build 通过。

@ITcathyh
ITcathyh requested a review from deepcoldy as a code owner August 18, 2026 14:35

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99598bed53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// topic group's context leaking into a private chat. Losing this
// session's context is the lesser evil; matches reasonix/antigravity,
// which reject `--continue` for the same "most recent is racy" reason.
return base;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate the fresh fallback to worker state

When a restored Cursor session lacks cliSessionId (and likewise for the changed Copilot/Kimi paths), this returns fresh-launch arguments while worker.ts leaves effectiveResume=true; because these adapters have no failing checkResumeTargetExists, the worker's fresh-demotion branch and its user-visible “历史会话无法恢复” warning never run. Copilot and Kimi normally lack ID capture, so routine crash, idle-recovery, or deployment restarts silently discard their conversation and deliver the next prompt to a blank context while the user is told nothing. Route this no-ID case through the worker's fresh fallback, or otherwise set the effective mode and emit the existing warning.

AGENTS.md reference: AGENTS.md:L64-L68

Useful? React with 👍 / 👎.

@deepcoldy

Copy link
Copy Markdown
Owner

自动化初步评审发现一处建议在合入前补齐的用户态语义,最终以维护者审阅为准。

本 PR 在 Copilot/Kimi 缺少 cliSessionId 时改为返回无 resume 参数、实际启动干净会话;由于这两个适配器目前从不捕获 cliSessionId,idle 回收、崩溃后的冷启动、关闭后点击恢复等路径都会命中该行为。安全取舍本身正确,但当前上层仍把它描述成“历史上下文已恢复”:

  • closed-session-card 无精确命令时显示“点击「恢复会话」继续”以及“可在飞书内 resume”(card.body.click_resume_only / card.body.cli_no_cli_resume);
  • 点击恢复后的回执为“会话已恢复,发条消息继续……”(card.action.resume_success);
  • 自动冷恢复时 adapter 静默省略 resume 参数,worker 不会走现有 fallBackToFresh 的“历史无法恢复,已新起干净会话”通知。

因此用户可能在以为旧上下文仍在的情况下直接发送依赖历史的后续指令。建议让“缺精确 id → fresh”成为 worker/上层可观察的结果(例如复用现有 fresh-demotion 通知),并让关闭卡片/恢复回执明确区分“逻辑路由重新激活”与“CLI 历史上下文已恢复”;同时补 Copilot/Kimi 缺 id 的卡片与冷恢复通知测试。

其余复核结果:自动 spawn 统一走 cliAdapter.buildArgs,未发现其它全局-latest 恢复入口;Cursor 捕获沿 launcher/真实 PID → 该进程打开的 store.db,未发现重新引入兄弟会话选择;与当前 master 的生产代码自动合并正确,唯一测试冲突需同时保留 --trust 断言并改为 not --continue

huangyuhang.edu and others added 4 commits August 19, 2026 08:47
…e 串用兄弟会话上下文

话题群会话 A 的上下文偶发串到私聊会话 B。根因:cursor / copilot / kimi
三个适配器在 resume=true 但 resumeSessionId 缺失(worker 重启时 cliSessionId
从未持久化,如崩溃早于捕获 / 观测失败)时回退到 `--continue`,而
`--continue` 恢复的是「全局最近会话」——同一 bot 的多个 botmux 会话共享
同一个 CLI 配置目录,于是 B 的 worker 可能把 A 的会话加载进自己的上下文,
B 的回复里出现只属于 A 的句子。「偶现」正对应「worker 重启 + cliSessionId
缺失 + 兄弟会话最近活跃」三者同时成立的竞态窗口。

修法:移除 `--continue` 兜底,缺 id 时新起干净会话,宁可丢本轮上下文也不
串用兄弟会话。与 reasonix / antigravity 已确立的模式对齐(两者注释明确
拒绝 `--continue`:"most recent is racy when multiple botmux sessions
run in parallel")。claude-code / codex / grok 等适配器本就按精确 id
恢复,不受影响。

影响面:仅 cursor / copilot / kimi 三个 CLI 适配器的「worker 重启且
cliSessionId 未持久化」恢复路径;话题群 / 群聊 / 私聊三种会话类型的
正常新建与精确恢复(有 cliSessionId)行为不变。

测试:cli-adapters 361/361、cursor-resume-policy 5/5、event-dispatcher
294/294、session-resume 39/39、write-input 136/136 均通过;新增 9 条
回归用例覆盖三适配器「缺 id 不 --continue / 有 id 精确 --resume /
fresh 不受影响」。

Co-Authored-By: Claude <noreply@anthropic.com>
…t/kimi 恢复回退

交叉审核三项修复:

1. grok 漏网:grok.ts buildArgs resume 路径在 resumeSessionId 与 sessionId
   均缺失时仍回退 --continue(恢复全局最近会话,跨 botmux 会话共享),与
   cursor/copilot/kimi 同款漏洞。移除 --continue,缺 id 时新起。补回归测试。

2. cursor sticky 缺 id:cursor-resume-policy 旧策略为 --continue 时代设计,
   resume=true && !cliSessionId 时关闭观测。适配器移除 --continue 后该场景
   实为新起会话,应恢复观测以捕获新 chat id,否则 id 永不捕获、下次重启仍
   缺 id。更新策略与测试:缺 id 新起时观测+持久化。

3. copilot/kimi 恢复能力回退显式说明:两者无任何 cliSessionId 捕获机制
   (无 bridge、无 observation、无 output capture),「缺 id」是常态。
   移除 --continue 后每次 worker 重启都新起会话,丧失跨重启恢复能力。
   在代码注释中写明该回退与后续 fast-follow(补 session id 捕获)。

测试:cli-adapters 362/362、cursor-resume-policy 5/5、cursor-transcript
22/22、event-dispatcher 294/294、session-resume 39/39、write-input
136/136 均通过;pnpm build 通过。

Co-Authored-By: Claude <noreply@anthropic.com>
评审指出:cursor/copilot/kimi 缺 cliSessionId 时 buildArgs 改为新起干净会话
是对的,但 worker 仍保留 effectiveResume=true,fresh-demotion 分支不触发
(这些适配器没有 failing checkResumeTargetExists),冷恢复/崩溃重启/空闲回收
静默丢上下文,而关闭卡片显示「点击恢复会话继续」、恢复回执说「会话已恢复」,
用户会在以为旧上下文仍在的情况下发依赖历史的指令。

- worker: 新增 Tier 0 回退——适配器声明 resumeRequiresCliSessionId 且无
  cliSessionId 时走现有 fallBackToFresh 分支(effectiveResume=false +
  user_notify「历史会话无法恢复,已新起干净会话」),缺 id 新起成为可观察
  结果;reattach 活 pane 不触发(无上下文丢失)
- cursor/copilot/kimi 声明 resumeRequiresCliSessionId(buildArgs 缺 id 即
  新起,无 --continue 回退);claude-code/grok(sessionId 即可恢复)与
  gemini(完全忽略 resume)不声明,行为不变
- 关闭卡片:缺精确 id 时文案改为「重新激活话题路由 + 新起干净会话」,不再
  暗示历史可恢复(card.body.resume_starts_fresh);有精确恢复命令时不变
- 恢复回执:区分「话题路由已重新激活」与「会话已恢复」
  (card.action.resume_success_fresh)
- 新增 services/resume-fresh-policy 统一判定,卡片/回执共用同一语义
- 测试:适配器能力位断言、卡片文案、恢复回执行为测试(copilot 缺 id/带 id、
  claude-code 对照)、worker 降级与卡片文案 source-lock

Co-Authored-By: Claude <noreply@anthropic.com>
@ITcathyh
ITcathyh force-pushed the fix-topic-context-leak branch from 99598be to 26a52d5 Compare August 19, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants