Skip to content

feat(project): live step-based progress UI for deploy and build - #2163

Merged
AlexanderRichey merged 4 commits into
refactorfrom
feat/project-deploy-progress-ui
Sep 2, 2026
Merged

feat(project): live step-based progress UI for deploy and build#2163
AlexanderRichey merged 4 commits into
refactorfrom
feat/project-deploy-progress-ui

Conversation

@AlexanderRichey

@AlexanderRichey AlexanderRichey commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the flat line-per-message stderr output of project deploy and project build with 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 --json invocations 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 and tornDown) and { error } on failure, with exit codes unchanged.

✓ Verifying AWS account 111122223333
✓ Synthesizing CloudFormation templates
⠸ Deploying AgentCore-orders-default-0
  │ AgentCore-orders-default-0 | 4/12 | CREATE_IN_PROGRESS | AWS::IAM::Role | RuntimeRole
  │ AgentCore-orders-default-0 | 5/12 | CREATE_COMPLETE    | AWS::IAM::Role | RuntimeRole

Built as reusable layers so other long-running commands can adopt the same treatment:

  • Structured eventsProjectEvent becomes a discriminated union of step and output events (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.
  • Output plumbingAsyncChannel + 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 builds a per-operation IIoHost that both debug-logs (unchanged) 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.
  • Component + driverTaskList (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.
  • 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 a 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.

Testing

  • bun test (2,624 pass), bun run typecheck, bun run lint:check, bun run format:check all clean. New coverage: channel/splitter, event bridge, TaskList (ink-testing-library), driver (interactive + plain + error paths), backend output plumbing, and the resequenced confirmation flows.
  • Eyeballed under a pty: paced demo, real project build (success and a sabotaged failing build showing ✕ + full untruncated error), and a full live AWS round trip — fresh project createdeploy to us-east-2 streaming 2,700+ genuine CloudFormation resource events through bootstrap and deploy, then remove all --yes + deploy --yes rendering the teardown and deleting the stack.

🤖 Generated with Claude Code

https://claude.ai/code/session_017KhMu3YVxNSVCst1LU877y

@github-actions github-actions Bot added the size/xl PR size: XL label Sep 1, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added agentcore-harness-reviewing AgentCore Harness review in progress claude-security-reviewing Claude Code /security-review in progress labels Sep 1, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@codecov-commenter

codecov-commenter commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.29%. Comparing base (89030dd) to head (184d79f).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Sep 1, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 1, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 1, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
AlexanderRichey and others added 3 commits September 1, 2026 19:20
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
@AlexanderRichey
AlexanderRichey force-pushed the feat/project-deploy-progress-ui branch from e436667 to 4a7b1ea Compare September 1, 2026 23:20
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 1, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
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
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Sep 1, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 1, 2026

@notgitika notgitika left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

Comment thread src/handlers/utils.tsx
// 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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@AlexanderRichey
AlexanderRichey merged commit bdd827f into refactor Sep 2, 2026
28 of 29 checks passed
@AlexanderRichey
AlexanderRichey deleted the feat/project-deploy-progress-ui branch September 2, 2026 03:05

@jariy17 jariy17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty clean and minimal code change that introduces a gorgeous UI

aidandaly24 added a commit to aidandaly24/agentcore-cli that referenced this pull request Sep 2, 2026
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`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: If ProjectManager.addResource emits output events, they are silently dropped instead of being written to stderr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants