feat: add progress spinner for create commands#78
Conversation
KayIter
left a comment
There was a problem hiding this comment.
Thanks for adding the spinner. The JSON/non-interactive guard and stderr separation are heading in the right direction, but I found one user-visible correctness issue that should be fixed before merge.
Required
instance create prints the success spinner status before all local success validation has completed:
ags-cli/internal/commands/instance/create/command.go
Lines 64 to 75 in 81284ba
Right now sp.Stop("✓", "Instance created") runs immediately after executor.Execute returns nil error, but the handler still checks whether the typed response contains response.Instance. If the control plane returns &ags.StartSandboxInstanceResponseParams{} (typed success response, but missing Instance), the command returns INTERNAL_ERROR: no instance returned from API while stderr has already printed ✓ Instance created.
I reproduced this locally with a fake control plane and forced TTY:
err=no instance returned from API
stderr="\r\x1b[K✓ Instance created\n"
Please move the success Stop until after all local response validation succeeds, just before returning the final successful result. It would also be good to restore/add a regression test for the missing-Instance path and assert that success is not printed on that error path.
Suggestion
The spinner writes to ErrOut, but the enable check uses deps.IO.IsStdoutTTY():
ags-cli/internal/commands/instance/create/command.go
Lines 55 to 58 in 81284ba
ags-cli/internal/commands/tool/create/command.go
Lines 50 to 53 in 81284ba
That means an interactive command with stderr redirected, e.g. agr instance create ... 2>log, can write carriage returns / ANSI clear-line sequences / spinner frames into the log file. A more precise guard would check whether stderr is a TTY, or let the spinner decide from the actual writer.
I also ran the focused packages locally with Go 1.25.0:
go test ./internal/progress ./internal/commands/instance/create ./internal/commands/tool/create
Those tests pass; this is a behavior gap rather than a currently failing CI test.
3733b8b to
b944a24
Compare
KayIter
left a comment
There was a problem hiding this comment.
instance create 之前提到的误报已经修掉了,stderr TTY 判断也已经改对;但 tool create 还有同类问题。
[P2] tool create 在没有确认创建结果有效时仍会打印成功 spinner。
现在流程是先执行 applyCreateResultText(result, req),这个函数在 result.Data 不是 *ags.CreateSandboxToolResponseParams 时会直接 return;但外层随后无条件执行:
sp.Stop("✓", "Tool created")
return result, nil所以如果 API/adapter 返回了非 typed response,或者后续出现 typed response 但 ToolId 为空的情况,交互式 stderr 仍会出现 ✓ Tool created。这和之前 instance create 的问题是同一类:用户会看到成功提示,但 CLI 实际没有足够信息确认工具创建成功。
我用临时回归测试复现了非 typed response 情况,stderr 为:
\r\x1b[K✓ Tool created\n
建议和 instance create 保持一致:只有确认 response 类型正确且关键返回值(至少 ToolId)存在后才 sp.Stop("✓", ...);否则 cleanup,或返回 structured internal error。
本地验证:
go test ./internal/progress ./internal/commands/instance/create ./internal/commands/tool/create ./internal/iostreams通过- 临时 repro 测试可稳定复现上述误报,测试文件已清理
81b8a2f to
245e013
Compare
Add a lightweight terminal spinner (Braille animation, 80ms) for instance create and tool create commands. Provides visual feedback during API calls. Features: - Spinner writes to stderr, checks IsStderrTTY() for enable guard - Disabled for JSON output, non-interactive mode, or non-TTY stderr - sp.Stop only prints success after all response validation passes - response.Instance == nil prints failure status (not false success) - NewForCLI() helper eliminates duplicate guard logic across commands New files: - internal/progress/spinner.go: core implementation (no external deps) - internal/progress/spinner_test.go: 9 unit tests Modified: - internal/cli/exports.go: export IsJSONOutput() - internal/iostreams/iostreams.go: add IsStderrTTY/SetStderrTTY - internal/commands/instance/create/command.go: integrate spinner - internal/commands/tool/create/command.go: integrate spinner - internal/commands/instance/create/command_test.go: e2e tests - internal/commands/tool/create/command_test.go: e2e tests Closes TencentCloudAgentRuntime#75
245e013 to
64549be
Compare
KayIter
left a comment
There was a problem hiding this comment.
复查了最新提交 64549be,之前 tool create 成功 spinner 误报的问题已经修掉了。
现在 applyCreateResultText 会返回是否确认到了有效 CreateSandboxToolResponseParams 和非空 ToolId;只有返回 true 才打印 ✓ Tool created,否则 cleanup,不会再对非 typed response/缺失 ToolId 的情况报成功。
我也重新跑了上次的临时 repro,非 typed response + stderr TTY 时不会再输出 ✓ Tool created。
本地验证通过:
go test ./internal/progress ./internal/commands/instance/create ./internal/commands/tool/create ./internal/iostreams
LGTM.
Summary
Add a lightweight terminal spinner (Braille dot animation, 80ms interval) for
instance createandtool createcommands. Provides visual feedback during API calls.Changes
New files
internal/progress/spinner.go— Core spinner implementation (no external deps)internal/progress/spinner_test.go— 9 unit testsModified
internal/cli/exports.go— ExportIsJSONOutput()internal/commands/instance/create/command.go— Integrate spinnerinternal/commands/tool/create/command.go— Integrate spinnerinternal/commands/instance/create/command_test.go— 10 end-to-end testsinternal/commands/tool/create/command_test.go— 11 end-to-end testsBehavior
-o json--non-interactiveDemo
Design
Closes #75