Skip to content

Draft.js: type_text / insert_text append must not double or replace existing content (clear_first:false) #121

Description

@Trace824

Summary

On X Draft.js compose, type_text / insert_text with clear_first: false (append) can duplicate text (body + body) or wipe/replace the existing draft. Append-without-wipe is the hard invariant for multi-step compose (body, then URL line).

Repro

  • Context: x.com compose, Draft.js [data-testid=tweetTextarea_0], existing draft text already present.
  • Steps:
    1. Insert body text once (CDP insert_text or selector type_text).
    2. Append a second string with clear_first: false / omit clear.
    3. Read draft contents before send.
  • Observed: doubled text (e.g. body repeated) or second call replaces first; clear_first / select-all paths also flake.
  • Partial mitigation on branch: draft_fast_path caret-at-end + clearFirst only when explicitly true (~actions.js L2967–3005); quirks remain under Draft.js / CDP mix.

Code pointers (verified against /workspace/FSB)

  • extension/content/actions.js — draft_fast_path clear/append (~L2967–3008); placeCaretAtEnd (~L3492+); clear_first / clearFirst handling (~L3473–3490, ~L3729–3730); append-safe verify comment (~L3667).
  • extension/background.js — cdpInsertText clearFirst (~L19131+, ~L20055–20093) via Input.insertText.
  • extension/ai/tool-definitions.js — insert_text / type_text schemas.

Proposed fix

Single root cause: append path must never select-all or replace Draft editor state when clear_first is false. Unify selector draft_fast_path and CDP cdpInsertText so both (1) place caret at end, (2) insert once, (3) verify post-text contains prior content + new suffix exactly once. Prefer one insertion API end-to-end for compose (see related paste issue).

Acceptance / regression

  • Given draft Hello, append \nhttps://example.com/ → draft is exactly body + newline + URL once.
  • Never doubles; never clears unless clear_first: true.
  • Automated regression for clear_first false/true on a Draft-like contenteditable fixture.

Owner

extension


Priority: P0 · Owner: extension

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions