feat(project): live step-based progress UI for deploy and build - #2163
Conversation
|
Claude Security Review: no high-confidence findings. (run) |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## refactor #2163 +/- ##
============================================
+ Coverage 97.27% 97.29% +0.01%
============================================
Files 510 515 +5
Lines 34115 34367 +252
============================================
+ Hits 33186 33437 +251
- Misses 929 930 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Claude Security Review: no high-confidence findings. (run) |
|
Claude Security Review: no high-confidence findings. (run) |
Replace the flat line-per-message stderr output of `project deploy` and `project build` with an inline Ink step list: a spinner on the running step, a ~5-line live tail of its real output (synth output, CDK Toolkit per-resource CloudFormation events) behind a muted gutter, and ✓/✕ as steps finish. Renders in normal scrollback (no alternate screen); the final frame leaves the completed step list above the success line and stack outputs. Non-TTY and --json invocations keep the previous plain line output byte for byte, and stdout stays machine-clean. Built as reusable layers so other long-running commands can adopt it: - ProjectEvent becomes a discriminated union of `step` and `output` events (the previous step completes when the next begins; the last when the generator returns). All producers and consumers updated. - AsyncChannel + createLineSplitter (src/io/channel.ts) and withOutputEvents (src/core/project/events.ts) bridge push-style output callbacks into the pull-based event generators. Synth chunks are line-buffered into output events; createCdkRunner now builds a per-operation IIoHost that both debug-logs and feeds the operation's onOutput sink. The backend keeps the last 20 Toolkit lines and appends them to terse Toolkit errors so failures are debuggable from the terminal alone; ProcessFailedError still carries full subprocess output untruncated. - TaskList (src/components/ui/task-list) renders tasks with the shared Spinner/✓/✕ vocabulary; runWithProgress (src/tui/progress.tsx) mounts it inline on stderr, resolves with the generator's return value, and on failure marks the step ✕, keeps its tail in scrollback, and rethrows unchanged for the existing exit-code handling. The teardown confirmation moves in front of the generator: the deploy handler prompts up front when the spec declares none of the resources removeAllResources clears, using the new read-only ProjectManager.resolveTarget to name the target's account and region. The decision reaches the backend pre-resolved, so nothing downstream blocks on interactive input; the backend's post-synth zero-resource count remains the non-interactive backstop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y
The handler no longer prints the outputs map to stdout on a plain deploy; align the guard test with that contract (stdout stays empty, --json still renders the full result). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y
`project build --json` printed nothing and `project deploy --json`
printed nothing on failure, leaving scripted callers to parse the
human-oriented stderr. Both now always emit one JSON document on
stdout: `{ message, ... }` on success (deploy keeps its outputs and
tornDown fields alongside the message) and `{ error }` on failure,
rendered before the error propagates so exit codes and the stderr
`Error: ...` line are unchanged. Errors marked silent (user
cancellation) stay silent. The shared renderJsonError helper lives in
handlers/utils for the next command that adopts the contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y
e436667 to
4a7b1ea
Compare
|
Claude Security Review: no high-confidence findings. (run) |
The rebase brought in the code-based evaluator feature (#2144), written against the pre-union ProjectEvent shape: retype its scaffold yield as a step event and guard its handler loops like every other consumer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y
|
Claude Security Review: no high-confidence findings. (run) |
| // human-oriented `Error: ...` line the exit-code handler prints to stderr. | ||
| // Callers rethrow afterwards; exit codes are untouched. Errors marked silent | ||
| // (e.g. a user cancellation) stay silent here too. | ||
| export function renderJsonError(ctx: Context, error: unknown): void { |
There was a problem hiding this comment.
does this cover middleware failures? withProject can fail before the build/deploy handlers call this helper, leaving the --json output empty. i would think it's fine but we could bring it further up in the pipeline if we want those covered
jariy17
left a comment
There was a problem hiding this comment.
Pretty clean and minimal code change that introduces a gorgeous UI
aws#2163 made ProjectEvent a discriminated union and updated the create wizard along with two of the three mocks in this file. The third belongs to a test aws#2164 added 112 seconds earlier, so aws#2163's branch could not see it: both PRs were green alone and only the merged pair fails typecheck and the spinner test. Same one-line change aws#2163 already made twice here.
| resourceConfig: gateway, | ||
| })) { | ||
| config.io.stderr.write(`${event.message}\n`); | ||
| if (event.type === "step") config.io.stderr.write(`${event.message}\n`); |
There was a problem hiding this comment.
Nit: If ProjectManager.addResource emits output events, they are silently dropped instead of being written to stderr.
Summary
Replaces the flat line-per-message stderr output of
project deployandproject buildwith a live, inline Ink step list: a spinner on the running step, a ~5-line scrolling tail of that step's real output (synth output, CDK Toolkit per-resource CloudFormation events) behind a muted│gutter, and ✓/✕ as steps finish. Renders in normal scrollback — no alternate screen — so the completed step list and success line remain in the terminal afterwards. Non-TTY and--jsoninvocations keep plain line-per-step output, and stdout stays machine-clean: nothing is written to it on a plain deploy. With--json, both commands always emit one JSON document on stdout —{ message, ... }on success (deploy includes its outputs andtornDown) and{ error }on failure, with exit codes unchanged.Built as reusable layers so other long-running commands can adopt the same treatment:
ProjectEventbecomes a discriminated union ofstepandoutputevents (a step completes when the next begins; the last when the generator returns). All producers (manager, CDK backend) and consumers (add/create/export handlers, create wizard) updated.AsyncChannel+createLineSplitter(src/io/channel.ts) andwithOutputEvents(src/core/project/events.ts) bridge push-style output callbacks into the pull-based event generators. Synth chunks are line-buffered intooutputevents;createCdkRunnerbuilds a per-operationIIoHostthat both debug-logs (unchanged) and feeds the operation'sonOutputsink. The backend keeps the last 20 Toolkit lines and appends them to terse Toolkit errors, so failures are debuggable from the terminal alone;ProcessFailedErrorstill carries full subprocess output untruncated.TaskList(src/components/ui/task-list) renders tasks with the shared Spinner/✓/✕ vocabulary;runWithProgress(src/tui/progress.tsx) mounts it inline on stderr, resolves with the generator's return value, and on failure marks the step ✕, keeps its tail in scrollback, and rethrows unchanged for the existing exit-code handling.removeAllResourcesclears, using a new read-onlyProjectManager.resolveTargetto name the target's account and region. The decision reaches the backend pre-resolved, so nothing downstream blocks on interactive input; the backend's post-synth zero-resource count remains the non-interactive backstop.Testing
bun test(2,624 pass),bun run typecheck,bun run lint:check,bun run format:checkall clean. New coverage: channel/splitter, event bridge,TaskList(ink-testing-library), driver (interactive + plain + error paths), backend output plumbing, and the resequenced confirmation flows.project build(success and a sabotaged failing build showing ✕ + full untruncated error), and a full live AWS round trip — freshproject create→deployto us-east-2 streaming 2,700+ genuine CloudFormation resource events through bootstrap and deploy, thenremove all --yes+deploy --yesrendering the teardown and deleting the stack.🤖 Generated with Claude Code
https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y