Files
PaperClipAI/ui
DottaandPaperclip 27db8354e4 fix(ui): make failed attempt notices stand out (#18174)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/257/changes/paperclip/257
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task conversations show when an agent could not finish a saved
request.
> - The exhausted-attempt notice currently looks like ordinary muted
status text.
> - People can overlook both the failure and its available Retry action.
> - This pull request gives failed attempts a padded, tinted surface and
a recognizable error icon using existing tokens.
> - The benefit is a clearer failure state while automatic recovery
keeps its quiet presentation.

## Linked Issues or Issue Description

Related: #17386 and #14156 cover recovery behavior. This PR only
improves the exhausted-attempt notice's presentation. Searches found no
duplicate styling PR.

**What happened?**

“Couldn’t finish this attempt. Your message is saved.” appears as muted
text without a background or padding above the task conversation, making
the failure easy to miss.

**Expected behavior**

An exhausted attempt should have a distinct, readable surface with
internal spacing and an obvious Retry action when permitted.

**Steps to reproduce**

1. Open a task whose system-owned interruption is `failed`.
2. Find the notice above the conversation.
3. Compare it with an automatic retry countdown. Previously, both had
the same muted inline treatment.

## What Changed

- Style failed attempts with a rounded destructive-tinted background,
token-based padding, foreground text, and a decorative error icon.
- Center the icon with the message and Retry button, including when the
message wraps.
- Keep the Retry button from shrinking on narrow screens.
- Check the center positions in the existing browser layout test.
- Add a production-component Storybook example beside a saved message.
- Document the exhausted-attempt treatment in the design guidance.

## Verification

- `pnpm check:token-gates` and `node scripts/check-maps.mjs`: pass.
- `pnpm exec vitest run
ui/src/components/ExecutionBlockerNotice.test.tsx`: 8 tests pass. These
cover Retry, countdowns, read-only access, active and resolved states,
admission waits, and admission errors.
- Chromium layout: 4 cases pass at 320px and 1280px in light and dark
themes. The icon, text, and Retry button have the same vertical center.
The previous code failed this check by 8–10px.
- Updated desktop and mobile screenshots are saved with the task.
- `pnpm --filter @paperclipai/ui typecheck` and `pnpm --filter
@paperclipai/ui build`: pass after the workspace SDK is built.
- Full local typecheck and build need Cargo. Cargo is not installed in
this sandbox. The full local Vitest run did not complete in the prior
session. CI must verify these checks.
- The updated head `4ba8de9da3e5c0c084cb5f752f371eccff31376a` passes all
test jobs, typecheck, build, and all eight E2E shards. The final CI
summary is queued.
- Greptile completed its review of this head with a score of 5/5. It
found no actionable issues. There are no review threads.
- The separate Paperclip Review check is queued. Its review task stopped
before it could publish the result. This check must complete before
merge.

## Risks

Low risk: this is a presentation-only change. The failed state takes
more vertical space. Recovery, authorization, retry timing, and API
contracts retain their existing behavior. Colors, spacing, radius, and
icon sizing use existing design tokens.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution, and browser inspection. The exact runtime model ID and
context-window size were not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 09:25:24 -06:00
..

@paperclipai/ui

Published static assets for the Paperclip board UI.

What gets published

The npm package contains the production build under dist/. It does not ship the UI source tree or workspace-only dependencies.

Storybook

Storybook config, stories, and fixtures live under ui/storybook/.

pnpm --filter @paperclipai/ui storybook
pnpm --filter @paperclipai/ui build-storybook

Typical use

Install the package, then serve or copy the built files from node_modules/@paperclipai/ui/dist.

Editor dependency identity

Keep the root and workspace overrides for @codemirror/state, @codemirror/view, and @lezer/common aligned. CodeMirror requires shared extension identity, while Lezer parsers and syntax highlighters require shared NodeProp IDs. Multiple Lezer copies can crash code-block highlighting with tags is not iterable. src/lib/codemirror-single-instance.test.ts checks the installed dependency graph and highlights sample code through the editor's real language dependencies. GitHub Actions owns regeneration of pnpm-lock.yaml.