Skip to content

fix: resolve 60s terminal_ready timeout on 'cli-box start' (headless + dev-mode) - #55

Merged
Shadow-Azure merged 4 commits into
mainfrom
fix/daemon-headless-terminal-ready
Jul 22, 2026
Merged

fix: resolve 60s terminal_ready timeout on 'cli-box start' (headless + dev-mode)#55
Shadow-Azure merged 4 commits into
mainfrom
fix/daemon-headless-terminal-ready

Conversation

@Shadow-Azure

Copy link
Copy Markdown
Owner

Problem

cli-box start blocked for the full 60s terminal-readiness timeout in two situations, then proceeded anyway (the sandbox was actually ready within milliseconds):

  1. Headless (Linux / cloud, no Electron): the daemon runs with --headless, so no Electron renderer ever connects the screenshot WebSocket. terminal_ready_sandboxes is populated only by a renderer-sent terminal_ready message, which never arrives — so the CLI's readiness poll always times out at 60s. (This is the known "TUI start 60s timeout" on the Aliyun test host.)
  2. Dev mode (macOS repo checkout): find_electron_binary() looked for Contents/MacOS/cli-box in the dev dist bundle, but the bundle's launcher binary is named CLI Box. Electron failed to launch ("No such file or directory"), no renderer connected, same 60s timeout.

Solution

Headless terminal_ready timeout — 8615cf2

In readyz_handler (crates/cli-box-core/src/daemon/mod.rs), when DaemonState.headless is true, derive terminal_ready from the queried sandbox's pty_pid existence instead of the renderer-populated terminal_ready_sandboxes set. PTYs are spawned synchronously at sandbox creation, so this is race-free. The CLI gates solely on terminal_ready (status/renderer_connected are #[allow(dead_code)]), so no protocol or CLI change is needed. The non-headless (renderer-driven) path is unchanged.

Dev-mode Electron binary name — d8ec07a

In find_electron_binary() (crates/cli-box-cli/src/main.rs), corrected the two dev dist paths (dist/electron/mac-arm64, dist/electron/mac) from Contents/MacOS/cli-boxContents/MacOS/CLI Box, matching the release path, both cached/downloaded paths, and the actual on-disk binary. The legacy Tauri cmd_start (a different app, #[allow(dead_code)]) is left unchanged.

Test Plan

  • cargo test -p cli-box-core --test daemon_integration — 16/16 pass, incl. 2 new: readyz_terminal_ready_in_headless_mode (headless sb→ready, unknown→not-ready) and readyz_terminal_ready_uses_renderer_set_when_not_headless (regression guard for the renderer path)
  • TDD: headless test failed first (terminal_ready false), passed after the fix
  • cargo clippy --all-targets -- -D warnings clean; cargo fmt --all -- --check clean
  • Per-task review (spec ✅ + quality Approved) + final whole-branch review (Ready to merge: Yes)
  • Aliyun headless host: cli-box start returns within ~1s instead of 60s (definitive headless verification)
  • Dev-mode: rebuild + re-run e2e-compound-start-screenshot (was failing on the name bug) to confirm green

🤖 Generated with Claude Code

ZN-Ice and others added 4 commits July 20, 2026 18:47
In headless mode the readiness signal path (renderer -> screenshot WS ->
terminal_ready_sandboxes) never fires, so 'cli-box start' always hits the
60s terminal readiness timeout. Spec proposes the daemon answer readiness
from PTY state in headless mode.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
In headless mode no renderer connects the screenshot WebSocket, so
terminal_ready_sandboxes was never populated and 'cli-box start' always
hit the 60s readiness timeout. Derive terminal_ready from the sandbox's
PTY existence in headless mode; non-headless path unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
The dev dist paths (dist/electron/mac-arm64 and mac) looked for
Contents/MacOS/cli-box, but the built bundle's launcher binary is named
"CLI Box" — matching the release path and both cached/downloaded paths,
and the actual file on disk. In dev mode this made Electron fail to
launch ('No such file or directory'), so no renderer connected and
'cli-box start' hit the 60s terminal_ready timeout on the non-headless
path. Align the dev paths with the other four.

The legacy Tauri cmd_start (line 340) is a different app and is left
unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔒 门禁检查结果

检查项 状态
Rust 格式化 ✅ success
Rust Clippy ✅ success
Rust 测试 & 覆盖率 ✅ success
前端测试 & 覆盖率 ✅ success
Playwright E2E ✅ success
统一测试 (test.sh) ✅ success
安全检查 ✅ success
发布模拟验证 ✅ success
升级流程测试 ✅ success
cli-box-skill 单元测试 ✅ success

Rust 测试覆盖率

指标 覆盖率
行覆盖率 67.3%
分支覆盖率 0.0%
模块 行覆盖率
crates.cli-box-core.src.process ███████████░░░░░░░░░ 57.7%
crates.cli-box-core.src.automation ███████████░░░░░░░░░ 58.3%
crates.cli-box-core.src ███████████░░░░░░░░░ 55.3%
crates.cli-box-core.src.daemon ██████████░░░░░░░░░░ 52.6%
crates.cli-box-core.src.sandbox ███████████████████░ 98.8%
crates.cli-box-core.src.capture ████████████████░░░░ 84.2%
crates.cli-box-core.src.server █████████████████░░░ 87.7%
crates.cli-box-core.src.instance ███████████████████░ 99.1%

详细报告见 Rust 覆盖率 artifact

前端测试覆盖率

指标 覆盖率
行覆盖率 ████████████████░░░░ 78.0%
分支覆盖率 70.4%
函数覆盖率 74.2%
语句覆盖率 77.5%
文件 行覆盖率
src/tests/mocks/websocket.ts ██████████████████░░ 88.0%
src/tests/mocks/xterm.ts ████████████████████ 100.0%
src/main/daemon-bridge.ts ████████░░░░░░░░░░░░ 40.0%
src/renderer/api.ts ██████████████░░░░░░ 68.2%
src/renderer/screenshotSync.ts ████████████████████ 100.0%
src/renderer/scrollback.ts ██████████████████░░ 88.9%
src/renderer/tabState.ts ████████████████████ 100.0%
src/renderer/terminalBuffer.ts ████████████████████ 100.0%

详细报告见前端覆盖率 artifact

✅ 所有检查通过,可以合入

点击 Squash and merge 合并此PR

@Shadow-Azure
Shadow-Azure merged commit ec51f7d into main Jul 22, 2026
14 checks passed
@Shadow-Azure Shadow-Azure mentioned this pull request Jul 22, 2026
4 tasks
Shadow-Azure added a commit that referenced this pull request Jul 22, 2026
Patch release for the headless terminal_ready timeout fix (#55): 'cli-box start' waited the full 60s for the renderer to connect in headless and dev mode. Resyncs Cargo.lock.

Co-authored-by: ZN-Ice <zn-ice@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
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.

1 participant