编程代理的提醒可能判断正确,却出现在错误的时刻。Claude Code 刚结束一轮,而终端正处于前台,全屏提醒反而会盖住用户正在读的结果。但“终端在前台就不提醒”也不对,因为等待用户的可能是另一个窗口里的会话。
判断条件必须收窄到一个问题:当前前台应用是不是这个会话对应 CLI 的宿主? Agent Island v1.7.1 在 macOS 与 Windows 上都做了这层判断。答案为真时暂存提醒;焦点切换后,如果该轮仍需用户处理,再只发送一次。
保留会话身份
实现从等待中的线程取出工作目录,找到工作目录匹配的 claude 或 codex 进程,再沿父进程链寻找前台应用。Windows 还会匹配承载 CLI 的 node 与 bun。两端的父进程遍历都限制在 24 层以内。
等待中的线程
-> 工作目录
-> 匹配的 CLI 进程
-> 父进程链
-> 前台应用进程
暂存不等于已提醒
被压住的提醒不会被标成已送达。它以 provider、session 与 turn 组成的 delivery key 暂存在内存里。焦点变化时,系统重新检查:提醒开关是否仍开启、该轮是否仍在 needs-you 集合里、是否已经确认或送达。
如果新的 transcript 扫描发现用户已经回复,暂存项会被删除,不会在之后突然弹出一条过期提醒。
使用事件,而不是轮询前台窗口
正式版在发送前已有一秒确认窗口,新的会话写入可以取消已经无效的提醒。前台判断再增加一个事件边界:macOS 监听应用激活,Windows 使用 EVENT_SYSTEM_FOREGROUND。只有切换焦点时才重新核验,不需要常驻轮询。
无法解析时保持原行为
tmux、容器、守护进程或权限限制可能让父进程关系无法还原。此时解析器返回 false,提醒照常出现。多弹一次比静默漏掉真正需要处理的交接更可控。
路径也要标准化。macOS 的 /tmp 与 /private/tmp 可能指向同一位置;Windows 需要处理大小写和分隔符差异,还要用进程创建时间阻止 PID 复用造成错误父链。
应该覆盖的测试
- 准确会话位于前台时暂存。
- 同一应用中的另一个会话位于前台时仍提醒。
- 未回复就切走时只提醒一次。
- 切走前已经回复时丢弃暂存项。
- 无法解析宿主时保持提醒。
- 多个子任务同时结束时先合并提醒风暴。
- 应用启动时不重放历史等待状态。
边界
前台匹配不代表用户真的阅读了结果,只能证明对应 CLI 的宿主应用当前可见。这套设计只是利用一个范围很窄、随时可撤销的条件减少打扰,并不做注意力追踪。
本文描述的行为已经包含在 Agent Island v1.7.1,macOS 与 Windows 实现都可以在公开仓库中检查。
