> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.revise.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Release history for @reviseio/sdk.

## 1.2.0

### Added

* **International text support now extends across the editing and conversion
  pipeline.** Unicode-aware line breaking, search, list numbering, font
  fallback, and IME composition preserve multilingual text more reliably, and
  text import now detects UTF-8 and UTF-16 files. HTML, DOCX, RTF, ODT, and
  plain-text conversions keep the expanded script coverage intact.
* **Orange and purple join the SDK highlight palette.** The editor UI,
  `find_highlights`, `style_blocks`, agent HTML, and DOCX round trips now
  share the same seven canonical highlight colors.
* **Agent styling covers richer document structures.** `style_blocks` adds
  span, descendant-wildcard, first-row, and named-paragraph-style selectors,
  with durable mappings for image sizing and alignment, paragraph borders,
  nested tables and lists, per-edge cell borders, cell fills, padding, and
  table-cell text styles.

### Fixed

* **DOCX import follows Word's effective paragraph and table styling.**
  Unstyled paragraphs inherit the document's default style; exact and
  at-least line rules use the resolved font size; paragraph before/after and
  contextual spacing replace the editor's fallback gap; missing table borders
  remain borderless; and non-uniform cell margins survive import. The imported
  spacing persists through Yjs, paragraph splits and merges, HTML, DOCX, and
  PDF output, keeping compact Word layouts from growing onto extra pages.
* **Unavailable Word fonts use the document's own substitution hints.** DOCX
  import reads `fontTable.xml` alternate names and PANOSE/family/pitch
  metadata, persists them with the document, and chooses metric-compatible
  fallbacks before resorting to a generic family.
* **Multilingual PDF export embeds and shapes the scripts it needs.** Chinese,
  Japanese, Korean, Indic, Southeast Asian, Tibetan, Ethiopic, Armenian,
  Georgian, Syriac, Thaana, symbols, emoji, and rare Han use bundled lazy
  fallback faces, while a hidden logical-text layer preserves search and text
  extraction.
* **Agent edits preserve complex formatting and pending review state.** Styled
  tables, nested content, list-item formatting, explicit text overrides,
  comments, and edits layered over pending insertions now survive preview,
  acceptance, and rejection without duplicating or flattening structure.
* **Borderless layout tables stay visually borderless while editing.** The
  canvas now reveals only the specific invisible vertical edge under a resize
  pointer instead of ghosting the table's entire grid on hover or focus.
* **Imported pale-yellow highlights remain highlights.** HTML clipboard import
  no longer remaps Word's pale yellow to the editor's green palette entry.

## 1.1.0

### Added

* **First-class right-to-left editing.** The built-in toolbar can set paragraph
  and list direction to automatic, LTR, or RTL. Mixed Hebrew, Arabic, and
  left-to-right text now uses bidi-aware line layout, visual arrow-key
  movement, stable caret and selection geometry, direction-aware alignment and
  indents, mirrored list markers, and RTL tab stops. Direction survives Yjs,
  clipboard and agent edits, HTML, and DOCX round trips; PDF export preserves
  mixed-direction reading order and positioning.
* **Multi-column sections.** Page layout now supports one, two, or three
  newspaper-style columns with a configurable gap. Continuous section breaks
  balance their final columns, while page and next-page sections keep ordinary
  pagination. The canvas editor and PDF export share the flow rules, DOCX and
  HTML import/export preserve the settings, and `set_page_layout` exposes
  `columnCount`, `columnGap`, and section-scoped updates to browser and
  server agent sessions.
* **Native document-structure tools.** `insert_block` can create a live table
  of contents with `<toc levels="3"></toc>`. The canonical
  `remove_blocks` tool can delete a counted range, exact IDs, a saved search
  result, or an explicitly authorized document tail with `through_end`.

### Changed

* **Agent tool sessions avoid unproductive read cycles.** Sequential reads now
  reject windows containing only blocks already returned in the same request
  with `no_new_read_context`; `read_specific_blocks` remains available for
  intentional revisits. `remove_blocks` is now the model-facing name, while
  the previous `remove_block` name remains an executable compatibility alias.

### Fixed

* **Strict-provider nulls behave like omitted optional tool fields.** Browser
  and server tool execution normalize provider-materialized `null` values
  from the generated schema before dispatch, without stripping required or
  deliberately nullable values. Optional layout and mutation inputs therefore
  no longer take invalid branches merely because a provider filled them in.
* **Agent-generated Unicode escapes become the intended text.** Literal
  `\uXXXX` sequences in agent HTML and replacement paths are decoded without
  disturbing escaped backslashes or code spans, preventing visible escape text
  in edited documents.
* **Review decisions preserve the reader's place.** Accepting or rejecting a
  tracked change no longer forces the embedded editor to scroll back to the
  active suggestion.
* **SDK PDF export keeps Hebrew and Arabic text self-contained.** The package
  now bundles the Noto fallback faces used by RTL export, so embedding hosts do
  not need to mirror Revise's public font directory to avoid dropped glyphs.

## 1.0.1

### Fixed

* **Malformed model input can no longer crash a host's agent loop.** A bare
  string where `search_document` expects a `queries` array — the most
  common model slip — threw a raw `TypeError` out of `execute()` /
  `executeDynamic()` instead of returning a structured failure. Bare
  strings are now coerced to one-element arrays (also for
  `read_specific_blocks`' `block_ids`), anything uncoercible fails
  structurally, and both surfaces gained a safety net that converts an
  unexpected handler throw into an `internal_error` result. The documented
  contract — expected failures as results, only environment errors reject —
  now holds for arbitrary input.
* **Invalid enum values no longer mutate the wrong target silently.** An
  insert tool called with `position: "above"` placed content *after* the
  reference block while reporting success, and `set_header_footer` with a
  misspelled or missing `side` edited the header. Both now return a
  structured failure naming the valid values.

## 1.0.0

One package, one tool contract. The browser and server surfaces now speak
the same canonical envelope, so host result-handling code is shared verbatim
between web and Node. That convergence is breaking on the browser side —
every change is listed below.

### Breaking

* **`tools.execute()` returns the canonical discriminated envelope.** The
  flat `{ toolCallId, name, success, error?, agentFeedback?, output?,
  documentContent? }` result is gone. Both surfaces now return
  `{ ok: true, value: { callId, tool, message, data, context, suggestionIds } }`
  or `{ ok: false, error: { callId, tool, code, message } }`
  (`ReviseToolResult`). Field mapping: `toolCallId → value.callId`,
  `name → value.tool`, `agentFeedback → value.message`,
  `output → value.data`, `documentContent → value.context.html`;
  `view_image`'s attachment lives on `value.image`.
  `ReviseEditorToolExecutionResult` no longer exists.
* **`tools.execute()` is typed and no longer routes `document_id`.**
  `execute()`/`call()` take the generated per-tool input types and
  cover the shared 24-tool contract; untrusted model calls — including the
  browser-only `get_selection`, `view_image`, and
  `revise_run_agent`, and model-facing `document_id` routing — go
  through the new `executeDynamic()`, exactly as on the server.
* **Unknown tools and role denials are results, not throws.** `execute()`
  returns `{ ok: false }` with `code: "unknown_tool"` or
  `"role_not_permitted"` instead of throwing; the new `tools.call()`
  throws a typed `ReviseToolError` for hosts that prefer exceptions.
  `ReviseRoleError` is still thrown by `agent.run()` and UI
  controllers.
* **ID-keyed suggestion decisions return per-ID outcomes.**
  `review.acceptSuggestions`/`rejectSuggestions`,
  `review.acceptCommentSuggestions`/`rejectCommentSuggestions`, and
  `tools.acceptAllSuggestions`/`rejectAllSuggestions`, and the server
  session's `acceptSuggestions`/`rejectSuggestions` return
  `{ resolved, missing, unresolved }` (`ReviseSuggestionDecision`)
  instead of a bare count. Stale IDs land in `missing`; a role that may
  not resolve reports everything `unresolved`. `review.acceptAll()` /
  `rejectAll()` keep their boolean UI-gesture contract.
* **Server sessions default to suggesting mode.** `createServerDocumentSession`
  without `mode` now proposes tracked changes instead of applying edits
  directly — the same default posture as the browser surface, and the safe
  one. Pass `mode: "editing"` (or per-call `directMode: true`) for
  direct application.

### Added

* **Browser mutation results report created suggestion IDs.** Successful
  mutations carry `suggestionIds` — the tracked records that call created
  (empty for direct edits, `null` for read/search/measure tools) — with a
  concurrent human suggestion never attributed to the tool call. Feed them
  straight to `review.acceptSuggestions()`.

* **The tool contract types ship from both entries.** `ReviseToolResult`,
  `ReviseToolResponse`, `ReviseToolFailure`, `ReviseToolError`,
  `ReviseSuggestionDecision`, the generated `ReviseToolInputMap`, and
  friends are exported by `@reviseio/sdk` and `@reviseio/sdk/backend`
  alike.

* **Server mutation results report the tracked records they created.**
  Successful mutation calls from `createServerDocumentSession` now carry
  `suggestionIds` — the tracked suggestion records that call created (empty
  for direct edits, `null` for read/search/measure tools) — so a host can
  persist per-edit IDs with its review workflow instead of diffing the
  document-global pending set.

* **`listSuggestions()`** returns every pending suggestion as a reviewable
  record with authorship metadata (`authorType`, `agentName`,
  `agentModel`, `source`, `label`, `createdAt`), so hosts can decide on
  their own agent's suggestions and leave collaborators' pending work alone.

* **`acceptAllSuggestions()` / `rejectAllSuggestions()`** make the
  whole-document decision an explicit, greppable call instead of the
  `acceptSuggestions(getPendingSuggestionIds())` idiom.

### Fixed

* **Server tool types now resolve for `moduleResolution: "NodeNext"`
  consumers.** The packaged declarations re-exported the server tool contract
  through extensionless relative specifiers, which NodeNext cannot resolve —
  every tool input/output type silently degraded to `any`, and importing a
  contract type by name (e.g. `ServerDocumentSession`) failed to compile.
  The declarations now use explicit `.js` specifiers, which every supported
  resolution mode maps to the sibling `.d.ts` files.
* **Importing a document with code blocks no longer risks crashing a Node
  host.** The canvas syntax highlighter tried to fetch its tree-sitter wasm
  under Node (the server DOM shims install a jsdom `window`, defeating its
  browser check), failing as an unhandled promise rejection. Highlighting now
  recognizes the server runtime explicitly and stays off, and a failed
  highlighter init in the browser no longer poisons later attempts.
* **Table and list mutations no longer spam `Invalid access` warnings.**
  Building table rows, cells, and list items called Yjs `push()` on
  elements not yet integrated into a document, which logs a warning per
  child. Construction now inserts children at explicit indices — dozens of
  stderr lines per table insert in server logs, gone.
* **Editing mode applies server edits directly again.** A server session in
  `"editing"` mode quietly recorded every mutation as a
  pending tracked suggestion instead of applying it. Editing-mode calls now
  run in the runtime's direct mode and settle within the call, matching the
  documented behavior; an explicit per-call `directMode` still overrides in
  either direction.

## 0.9.0

### Added

* **`review.listChanges()` now reports linked moves as moves.** A move pair
  surfaces as ONE `ReviseTrackedChange` with `kind: "move"`,
  `moveSourceBlockIds`/`moveDestinationBlockIds` locating each half, and
  `deletedText`/`insertedText` carrying the text as it left and as it
  arrived. Previously both halves were folded into a single change labeled
  `"delete"`, leaving a host review panel no way to distinguish a move from
  a replacement. Accept/reject semantics are unchanged: resolving the change
  settles both locations atomically.

## 0.8.0

### Added

* **Cut and paste now creates native linked moves in Suggesting mode.** Cutting
  text from supported paragraphs and pasting that same internal clipboard
  payload elsewhere in the document produces one atomic “Moved from”/“Moved
  here” pair. Accepting or rejecting either half resolves both locations, undo
  cannot strand an orphaned half, and DOCX export/reimport preserves native
  linked move markup. Copy/paste, editing mode, reused or mismatched clipboard
  payloads, and unsupported structural selections continue to use ordinary
  insertion/deletion behavior.

## 0.7.0

### Added

* **Server-side semantic tools.** `await createServerDocumentSession(ydoc, { documentId, mode })` in `@reviseio/sdk/backend` binds the canonical
  document-local agent tools — read, search, measure, mutate, layout,
  footnotes, tables, comments — to a host-owned Y.Doc under plain Node.
  `mode: "suggesting"` produces Word-compatible tracked changes with
  accept/reject; concurrent calls are serialized; literal tool calls infer
  their schema inputs and structured outputs. See the README's "Server semantic
  tools" section.
* **Linked Word moves now round-trip as atomic move suggestions.** DOCX import
  pairs native `w:moveFrom` and `w:moveTo` ranges across runs, paragraphs,
  and table cells. Accepting either half keeps the text at its
  destination; rejecting either half restores its original location; export
  re-emits native paired move markup. Suggestion cards distinguish “Moved from”
  and “Moved here”, and focusing either half highlights its partner even across
  paragraphs.

### Fixed

* **Node-side DOCX imports preserve tracked table-row revisions without a
  browser `FileReader`.** The backend DOM shims and table-revision
  postprocessor now work from `Blob.arrayBuffer()`, retaining row insertion
  and deletion metadata in server integrations.
* **Word comment anchors preserve their identity and semantic range.** Safe
  native numeric IDs no longer shift, cross-paragraph and table-cell ranges
  emit one anchor triple instead of duplicates, and collapsed, overlapping,
  threaded, and resolved comments survive repeated round trips.
* **Visible drawing text survives DOCX import when shape geometry is
  flattened.** Inline and anchored DrawingML, grouped shapes, legacy VML,
  headers, and standards-valid `mc:AlternateContent` Choice/Fallback content
  become editable paragraphs in reading order without duplicate fallback text.
* **DOCX archives no longer inflate and large imports avoid repeated work.**
  Generated packages use DEFLATE compression, parse the main document XML once,
  and skip move indexing when a file has no moves, preventing the reported
  multi-fold output growth and superlinear no-move scan.

## 0.6.0

### Added

* **Horizontal rules and ornamental dividers are now supported throughout the
  editor.** Insert thin, thick, double, dashed, dotted, star, or diamond
  dividers from the toolbar or context menu, or create them with text triggers
  such as `---`, `===`, `-**-`, and `-<>-`. DOCX, HTML, Markdown, agent HTML,
  PDF, and plain-text output preserve the divider where the format permits;
  DOCX, HTML, Markdown, RTF, and ODT imports recognize their native divider or
  paragraph-border representations.

### Changed

* **Em-dash autocorrection now waits for a word boundary.** Typing `--` remains
  literal until Space or Enter, allowing `---` to be used for horizontal-rule
  insertion and preserving word-initial values such as `--flag`.

### Fixed

* **Words no longer wrap in the middle at formatting or tracked-change run
  boundaries.** A word split across differently styled text nodes now wraps as
  one unit and keeps a stable layout when suggestions are accepted.
* **Suggestion editing produces stable runs and caret placement.** Continued
  typing or backspacing merges into the existing suggestion instead of creating
  one run per keystroke, replacement normalization no longer leaves the caret
  inside hidden deleted text, and Enter after a pending deletion creates the
  expected paragraph or list item without moving the deleted content.
* **Structural editing keeps the expected document shape and keyboard focus.**
  Backspace exits or splits empty list items correctly, compatible lists rejoin
  when their separating empty paragraph is removed, Enter at the start of a
  leading heading or code block creates a body paragraph above it, and toolbar
  commands no longer steal keyboard focus from the editor.

## 0.5.1

### Fixed

* **PDF table-of-contents page numbers stay accurate when a heading moves to
  the next page.** Export now records a heading's destination after paragraph
  pagination, so a keep-with-next or end-of-page preflight cannot leave the
  TOC pointing at the page the heading would have occupied before it moved.

## 0.5.0

### Added

* **Comments now work on list items, including nested items.** Selecting list
  text, expanding a word from the caret, and commenting on a whole item all
  create item-local anchors. Returning the caret to that text activates the
  thread, list-item threads survive agent-HTML round trips, and the
  `leave_comment` agent tool accepts list-item IDs.

### Changed

* **PDF export now follows the editor's layout and print semantics much more
  closely.** It shares wrapping and pagination rules for tab stops and
  leaders, hyphenation, keep-with-next, keep-lines, widows and orphans, code
  blocks, nested tables, footnotes, page and section breaks, live TOC page
  numbers, line numbers, and watermarks. Editor-only placeholders and review
  chrome are not printed, and Word hidden text remains hidden in ordinary PDF
  output. The SDK now carries its metric-compatible PDF fonts itself, so an
  embedding host does not need to mirror Revise's public font directory.
* **Agent tool sessions reject redundant full-document read loops.** After a
  session has read the complete document, another sequential `read_document`
  returns `no_new_read_context`; agents can still revisit known content with
  `read_specific_blocks`.

### Fixed

* **DOCX formatting exceptions survive a complete edit and export cycle.**
  Explicit run-property clears over named styles, zero paragraph indents,
  paragraph border and shading clears, decimal font sizes, and mixed small-cap
  and all-cap overrides now remain distinct from inherited formatting and do
  not leak into adjacent text.
* **Complex Word structures no longer lose modeled content on re-export.**
  Internal bookmark links stay internal; exact table widths, columns,
  alignment, cell padding, and vertical alignment survive; nested tables keep
  the paragraphs around them; display equations are not flattened when a file
  is immediately re-exported; and multi-block footnotes and endnotes can retain
  their lists and tables.
* **Accepting or rejecting a compound agent edit is atomic.** Mixed text,
  formatting, and structural suggestions are resolved together, so accepting
  a rewrite no longer retains deleted fragments and rejecting it restores the
  original content and formatting.
* **Comment cards stay where users put them.** A previously active card no
  longer drifts with the viewport, and selecting text inside a card no longer
  jumps focus back to the document or clears the selection. Inline code in
  comment bodies is also styled as code.
* **Package managers can no longer omit the Yjs runtime.** Every editor session
  is Yjs-backed even without a collaboration provider, so `yjs` and
  `y-protocols` are now required peers instead of optional peers. This makes
  package managers install or validate them instead of letting bundlers
  substitute empty optional-peer modules and fail the consumer build.

## 0.4.5

### Fixed

* **Starting a list no longer drops the font.** Typing a list trigger
  (`- `, `1. `, `[] `) in a paragraph set in a non-default font produced
  a list item that fell back to the default font: clearing the trigger text
  left an empty item with nowhere to carry its formatting. The formatting at
  the trigger's trailing edge — the font family included — is now preserved
  on the empty item and applies to the next character typed.

## 0.4.4

### Fixed

* **Suggestion cards now hang from the suggested text.** The floating
  accept/reject card anchored to the caret; it now follows the suggested
  fragment (or your selection) and sits centered below its line, the same
  placement the revise.io app uses, falling back to the caret only when the
  fragment cannot be measured. Wide cards are clamped to the page edges
  instead of a fixed margin.

## 0.4.3

Identical in content to 0.4.2; republished.

## 0.4.2

### Fixed

* **Word-level diffs misplaced edits next to repeated words.** When the text
  adjacent to an edit repeated a word from the edit itself (replacing
  "\[Berkshire County / appropriate Massachusetts county]," with "Suffolk
  County, Massachusetts," just before "Massachusetts will"), the unchanged
  suffix could be drawn as deleted and retyped. Unchanged repeated words now
  stay anchored as unchanged, in tracked changes and the diff view alike.
* **Writing a comment no longer collapses the comments margin.** Finishing a
  draft that had itself opened the margin always collapsed it — even when
  submitting had just created a thread, so the pages jerked sideways in both
  directions and hid the card the user just wrote. The margin now stays open
  on the new thread; only an abandoned draft with no other open thread
  collapses it.
* **Comment card placement around drafts and tracked changes.** A comment
  draft started while hovering the card stack could pin its card — and drag
  the viewport — to the top of page 1; it now anchors where the draft was
  made. A caret inside a resolved thread's highlight, or inside an imported
  thread's replies, activated no card at all; it now activates the right
  open thread. And when a commented paragraph also contains tracked changes,
  the card describes the change under the cursor instead of jumping to the
  top of the paragraph.
* **The selection card no longer chases the pointer mid-drag.** While the
  mouse button is down nothing pops up under the pointer; the card appears
  on release, anchored below the selection the user meant.

## 0.4.1

### Fixed

* **Opening the export menu crashed.** An icon component in the export menu
  referenced React without importing it, which the packaged build has no
  global to fall back on.

## 0.4.0

### Changed

* **The default entry no longer ships Tree-sitter syntax highlighting or the
  embedded WASM payload.** Code blocks still render as code, and every WASM
  hot path has a TypeScript implementation. This keeps the normal
  integration smaller and compatible with strict Content Security Policies.
  Optional features now load as async chunks inside the package.

### Added

* **`@reviseio/sdk/full`** — an opt-in entry point that keeps token-coloured
  code blocks and the WASM hot paths. The API and stylesheet are identical
  between the two entries.

## 0.3.4

### Fixed

* **The SDK no longer attempts any telemetry.** Earlier builds emitted
  editor health metrics toward a Revise backend that does not exist in your
  deployment, which could only fail — loudly, as console CORS errors — and
  represented network calls you never asked for. Telemetry is now something
  only the revise.io application itself can switch on; embedded editors
  send nothing anywhere: no metric POSTs, no analytics vendor code, no
  beacons.

### Added

* **`onAnalyticsEvent`** — the editor's own instrumentation, delivered to
  the host instead:
  `<ReviseEditor onAnalyticsEvent={(event, properties) => ...} />`.
  Forward events to your own analytics service; a throwing handler never
  breaks the editor. Event names and property shapes are internal and
  version-unstable.

## 0.3.3

Four suggesting-mode fixes, two of them content corruption. If your users
edit in `suggesting` mode — the mode this SDK exists for — take this
release.

### Fixed

* **Pasting in suggesting mode corrupted the document.** The paste path
  predated suggesting mode: it duplicated the rest of the paragraph and
  inserted the pasted text without tracked-change marks, so the paste was
  invisible to review and survived reject. Pasting is now recorded exactly
  as if the pasted characters had been typed — an insertion suggestion, plus
  a deletion suggestion for any replaced selection.
* **Formatting across a pending change destroyed it.** Applying bold (or any
  inline format) over a range touching a pending insertion or deletion
  overwrote the change's identity; resolving the format then silently turned
  a pending insertion into accepted text, or resurrected deleted text.
  Formatting now leaves deletion spans alone, folds into insertion spans (as
  Word nests run properties inside `w:ins`), and records a reviewable
  format change only on unmarked text.
* **Accepting a deletion that crossed a paragraph boundary left the
  paragraphs unmerged.** The boundary is now part of the suggestion, as the
  pilcrow is in Word: accepting merges the paragraphs, in any resolution
  order, for any number of paragraphs in the selection.
* **Copying a selection inside your own pending insertion copied nothing.**
  It now copies the selected text. Clipboard payloads are also sanitized so
  tracked-change marks never travel with copied content.

### Console

* Opening a document no longer logs to the console (previously one Yjs
  warning per block plus two internal debug lines). `console.warn` and
  `console.error` remain for genuinely actionable problems.

## 0.3.2

### Fixed

* `editor.whenReady()` was missing from the published type declarations. It
  worked at runtime, but TypeScript rejected the call the documentation tells
  you to make.

## 0.3.1

### Fixed

* Using the editor handle from `onReady` no longer throws. `onReady` fires
  before any document exists, and "subscribe to everything on ready" is the
  first thing a host writes — a subscription placed then now waits and
  attaches when a document arrives. `selection.observe()` was affected too.
  Methods that act on a document still fail loudly, and the message now names
  the fix.

### Added

* `editor.whenReady()` — resolves once a document is open and its
  controllers are usable.
* `REVISE_SDK_VERSION` and `REVISE_SDK_BUILD` exports, and a `bugs` entry
  in the manifest: a support ticket can name the exact build it came from.

## 0.3.0

### Collaboration

Multi-user editing over a Yjs transport you own. The editor builds the
document; you attach the connection:

```ts theme={null}
collaboration: {
  connect: (doc, awareness) =>
    new HocuspocusProvider({ url, name, document: doc, awareness }),
  synced,
}
```

Remote carets, a presence roster (`editor.collaboration`), seed-or-join
semantics, and validation of any document you supply. See the collaboration
guide.

### Roles

`role="editor" | "suggester" | "viewer"`, editor-wide or per document, and
enforced on every surface: typing, the built-in chrome, the handle, and agent
tool calls. A suggester cannot leave suggesting mode, apply anything directly,
or accept and reject.

### Tracked changes you can list

`review.listChanges()` and `review.getChange(id)` return each pending change
with its kind, author, timestamp, affected blocks, and text — enough to build
your own review panel. Imported Word redlines keep their original reviewers.

### Server-side primitives

New subpath export `@reviseio/sdk/backend` (Node only): `parseDocument`,
`fileToYDoc`, `seedYDocFromFile`, `ydocToDocx`, `encodeYDoc`/`decodeYDoc`.
Your server can create a collaborative room from a .docx before any browser
connects, and export a live room without one. Requires `jsdom`.

### Breaking

* **`yjs` and `y-protocols` are now peer dependencies** and are no longer
  bundled. Install them yourself, and make sure your bundler resolves ONE copy
  — Yjs identifies its own types with `instanceof`, so a second copy breaks a
  shared document. Only collaboration needs them; they are optional peers.
* **`ReviseDocumentInput.docx` is now optional**, since a document joining a
  collaborative room needs no source file. Inputs must supply `docx`,
  `collaboration`, or both.

### Fixed

* `search_result_id`, which the agent tool schemas advertise for bulk edits,
  was unusable: tool state did not survive between `tools.execute()` calls.
* `exportDocx()` omitted TOC page numbers, which only the live layout knows.
* Exports lost imported named styles and reset core property dates in any
  non-browser environment.
* `collaboration.synced` was read once at mount, so a host reporting sync
  later was ignored and the document never opened.
* The margin insert-comment chip was missing from the embedded editor.
* Presence colours: an explicit `currentUser.color` was ignored whenever the
  user had an id.

## 0.2.0

Multi-document sessions, host-owned chrome, skinning props, per-embed
theming, the selection controller, and comment-thread agents.

## 0.1.0

First release: the editor, DOCX in and out, tracked changes, comments, and
the agent tool surface.
