Files
PaperClipAI/ui
DottaandPaperclip 0b8578055a fix: restore trailing spaces in queued steering messages (#19456)
## Thinking Path

> - Paperclip lets people manage AI agents and give them more
instructions during work.
> - The task composer sends those instructions through the shared
Markdown editor.
> - The editor writes a final text space as the HTML entity ` `.
> - The composer trims spaces before it submits a message. An entity
survives this step.
> - Queued messages can therefore contain extra text that the person did
not type.
> - This pull request restores final prose spaces at the editor output
boundary.
> - The queue and the agent receive clean message text. Code and escaped
examples keep their source.

## Linked Issues or Issue Description

**What happened?**

A message that ends with a space can contain a final ` ` when it
enters the steering queue. The shared editor exports this entity, and
normal message trimming does not remove it.

**Expected behavior**

The editor must return final prose spaces as spaces. Code samples and
escaped literal entities must keep their exact text.

**Steps to reproduce**

1. Open a task while its agent works.
2. Type a steering message with a space at the end.
3. Submit the message to the queue.
4. Inspect its stored Markdown. Before this fix, it can end with
` `.

**Paperclip version or commit**

Reproduced from `70d23612dd` with the installed Markdown serializer. The
serializer writes `Steer the current turn ` as `Steer the current
turn ` plus a newline.

Searches for related trailing-space and steering-entity PRs found no
duplicate.

## What Changed

- Restore trailing space entities only in the final Markdown text node.
- Apply this step before the editor removes its other transport escapes.
- Keep code, raw HTML, escaped entities, links, internal entities, and
hard breaks unchanged.
- Limit the fix to an entity at the end of the message. Keep entities
before internal newlines or closing emphasis markers. Replacing those
entities with spaces can create hard breaks or remove bold and italic
formatting. Add tests for these limits.
- Add editor regression cases and focused Markdown cases. Keep the fix
in the shared editor; no queue API change is needed.

## Verification

- TDD: the new editor test failed in 3 cases before the fix. It received
literal entities instead of spaces. All 6 cases pass after the fix.
- All 353 focused editor, Markdown, composer, and queue tests pass. This
includes 10 new cases for internal newlines, emphasis, and a final space
after these cases.
- `pnpm check:token-gates` and `git diff --check` pass.
- UI typecheck and UI production build pass.
- Repository typecheck and build could not complete locally because
Cargo is not installed. The full test command was started, then stopped
after confirming its native Runner cases also need Cargo. No complete
local full-suite verdict is claimed. Current-head
[CI](https://github.com/paperclipai/paperclip/actions/runs/42229743296)
passes for `350af775850664226d6630072cb8e08732e2a218`. This includes
typecheck, build, tests, and E2E checks.
-
[Greptile](https://github.com/paperclipai/paperclip/pull/19456#issuecomment-6686109030)
and [Paperclip
review](https://github.com/paperclipai/paperclip/pull/19456#issuecomment-6686063906)
each score the current commit 5/5. No review threads remain open.
- Checked the design-review dependency claim against the current commit.
[ui/package.json already declares the
parser](https://github.com/paperclipai/paperclip/blob/350af775850664226d6630072cb8e08732e2a218/ui/package.json#L71).
The existing underscore helper uses the same parser. Six direct checks
also pass for GFM strikethrough, task lists, URLs, and tables.
- No visual style changed. No database or API contract changed. The
helper comment documents the storage rule.

## Risks

- Low risk. The change only restores encoded spaces at the end of the
document. Internal line endings and spaces inside emphasis are out of
scope. The tests keep these entities unchanged to preserve Markdown
formatting. Parser source positions protect code and HTML. Escape pairs
protect literal entity examples.
- Existing stored messages are not rewritten. They use the corrected
output after an editor change.

## Model Used

- OpenAI Codex, GPT-6. GPT-6.1 Sol (`gpt-6.1-sol`) assisted with the
review follow-up. The runtime does not expose the context-window size.
Used reasoning, repository tools, code execution, and test execution.

## 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
- [x] 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-06 09:06:25 -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.