Files
PaperClipAI/ui/src/lib
DottaandPaperclip 5996f25122 fix(ui): replace selected text on ordinary paste (#18796)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People edit task documents and comments in the Markdown editor.
> - Its link validator accepts safe text that is not a URL.
> - Lexical uses that validator to turn pasted text into a link around
the selection.
> - Pasting JSON or prose can keep the old text and put the new text in
its link destination.
> - This pull request handles plain selected-text replacement in the
existing paste plugin.
> - The benefit is standard text replacement with existing manual link
controls intact.

## Linked Issues or Issue Description

Fixes #2930.

Related: #8506 by `joegalbert-ai` identifies the same validator cause.
Thanks for that analysis. This change adds current Lexical command
coverage and preserves the separate manual and decorator link paths. The
contributor PR remains unchanged.

Reproduce by selecting an existing paragraph and pasting
`{"status":"ready"}`. The old code keeps the previous paragraph as a
link label and uses the JSON as its destination. The expected result is
the pasted JSON as text.

## What Changed

- Replace a selected text range, including soft line breaks, when the
clipboard text is not an unambiguous link target.
- Keep selected-label link wrapping for valid scheme, network, web and
email targets, including international addresses. Treat ambiguous
relative paths and fragments as ordinary pasted text.
- Leave the manual link validator unchanged. Keep manual relative,
internal, fragment, email and decorator links, with existing
executable-scheme guards.
- Use the same native Lexical rich-paste insertion API for selected HTML
payloads. Preserve HTML formatting and the paste undo boundary. Keep
files, Markdown, code and other selection types with their existing
handlers.
- Declare the clipboard API and test rich-text API at the existing
Lexical 0.48.0 version. The scheduled repository bot owns the lockfile
refresh; this PR has no lockfile delta.
- Add real Lexical paste and link-command regressions through the
production editor policy and paste plugin. This restores expected
editing behavior; it adds no setting, endpoint or new feature-map entry.

## Verification

- Before the fix, real selected-text paste tests fail for JSON, prose
and multiline text. They retain the old label and create a link with the
replacement as its URL. The valid-URL control passes.
- A test-only experiment with the exact recognition predicate from #8506
fails four current decorator relative/fragment cases. The chosen
paste-handler fix keeps the manual validator intact. The experiment was
removed after preserving its result.
- `pnpm --filter @paperclipai/ui exec vitest run
src/components/MarkdownEditor.test.tsx src/lib/markdownPaste.test.ts
src/lib/normalize-markdown.test.ts
src/lib/mention-aware-link-node.test.ts
src/lib/mention-deletion.test.ts`: 119 editor-focused tests passed.
After the baseline update, the same editor suites plus App and
ShellConfigurationGate passed 146 tests.
- The React MDXEditor shell is mocked. The configured production
predicate, actual paste-normalization plugin, native rich-text paste
handler and real Lexical paste/link commands are not mocked. Tests cover
URL wrapping, plain replacement, manual/decorator links,
executable-scheme handling and paste-owner handoff.
- UI typecheck and production build pass. UI token gates, module
boundaries and diff checks pass. Initial test event-type errors were
fixed. Greptile found that JSON with an email still formed a link. Its
real-command regression failed before narrowing whole-address
recognition and passes after the fix. An isolated frozen install and SDK
build resolved local workspace prerequisite errors.
- No live task edit or deployed replay was run. Full repository checks
run in current-head CI. The initial quality gate rejected generated
lockfile edits; the policy correction removes them without changing
tested source. The earlier current-head workspaces-a CI failure was the
independently fixed invitation-access fixture in App.test.tsx. Merge
#18799 supplied that baseline fixture fix. Its local regression and the
editor suites now pass together; all final-head CI checks now pass.
Final head `5156085b83c908e1439927bbebf25ab0aa42f81b` has 60 terminal
contexts: 56 success, three skipped, and the neutral Paperclip review at
5/5. Greptile is 5/5 with no unresolved findings.
- Review regressions also failed before repair for a selected soft line
break, formatted HTML with JSON, and international email addresses.
These cases now pass. The HTML test checks that bold formatting
survives.

## Risks

- URL recognition must not turn ordinary text into a link. Ambiguous
relative paths use text replacement on paste; the manual link controls
still accept them.
- The selected HTML path must preserve formatting. It delegates
insertion to the native rich-paste API with the original clipboard. File
payloads and non-simple selection types still yield.
- Existing Markdown normalization still applies. Script/data scheme
checks and rendered-link sanitization remain unchanged.
- No visual tokens, schema, public API, provider or deployment
configuration changes are required. No additional user documentation is
needed for this expected editing behavior.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, Extra High reasoning, with source
inspection, code execution and regression testing. Context-window
capacity is 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 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-04 07:09:37 -06:00
..
…
…
…
…