Skip to content

feat(cli): add loading spinner for argue run and argue act - #61

Merged
onevcat merged 2 commits into
masterfrom
feat/run-act-spinner
May 11, 2026
Merged

onevcat merged 2 commits into
masterfrom
feat/run-act-spinner

Conversation

@onevcat

@onevcat onevcat commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #60. Fixes the "is it even running?" silence in argue act and the
similar quiet gaps between rounds in argue run by adding a Braille
spinner ⣾⣽⣻⢿⡿⣟⣯⣷ to stderr.

  • argue act: spins from dispatch until awaitResult settles, so
    the long opaque wait now shows visible progress.
  • argue run: the output formatter now owns a spinner. After each
    *Dispatched event it starts; each ParticipantResponded /
    ParticipantEliminated removes that id from a per-round waiting set
    and either restarts with the updated label or stays idle until the
    next event. Stops on RoundCompleted / ReportCompleted /
    ActionCompleted / ActionFailed and in runCompleted / runFailed.
  • Spinner writes to stderr so argue act's stdout (the action response)
    stays clean for piping. Non-TTY → one breadcrumb line, no animation.
    NO_COLOR and --no-color are honored.

Side fix: unref'd timers

While testing against the mock provider I hit
Warning: Detected unsettled top-level await plus spinner stuck on the
first frame. Two timer.unref() calls combined with the mock's own
unref'd setTimeout left the event loop with zero ref'd handles, so it
exited before the awaited promise could settle. Removed:

  • spinner.ts setInterval — keeping it ref'd means the animation
    actually renders for the full wait
  • runtime/delegate.ts withTimeout setTimeout — clearTimeout runs on
    both settle paths so this is safe; the previous unref masked the issue
    only when real network sockets were holding the event loop open

Test plan

  • npm run format:check, npm run lint, npm run check
  • npm run ci (argue 52 + cli 217 + viewer 78 = 347 tests pass)
  • New spinner unit tests (frames, cursor, clear-line, non-TTY
    fallback, idempotent start/stop, color toggle, setLabel, isActive)
  • New output integration tests (RoundDispatched → label updates →
    RoundCompleted stops; ActionDispatchedActionCompleted stops)
  • Manual end-to-end against the mock provider in a real TTY: spinner
    rotates through full waits, clears cleanly, stdout output unaffected
  • Manual non-TTY (piped): single breadcrumb line, no animation

The act command had no output between dispatch and awaitResult, leaving
users unsure whether anything was running. The run command had event
prints but the gaps between RoundDispatched and the first response could
still feel silent on slow agents.

Add a Braille spinner (⣾⣽⣻⢿⡿⣟⣯⣷) wired into:

- runAction: spins from dispatch until awaitResult settles
- runHeadless: spins between *Dispatched events and the next event,
  tracking still-waiting participants in a per-round set so the label
  updates as agents come back

Spinner writes to stderr so it never pollutes act's stdout output.
Non-TTY falls back to a single breadcrumb line; NO_COLOR disables ANSI.

Also remove timer.unref() in two places:

- spinner.setInterval: keeps the event loop alive while spinning so the
  animation actually renders instead of getting cut off after one frame
- delegate.withTimeout: combined with mock provider's unref'd setTimeout
  it was causing "Detected unsettled top-level await" exits in act runs
  against the mock provider. clearTimeout is called on both settle paths
  so keeping the timer ref'd is safe.

Closes #60
@onevcat

onevcat commented May 11, 2026

Copy link
Copy Markdown
Owner Author

@onevpaw @onevtail /argue review一下这个PR

@onevpaw

onevpaw commented May 11, 2026

Copy link
Copy Markdown
Contributor

🤖 Argue 研判结果

  • Trace: mh_1778498322092_29cf25d0
  • Session status: consensus
  • Participants: @onevpaw, @onevtail
  • Rounds: 5
  • Claims: 7/7 resolved, 0 unresolved
  • Verdict: pass

Representative

  • Agent: onevpaw
  • Score: 86.80

Summary

共识结论:PR #61 主体实现方向正确,CI 与相关测试支持合并方向;但不建议直接 approve,应 request small changes,先修 argue act --no-colorrunAction 异常路径 spinner stop 顺序,以及 TTY 光标异常退出 cleanup。

All claims

  • ✅ 主线实现可合并 (2/2)
  • ✅ 需要补充光标恢复机制 (2/2)
    • Claim ID: onevpaw:0:1
    • Statement: spinner 在 TTY 下会隐藏光标,因此应在合并前补 SIGINT/SIGTERM/exit 等异常退出 cleanup;该 cleanup 应集中式或可 dispose,避免每个 spinner start 永久注册处理器导致 listener 累积或测试污染。
  • ✅ argue act 的 --no-color 不一致 (2/2)
    • Claim ID: onevpaw:0:2
    • Statement: PR 描述声称 --no-color 被 honor,但 argue act 的 parseActOptions 不接受 --no-color,runAction 也没有把 noColor 传给 createSpinner;需要补支持或修正文档描述。
  • ✅ 移除 withTimeout unref 是合理的 (2/2)
    • Claim ID: onevpaw:0:3
    • Statement: delegate.withTimeout 不再 unref timeout 可以避免所有其他 handle 都 unref 时 top-level await 提前失去 ref handle 的问题,且 resolve/reject 都 clearTimeout,因此该改动是合理的。
  • ✅ 非 TTY 与 stdout 设计正确 (2/2)
    • Claim ID: onevpaw:0:4
    • Statement: spinner 写入 stderr 可以保护 stdout piping;非 TTY 模式退化为 breadcrumb 而非动画是正确方向,但文案应明确是每个等待阶段/重启一条 breadcrumb,或实现全程只提示一次。
  • ✅ Exception path can print while spinner is active (2/2)
    • Claim ID: onevtail:0:3
    • Statement: If dispatch or awaitResult throws in runAction, the catch block logs the error before finally stops the spinner, which can leave messy terminal output or a hidden cursor during the error write.
  • ✅ Recommended pre-merge fixes are small (2/2)
    • Claim ID: onevtail:0:6
    • Statement: Before merging, complete a small pre-merge checklist: add --no-color support/tests for argue act, stop the spinner before logging caught action errors, and implement centralized/disposable SIGINT/SIGTERM/exit cleanup so hidden cursors are restored without accumulating signal handlers.

Report


🧵 mh_1778498322092_29cf25d0
🐾 MeowHook Argue
⚙️ Powered by onevcat/argue engine

…rror

- parseActOptions now accepts --no-color and forwards noColor to the
  spinner so the act command honors the flag, matching the PR claim.
- runAction's catch path now stops the spinner before printing the
  error so the line is not interleaved with an in-flight frame or
  written under a hidden cursor.
- Help text updated to list --no-color under argue act.
@onevcat
onevcat merged commit 6d7b6ee into master May 11, 2026
1 check passed
@onevcat
onevcat deleted the feat/run-act-spinner branch May 11, 2026 11:39
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.

argue act 能添加个正在执行的的 loading ?

2 participants