fix: prevent premature completion notifications and Windows console popups - #183
Merged
Merged
Conversation
`Stop` fires at the end of every turn, not at task completion, so the guard
that suppresses the completion toast while work is still in flight is what
keeps that notification honest. It reads `background_tasks`, but the counter
only accepted entries whose type was `subagent` — and Claude Code reports a
backgrounded Bash command as `local_bash`. The most common shape (start a
long command, turn ends, command still running) therefore counted zero: the
guard stayed off and the toast claimed the turn was done while the command
was still running.
Count every entry the field carries. It is documented as in-flight work
("Empty array when nothing is in flight"), so the filter belongs on the
status, not on the type. Idle `in_process_teammate` entries stay excluded —
they keep reporting `status: "running"` after they finish
(anthropics/claude-code#85955) — matching Claude Code's own
`status === "running" && !isIdle` predicate.
Tests: three cases pin the counting (every in-flight type, an empty array
leaving the turn done, an idle teammate not holding it open). The first one
counted zero before this change.
Pebrel is a `windows_subsystem = "windows"` process, so it has no console to hand to a child, and Windows allocates a new one for every console program we spawn. When the default terminal application is Windows Terminal that is not a hidden flash — it is a whole window on screen. Measured on the test binary, which has no console for the same reason: one full `cargo test` run popped 86 windows, and the `runtime_api` module alone popped 7. Most spawn sites already carried `CREATE_NO_WINDOW`, but each spelled it itself — `0x0800_0000` in some places, the named constant in others, a private `hidden_command` in one module. Three sites had no flag at all: `pane.exec` (`runtime_exec::configure_process_group` was a no-op on Windows), the WSL path of drag-and-drop (`path_drop::wsl_paths`), and the `ssh -G` probe behind the `pebrel ssh` entry point. Route every console child through one helper, `platform::process`: - `hidden_command` for the common case; - `hidden_command_with` when the caller needs extra creation flags (the daemon's `CREATE_NEW_PROCESS_GROUP`) — `creation_flags` replaces rather than ORs, so the helper owns the `CREATE_NO_WINDOW` bit; - a `CREATE_NO_WINDOW` constant for `Command` types that are not `std::process::Command` (the tokio proxy command). No raw literals left. Test helpers are included: the test binary is console-less too, so its git calls popped windows as well (7 during one `runtime_api` run, 0 after). Deliberately left alone, and now documented as such: the interactive `pebrel ssh <host>` session (it inherits the parent console through `AttachConsole`), the update installer wizard, and `notepad`/`explorer`/ `open`, which exist to be visible.
The screen watchdog downgrades `Working -> Done` after the pane's screen has been static for 5 ticks (it samples at 1 Hz), and that transition used to notify unconditionally. But a static screen is not evidence that the agent stopped: Claude Code prints nothing while it thinks, and a long command such as a full build writes nothing for minutes. The result was a "回合完成" toast while the task was still running. The screen is only a fallback for when the hook never arrives. When hooks are live, the agent CLI's own `TurnDone` is the authoritative terminal state, so keep the screen-derived transition (the sidebar dot still updates) but stay silent about it. Clients without hooks keep the old behaviour, where the screen really is the only evidence. This is the notification half of the problem. The other half is that `active_background_tasks` never fires for Claude Code — its `Stop` payload carries no `background_tasks` field — so the guard at the top of the `TurnDone` arm is dead code for that CLI. Left as-is for now.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Result / 用户结果
修复现有通知误报和 Windows 后台命令弹窗,保留原作者提交与 PR 历史:
Design / 设计边界
只处理 bug 修复。#130、#131、#133、#144、#145 及其功能和翻译扩展均不纳入。没有新增设置、工作流、依赖或持久化格式。
合并冲突保留 main 的 SSH 显式配置路径与现有 HTTP 更新客户端。屏幕状态自愈、无 hook 会话的通知回退和需要交互的进程保持现有语义。源码注释已纠正:看门狗连续识别 Idle 界面,并非仅检测屏幕静默。
采用 merge commit 保留 #142/#143 的原始 head 为祖先,合并后核验原 PR 的远端 merged 状态。
Evidence / 验证依据
Required Review / 必须确认