revise 3.1.7 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +1677 -184
  2. package/FONT-LICENSE-HAN-EXT-B.txt +91 -0
  3. package/FONT-LICENSE-KATEX.txt +95 -0
  4. package/FONT-LICENSE-LIBERATION.txt +102 -0
  5. package/FONT-LICENSE-NOTO-MULTILINGUAL.txt +93 -0
  6. package/FONT-LICENSE-NOTO-SANS-SC.txt +93 -0
  7. package/FONT-LICENSE-NOTO.txt +94 -0
  8. package/FONT-LICENSE-SOURCE-CODE-PRO.txt +94 -0
  9. package/FONT-LICENSE-SOURCE-SERIF-4.txt +93 -0
  10. package/LICENSE +41 -21
  11. package/README.md +29 -121
  12. package/THIRD-PARTY-NOTICES.md +2751 -0
  13. package/assets/historyMaterializeWorker-ZFUHJDWr.js +619 -0
  14. package/chunks/AgentPageRenderer-CHHktDQ1.js +1 -0
  15. package/chunks/AgentPageRenderer-CN-N65JC.js +1 -0
  16. package/chunks/AttachmentDocumentImporter-DnHC9t7I.js +1 -0
  17. package/chunks/AttachmentDocumentImporter-Dqg7IPtK.js +1 -0
  18. package/chunks/ColorParserFull-BKH72fK8.js +446 -0
  19. package/chunks/DocumentScrubber-Ch_bOtHW.js +1 -0
  20. package/chunks/DocumentScrubber-DRzACkWJ.js +1 -0
  21. package/chunks/DocxConverter-BGPkGmyg.js +13 -0
  22. package/chunks/DocxConverter-DeurS5EF.js +13 -0
  23. package/chunks/DocxGraft-D71OgoMh.js +1 -0
  24. package/chunks/DocxGraft-QLkGEcwQ.js +1 -0
  25. package/chunks/FileImporter-BIT0ZBDY.js +1 -0
  26. package/chunks/FileImporter-Cgwoawuk.js +1 -0
  27. package/chunks/OdtConverter-2pm0SH5c.js +6 -0
  28. package/chunks/OdtConverter-CSUQTfVp.js +6 -0
  29. package/chunks/OfficeImportShared-C_mYnG5V.js +1 -0
  30. package/chunks/OfficeImportShared-O-d47J7O.js +1 -0
  31. package/chunks/PdfConverter-BYg_pr5J.js +21 -0
  32. package/chunks/PdfConverter-Z2HlY84F.js +21 -0
  33. package/chunks/PdfImportService-C2gwK1Sq.js +2 -0
  34. package/chunks/PdfImportService-CxtUtxM6.js +2 -0
  35. package/chunks/RtfConverter-BrtojpDV.js +15 -0
  36. package/chunks/RtfConverter-DlztsAoK.js +15 -0
  37. package/chunks/XmlConverter-3XWISlqr.js +2 -0
  38. package/chunks/XmlConverter-B1Kcohr0.js +2 -0
  39. package/chunks/__vite-browser-external-l0sNRNKZ.js +0 -0
  40. package/chunks/_revise-sdk-lazy-harfbuzz-X8gnYTZL.js +1 -0
  41. package/chunks/ar-vDYSGTpE.js +13 -0
  42. package/chunks/browser-module-BVdVmrPb.js +3 -0
  43. package/chunks/browser-module-CWlRHeO2.js +3 -0
  44. package/chunks/bundle.min-DRpfgV69.js +782 -0
  45. package/chunks/de-CWX4cvtt.js +13 -0
  46. package/chunks/es-DoAhvF6_.js +13 -0
  47. package/chunks/fil-DdAeD8Br.js +13 -0
  48. package/chunks/fr-CazsUjNQ.js +13 -0
  49. package/chunks/html2canvas.esm-CntiHiYW.js +997 -0
  50. package/chunks/index-BWdRWxoH.js +1807 -0
  51. package/chunks/index-D9_PwgOX.js +402 -0
  52. package/chunks/index-DcIXw_KB.js +402 -0
  53. package/chunks/ja-alh_QHTB.js +13 -0
  54. package/chunks/jspdf.es.min-BuJNZ-oY.js +1882 -0
  55. package/chunks/katex-DWj8TvwO.js +1462 -0
  56. package/chunks/pdf-BLWDCiFF.js +1828 -0
  57. package/chunks/persistInlineDocumentImages-DQj2iaqg.js +1 -0
  58. package/chunks/pseudoLocale-Bld5ZUFr.js +1 -0
  59. package/chunks/pseudoLocale-CLm3_c4X.js +1 -0
  60. package/chunks/tree-sitter-D6zWWUMP.js +4 -0
  61. package/chunks/wasmInline.generated-CBYFkdSM.js +1 -0
  62. package/chunks/web-tree-sitter-BXGZGnNj.js +2 -0
  63. package/chunks/zh-20eXwzFZ.js +13 -0
  64. package/cli-shim.js +34 -0
  65. package/full.js +1 -0
  66. package/index.d.ts +995 -13
  67. package/index.js +1 -31
  68. package/legacy/server.d.ts +19 -19
  69. package/legacy/server.js +39 -23
  70. package/package.json +55 -45
  71. package/serverToolContract.d.ts +420 -0
  72. package/serverToolInputs.generated.d.ts +269 -0
  73. package/style.css +1 -0
  74. package/version.d.ts +4 -0
  75. package/version.js +2 -0
  76. package/agent.d.ts +0 -139
  77. package/chunks/chunk-SMTOJL2X.js +0 -2436
  78. package/chunks/chunk-U5X47PZ6.js +0 -135
  79. package/chunks/chunk-U6YKQBKL.js +0 -15
  80. package/chunks/package-5SHL5FOJ.js +0 -14
  81. package/chunks/render-QD5VWKSV.js +0 -109
  82. package/cli-output.schema.json +0 -2159
  83. package/cli.js +0 -4152
  84. package/document.d.ts +0 -439
  85. package/docx.d.ts +0 -73
  86. package/errors.d.ts +0 -14
  87. package/legacy/editor.d.ts +0 -19
  88. package/legacy/editor.js +0 -16
  89. package/legacy/style.css +0 -2
  90. package/package.d.ts +0 -23
  91. package/render.d.ts +0 -27
package/CHANGELOG.md CHANGED
@@ -1,234 +1,1727 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.1
4
+
5
+ ### Fixed
6
+
7
+ - **The package README** no longer shows a broken image.
8
+
9
+ ## 4.0.0
10
+
11
+ The editor is the `revise` package, released at one version with
12
+ [`@reviseio/cli`](https://www.npmjs.com/package/@reviseio/cli) (the CLI and
13
+ TypeScript library) and `@reviseio/engine`, all built from one commit.
14
+
15
+ ### Added
16
+
17
+ - **Live lists of figures and tables.** `<toc source="captions">` lists
18
+ the document's figure captions with page numbers and stays current as
19
+ captions change; `label="Table"` (or any other label, such as Chart or
20
+ Exhibit, matched literally) collects that kind instead. Appendix and
21
+ supplementary numbers (A.2, S1, B-2) are listed. Word's `TOC \c "Label"`
22
+ field imports as one and exports back as the same field, and the list
23
+ renders in PDF, Markdown, RTF, and plain-text exports.
24
+ - **`join_paragraphs` joins ranges.** Pass
25
+ `ranges: [{ firstId, lastId, separator? }]` (up to 100) to join each run
26
+ of consecutive sibling paragraphs, such as lines pasted from a PDF,
27
+ without retyping the text. Every range is checked first: if any is
28
+ invalid, the call reports every problem and changes nothing. Each joined
29
+ range is one tracked change.
30
+ - **Comment anchors across wrapped lines.** A `leave_comment` anchor, or a
31
+ start/end anchor pair, whose text runs on into the following paragraphs
32
+ is anchored across them, as long as every block it spans has been read.
33
+ It used to fail with "Anchor text was not found". A miss now quotes the
34
+ block's text or names a letter-case difference.
35
+ - **`showImportButton`.** With `onImportFile`, controls whether the ribbon
36
+ shows Import (default true). Hosts that import only into an empty
37
+ document (through `uploadPlaceholder`) or by drop can turn it off.
38
+ - **Per-edge cell borders and padding shorthand.** `style_blocks` on table
39
+ cells takes `borderTop`, `borderRight`, `borderBottom`, and `borderLeft`.
40
+ `none` sets that edge to no border, and `null` clears the setting. CSS
41
+ padding shorthand such as `"7px 9px 7px 0"` is accepted (it was refused
42
+ before).
43
+ - **`style_blocks` `fontVariant`** takes `small-caps` or `normal`.
44
+
45
+ ### Changed
46
+
47
+ - **Install `revise`.** `npm i revise`, and import from `revise`,
48
+ `revise/full`, `revise/version`, and `revise/style.css`. Projects on
49
+ `@reviseio/editor` change the dependency and imports; see
50
+ [upgrading](https://revise.io/developer/docs/editor-sdk/installation#upgrade-from-an-earlier-version).
51
+ - **Server-side peer: `@reviseio/cli`.** The optional peer for server-side
52
+ work (conversion, agent tools over a shared Y.Doc, seeding collaboration
53
+ rooms) is `@reviseio/cli` at the same version.
54
+ - **A `revise` command.** It runs the Revise CLI from `@reviseio/cli`: the
55
+ installed copy, or `npx @reviseio/cli` at the same version.
56
+ - **`agent.run()` during a run waits its turn.** A second call while a
57
+ run was in progress used to return at once without running. It now
58
+ starts once the current run has finished, including a run that is still
59
+ ending after an error or `cancel()`.
60
+ - **New table rows and columns match their neighbors.** They take the
61
+ adjacent cell's borders, padding, shading, and vertical alignment. A row
62
+ added under a shaded header row takes the body rows' formatting, and a
63
+ row added to a table with alternating row shading continues the pattern.
64
+ This applies to the editor's table commands and to `insert_table_row` and
65
+ `insert_table_column`.
66
+ - **`replace_block` keeps paragraph layout.** A replacement paragraph keeps
67
+ the replaced paragraph's alignment, indents, spacing, line height, named
68
+ style, and text direction unless its HTML sets them. An explicit value,
69
+ including `line-height: normal` or `data-style-id=""`, still changes it.
70
+ - **A `replace` find may span paragraphs.** A plain-text `find` containing
71
+ line breaks can match the target block and the paragraphs right after
72
+ it. Each replacement line goes into its own block, and text outside the
73
+ match stays where it was. A miss explains the rule.
74
+ - **`join_paragraphs` keeps line-end hyphens.** Without a `separator`, a
75
+ line ending in a hyphen followed by a lowercase word joins with no space
76
+ ("exam-" + "ple" gives "exam-ple"). Other boundaries still get a space.
77
+ - **`remove_blocks` needs no read for page breaks and empty paragraphs.**
78
+ Section breaks and empty paragraphs that carry formatting (horizontal
79
+ rules, for example) still do.
80
+ - **Empty numbered list items show their number** in tool HTML
81
+ (`data-marker`).
82
+ - **The word count shows pages and the selection.** The figures under the
83
+ word count on the Tools tab show pages instead of characters (no page
84
+ count in pageless documents). With text selected they read "N of M
85
+ words" and "N of M pages". The selection count reads pending changes the
86
+ same way the total does, so selecting everything matches the total.
87
+ - **The change at the caret stands out** with
88
+ `settings.trackedChanges.markupStyle: "word"`. The tracked change under
89
+ the caret, or the one Review navigation is on, gets a faint red
90
+ highlight.
91
+ - **The ribbon keeps Export longest.** As the editor narrows, the full
92
+ ribbon first reduces cut, copy, and paste to undo and redo, and the
93
+ compact ribbon drops lists, then headings. Export and Import stay until
94
+ only undo, redo, and the font controls are left. The compact ribbon shows
95
+ Insert when there is room.
96
+ - **Clearer tool errors.** A negative `leftIndent` explains how to make a
97
+ hanging indent, and `leftIndent` or `firstLineIndent` on a list item
98
+ points to `indentLevel`. An `edit_table_cells` target inside a merged
99
+ cell names the merged cell's `row_id` and column. A delegated agent's
100
+ `move_blocks` refused only because of its own pending formatting says to
101
+ roll that back, move, and reformat.
102
+ - **Delegated agent: whole-document reviews are held to coverage.** A
103
+ review, audit, or summary that declares the whole document as its scope
104
+ is sent back to the ranges it skipped, as edits already were. A finish
105
+ reported as incomplete is not. A finish whose only edit is page setup on
106
+ a document the agent hasn't read is asked once to confirm that page setup
107
+ was the whole task.
108
+ - **Delegated agent: searches return up to 200 matches per page** (was 25).
109
+ The `search_document` default for `tools.execute` is unchanged.
110
+ - **Delegated agent: `cancel()` keeps the reasoning so far.** The next
111
+ `agent.run()` continues from the model's reasoning in the turns that
112
+ finished instead of starting without it.
113
+ - **Delegated agent: long conversations reuse the prompt cache.** Earlier
114
+ tool results and images are no longer trimmed from the history on each
115
+ request. The history is summarized only near the model's context budget.
116
+ - **Delegated agent: `render_document_pages` with placeholders** returns
117
+ the pages and marks the images and formulas it couldn't draw
118
+ (`visualVerification: "incomplete"`). It used to refuse every page.
119
+
120
+ ### Fixed
121
+
122
+ - **Footnotes and endnotes in suggesting mode stay with their references.**
123
+ A later edit to a sentence holding a pending note's reference used to
124
+ recreate the reference under the new suggestion or drop it, and rejecting
125
+ either change left a note with no reference. Now the paragraph is edited
126
+ around the reference, deletions over it are layered on top, and
127
+ formatting never moves it. An edit that would rebuild the block (changing
128
+ its type, splitting or joining it, or adding or removing list items
129
+ around it) fails with `pending_footnote_reference` and changes nothing.
130
+ - **Pending notes are credited to the right author.** A person's deletion,
131
+ or a note reference they type, inside an agent's pending text is credited
132
+ to the person, not to the agent's request. A note the agent writes into a
133
+ block it replaces no longer stops that block from being rejected.
134
+ - **Pending footnotes from Word.** A footnote or endnote reference inside a
135
+ tracked insertion or deletion imports with its note as part of the same
136
+ pending change, so accepting or rejecting settles both.
137
+ - **Footnote numbers with collaborators and undo.** Removing a note while a
138
+ collaborator renumbers no longer brings it back. Numbers left stale by an
139
+ undo are corrected on the next edit by any peer that can write, and undo
140
+ or redo of a removed note keeps its reference. A collaborator's typing no
141
+ longer makes every peer scan every paragraph of a long document, and two
142
+ peers renumbering at once no longer produce wrong numbers.
143
+ - **Viewers no longer write to the document when they open it.** In
144
+ `viewing` mode the editor applied legacy-format migrations and footnote
145
+ repairs to the shared Y.Doc, where a sync server rejected them and the
146
+ viewer's copy drifted. A viewer now shows a legacy document as it looks
147
+ after migration, without writing. The migrations run once the session
148
+ gets write access.
149
+ - **`replace` no longer rewrites similar paragraphs next to an exact
150
+ match.** In a table, list, or other container, a `find` that matches one
151
+ paragraph exactly no longer also fuzzy-matches near-identical paragraphs
152
+ beside it ("Paragraph 9 opens…" no longer matches every "Paragraph N
153
+ opens…"). `replace_all` never fuzzy-matches.
154
+ - **Fewer unnecessary "not fully read" refusals on tables.** Inserting a
155
+ block before or after a partly read table, and an exact-text `replace`
156
+ inside one (including `occurrence: "all"` and batches spanning several
157
+ tables), no longer require reading the whole table. Whole-block and
158
+ whole-cell edits still do.
159
+ - **`th` in `style_blocks` selectors** matches only the header row of a
160
+ table that has one. It used to match every body cell in that column.
161
+ - **The agent's own edits no longer look like someone else's.** After a
162
+ `style_blocks` call that restyled many blocks, editing one of them no
163
+ longer fails as "edited after you last read it". A block that is really
164
+ stale fails with the retryable `target_stale`. The agent's own edits no
165
+ longer invalidate its other search results, and cells of a row or column
166
+ it inserted as a pending change are no longer refused (or skipped while
167
+ reporting success) by `edit_table_cells`.
168
+ - **Images in `replace_block`.** An image can be replaced with text,
169
+ including when it is the document's only block (it failed with "not a
170
+ directly editable text block"). Replacing an image keeps the referenced
171
+ image's settings, CSS width and height in px set its size, and the result
172
+ names CSS that images ignore. It used to fall back to 200×200 and report
173
+ success.
174
+ - **A `replace` that matches an image's alt text** fails and says to use
175
+ `replace_block` instead of reporting success without changing anything.
176
+ - **`style_blocks` `letterSpacing: "normal"`** means no extra spacing. It
177
+ was rejected as not a number.
178
+ - **Web-search citation markers** that some OpenAI models emit are removed
179
+ from tool arguments, so they no longer show up as boxes in text,
180
+ footnotes, or comments.
181
+ - **PDF exports open in strict PDF readers.** Embedded TrueType fonts get
182
+ spec-conformant font dictionaries (Identity ordering, a unique subset name
183
+ per face, correctly scaled cap height, and correct italic flags). Pages
184
+ look the same.
185
+ - **Pasting a table with an empty line before or after it**, such as one
186
+ copied from Google Docs, pastes it. It used to do nothing.
187
+ - **Selection observers** no longer log "The selection endpoints no longer
188
+ exist" when a change removes the blocks holding the caret (an import into
189
+ the whole document, or a collaborator deleting them). The selection
190
+ snapshot is empty until the caret is back in the document.
191
+ - **Ribbon menus** no longer overflow their bounds in hosts without a global
192
+ `box-sizing` reset.
193
+ - **Delegated agent: a stalled model stream no longer hangs the run.** A
194
+ turn that receives nothing for five minutes is retried once. A second
195
+ stall in the same request ends the run with an error.
196
+ - **Delegated agent: whole-document coverage.** The coverage check credits
197
+ every range the request read, including reads that were trimmed or
198
+ repeated, reads from before a pause, and what a stopped request read
199
+ before the next one. A short document laid out as a table no longer lets
200
+ the agent stop as "incomplete" without trying, and the agent is sent back
201
+ at most once per blocker.
202
+ - **Delegated agent: edits outside the user's selection** are no longer
203
+ refused.
204
+ - **Delegated agent: removals after a clarifying question.** Blocks the
205
+ agent read before asking can be removed in the answer's request without
206
+ reading them again, if nobody has changed them since.
207
+ - **Delegated agent: page renders in a narrow editor** use the document's
208
+ page layout. On phone-width editors, a multi-page document rendered as
209
+ one long page.
210
+ - **Delegated agent: finishing with `completed_plan_steps` and no plan**
211
+ creates the plan instead of failing.
212
+
213
+ ### Security
214
+
215
+ - **jsPDF 4.2.1.** The bundled PDF writer moves from jsPDF 3.0.1 to a fork
216
+ of 4.2.1, which clears the npm advisories filed against 3.0.1, including
217
+ two critical ones. The fork leaves out `html()` and `addSvgAsImage()`,
218
+ which Revise does not use. THIRD-PARTY-NOTICES.md now lists jsPDF and the
219
+ packages it inlines (fflate, fast-png, pako, iobuffer, Babel helpers).
220
+
3
221
  ## 3.1.7
4
222
 
5
- Released with `@reviseio/editor` 3.1.7, the editor's first release in
6
- lockstep with revise: one version and one build for all three packages. A
7
- Y.Doc or .docx moves between the editor and revise unchanged.
223
+ From this release the editor, the CLI and library, and `@reviseio/engine`
224
+ share one version, built from one commit.
225
+
226
+ ### Removed
227
+
228
+ - **`@reviseio/editor/server`.** Server-side work moved to
229
+ [`revise`](https://www.npmjs.com/package/revise), the MIT CLI and
230
+ TypeScript library built from the same engine and released with this
231
+ version. It covers everything `/server` did:
232
+
233
+ | `@reviseio/editor/server` | `revise` |
234
+ | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
235
+ | `createServerDocumentSession(ydoc)` | `ReviseDocument.fromYDoc(ydoc)`, then `doc.tools` |
236
+ | `parseDocument`, `documentToDocx`, `fileToYDoc` | `ReviseDocument.open(file)`, `doc.export()`, `doc.ydoc` |
237
+ | `exportDocument(room, { mode })`, `ydocToDocx(room)` | `ReviseDocument.fromYDoc(room)`, then `doc.export({ format, mode })` |
238
+ | `seedYDocFromFile(room, bytes, filename)` | `seedYDoc(room, { bytes, filename })` |
239
+ | `encodeYDoc`, `decodeYDoc` | Y.js itself: `Y.encodeStateAsUpdate(doc.ydoc)`; `ReviseDocument.restore(update)` opens a bare update |
240
+
241
+ Documents move between the two unchanged: a Y.Doc the editor edits is a
242
+ Y.Doc `revise` opens, and the reverse. Two differences when porting:
243
+ `revise` methods are async (await them), and tools return
244
+ `{ ok, value | error }` instead of throwing; `doc.export()` returns
245
+ `{ bytes, … }`. `doc.snapshot()` is `revise`'s own storage format, not a
246
+ Y.js update: keep `Y.encodeStateAsUpdate` for anything that speaks Y.js.
247
+
248
+ ### Added
249
+
250
+ - **`uploadPlaceholder`.** With `onImportFile`, an empty document shows
251
+ "Type or paste your text or [Upload] a document" until something is typed
252
+ or pasted. Upload opens a file picker for the same formats as Import and
253
+ hands the file to `onImportFile`. Off by default, and never shown in a
254
+ read-only editor.
255
+ - **Markdown shortcuts while typing.** `#` through `######` and a space at
256
+ the start of a paragraph make it a heading. Typing the closing delimiter of
257
+ `**bold**`, `__bold__`, `*italic*`, `_italic_`, or `` `code` `` formats the
258
+ text and removes the markers. Only keyboard typing converts (paste and
259
+ agent edits don't), never in suggesting mode or inside code, and one undo
260
+ restores the literal text. Like smart quotes, they're on in every editor;
261
+ there is no prop to turn them off yet.
262
+ - **Failed tool results carry `details`** when the tool reported more than
263
+ its message, for example `edit_table_cells`' per-cell `errors` and the
264
+ `recovery_read` that fixes them (`ReviseToolFailure.details`, also on a
265
+ thrown `ReviseToolError`'s `failure`).
8
266
 
9
267
  ### Changed
10
268
 
11
- - **`remove_blocks` takes up to 200 ids** (was 50). Past the limit it removes
12
- nothing and says how to proceed: pass a search's `search_result_id` to
13
- remove every match, or send the ids in batches.
269
+ - **`revise` is an optional peer dependency** at the same version. Install
270
+ it for server-side work; a browser-only host doesn't need it. `jsdom` is
271
+ no longer a peer of this package (`revise` brings it).
272
+ - **`remove_blocks` accepts up to 200 ids** per call (was 50). A larger
273
+ batch fails without removing anything and points to `search_result_id`.
274
+ - **`search_document` doesn't page through empty paragraphs.** When every
275
+ match is an empty paragraph, asking for a later page fails and points to
276
+ acting on all of them at once with `search_result_id`.
277
+ - **`insert_table_row` matches its neighbors.** Text in a new row takes the
278
+ paragraph spacing, alignment, font, size, and color of the reference row's
279
+ cell in the same column wherever the HTML leaves them unset. Bold and
280
+ italic are not copied (the reference is often a totals row).
281
+ - **`<del>` in tool HTML** is strikethrough. A `<del data-change-id>` (how
282
+ `revise` shows a tracked deletion) is left out, so HTML copied from a
283
+ tracked read edits the text as it reads with changes accepted.
284
+ - **The delegated agent on long documents.** `agent.run()` and comment
285
+ agents keep long requests within each model's context budget: earlier
286
+ document snapshots leave the conversation and the latest read window is
287
+ sent again. When a document-wide edit leaves thousands of blocks pending,
288
+ the document overview lists a sample of them with the total instead of
289
+ every one. An agent that stops "incomplete" with budget left and nothing
290
+ blocking it is sent back to work, and one that finishes a task it declared
291
+ whole-document after reading under 90% of the document is sent back to the
292
+ ranges it skipped. A request restarted after a reload keeps credit for the
293
+ edits its first attempt made.
14
294
 
15
295
  ### Fixed
16
296
 
17
- - **Page numbers next to an existing header or footer.** `set_page_layout`
18
- with a page-number position, or a preset that numbers pages (APA puts them
19
- top right), used to report success while a hand-authored header or footer
20
- kept the number from appearing. The number now goes into that header's or
21
- footer's empty zone at the requested side, in the authored text's font. When
22
- the zone already holds text or the header already shows a page number, the
23
- result says so and lists the headers and footers instead of claiming the
24
- layout changed.
25
- - **A `replace` whose `find` and `replace` are identical** fails with an error
26
- that says so, instead of the generic "no changes detected".
297
+ - **Word-numbered headings stay headings.** Word often numbers clause
298
+ headings ("8.1 Cap on liability") through its heading styles, so they
299
+ import as list items, and their heading level was dropped. They keep it
300
+ now: `measure_document` and the delegated agent count them as sections,
301
+ titled with their number, tool HTML marks them `data-heading`, and
302
+ Markdown export writes them as `## 8.1 Cap on liability`. A paragraph whose
303
+ .docx sets `numId` 0 is no longer numbered by its style.
304
+ - **Markdown export numbers nested lists per level.** An item under "8." is
305
+ "1.", not "9.".
306
+ - **Tracked changes in headers and footers** import from .docx as pending
307
+ changes (they were silently accepted) and export as Word revisions (the old
308
+ and new text were both written, side by side).
309
+ - **Exporting an edited Word file no longer restyles it.** A file whose
310
+ package declares no document defaults exported with 12pt ones, so text that
311
+ inherits its size grew from Word's 10pt to 12pt, and runs that inherit
312
+ Word's default font were written back as explicit Arial. Both now export as
313
+ the original had them.
314
+ - **`set_page_layout` page numbers next to an authored header or footer.**
315
+ When the requested header or footer already has text, the number goes into
316
+ its empty left or right zone (a running head keeps its text and gains the
317
+ number), and the result says where the number is or why it could not be
318
+ placed. It used to report success with no number shown. The `apa7` preset's
319
+ page numbers work the same way; any existing header used to hide them.
320
+
321
+ ## 2.3.2
322
+
323
+ ### Fixed
27
324
 
28
- ## 3.1.6
325
+ - **Reordering a list** with `replace_block` reported success without
326
+ reordering, and rejecting it after a .docx round trip could duplicate an
327
+ item.
328
+ - **Hyperlinks across a .docx round trip:** tracked changes that add, remove,
329
+ or retarget a link in a list item (including lists in table cells) are
330
+ saved as revisions, so accepting or rejecting them after reopening gives
331
+ the same result as in the editor. A link removed in direct mode stays
332
+ removed when another author has a pending change on it, and a tracked
333
+ removal of a linked list item restores the whole link on reject.
334
+ - **Spacing and list levels across a .docx round trip:** tracked paragraph
335
+ spacing changes, including in list items and table cells, and tracked list
336
+ indent-level changes are saved as revisions, so rejecting them after
337
+ reopening restores the original. Deciding a reopened spacing change no
338
+ longer moves a nested list item to the top level.
339
+ - **Footnotes and table cells across a .docx round trip:** tracked paragraph
340
+ splits and joins in footnotes and table cells are saved as revisions; a
341
+ joined footnote stays joined after accepting, and rejecting no longer
342
+ leaves an extra empty paragraph. Accepting a reopened deletion of a list
343
+ item in a table cell no longer leaves an empty item.
344
+
345
+ ## 2.3.1
346
+
347
+ ### Fixed
348
+
349
+ Agent edits (`tools.call`, `tools.execute`, a delegated `agent.run()`, and
350
+ `@reviseio/editor/server` sessions) no longer change other people's pending
351
+ tracked changes. Before, an edit on or next to content that held someone
352
+ else's suggestions could silently accept them (with `directMode`) or re-create
353
+ them under the editing agent's name and today's date.
354
+
355
+ - **Paragraphs and list items** with pending changes: only the edit itself is
356
+ applied; existing suggestions keep their ids, authors, and dates. This
357
+ covers replacing text, formatting (`style_blocks`, `clear_formatting`),
358
+ appending, splitting, joining, inserting next to them, and item spacing and
359
+ indents.
360
+ - **Tables:** editing one cell changes only that cell. Inserting or removing
361
+ rows and columns keeps the other cells' suggestions.
362
+ - **New refusals instead of silent loss.** A few structural edits can't yet
363
+ keep existing suggestions, so they now fail with a clear error and change
364
+ nothing: `pending_table_changes` (row/column changes or merges on a table
365
+ that already has a pending row or column change or merged cells) and
366
+ `pending_list_changes` (converting a list's type, reordering, or other
367
+ list-level changes while the list holds pending changes). Resolve the
368
+ pending changes first, or edit the text directly.
369
+ - **Rejecting a format change after a .docx round trip** keeps footnote
370
+ references, comment anchors, fields, and hyperlinks. A rejected tracked
371
+ format change could delete a footnote's text.
372
+ - **DOCX export:** imported revision ids stay stable when new suggestions are
373
+ added; deletions over another author's insertion round-trip; replaced
374
+ paragraphs have no stray space after accept or reject in Word; suggestions
375
+ carry their author and date (some were written as "Anonymous"); deleted
376
+ list items accept cleanly after reopening; deleted links restore on reject.
377
+ - **DOCX import:** tracked insertions and deletions inside hyperlinks are
378
+ read; a list item that is wholly inserted or deleted imports as one
379
+ revision.
380
+ - `insert_footnote` works in paragraphs that have pending changes.
381
+ - Removing a table cell's only paragraph empties it instead of leaving a
382
+ change that can't be accepted.
383
+
384
+ ## 2.3.0
385
+
386
+ ### Added
387
+
388
+ - **`toolbarMode="compact"`.** The everyday part of the ribbon, centered,
389
+ for narrow fixed-width hosts (about 760px): undo and redo, font, size,
390
+ styles, paragraph, links, indents, lists, Find, and Export. The clipboard,
391
+ Insert, and Print are left out.
392
+ - **`toolbarMode="floating"`.** The full ribbon as a centered card over the
393
+ canvas, the way the Revise app shows it.
394
+ - **`onImportFile`.** Shows Import before Export in the ribbon (a file picker
395
+ for DOCX, ODT, RTF, Markdown, HTML, text, and XML) and accepts files
396
+ dropped anywhere on the editor, with a "Drop to import" overlay. Image
397
+ drops still insert images. The host receives the file and decides what
398
+ importing means.
399
+ - **Header and footer images.** Logos in Word headers and footers now show
400
+ on the page and in PDF export. They were kept for DOCX round trips but
401
+ never drawn. Images are scaled down to fit the margin band and never
402
+ overlap body text. `set_header_footer` takes an `image` (`image_id` of an
403
+ image already in the document, with `zone`, `alt`, `width`, and `height`)
404
+ and a one-based `sectionIndex` to edit one section's own header or footer.
405
+ Concurrent edits to different bands' images merge instead of overwriting
406
+ each other. DOCX export keeps the logo's alignment. It turns on Word's
407
+ first-page or odd/even headers when a logo needs them, and leaves a logo
408
+ out of sections whose margin is too small to show it.
409
+ - **`@reviseio/editor/server`: `agentName`.**
410
+ `createServerDocumentSession({ agentName })` sets the author on the
411
+ suggestions and comments the session's tools create, which DOCX export
412
+ writes as `w:author`. Defaults to "Revise Agent".
413
+ - **The delegated agent can move any block** as one tracked move: images,
414
+ code, equations, horizontal rules, page breaks, and tables of contents as
415
+ well as paragraphs, lists, and tables. Section breaks are still refused.
416
+
417
+ ### Changed
418
+
419
+ - **Import paths.** `revise/editor` → `@reviseio/editor`,
420
+ `revise/editor/full` → `@reviseio/editor/full`, `revise/server` →
421
+ `@reviseio/editor/server`, `revise/style.css` →
422
+ `@reviseio/editor/style.css`, and the build identity →
423
+ `@reviseio/editor/version`. The editor, license, and API are unchanged. The
424
+ docs moved to
425
+ [revise.io/developer/docs](https://revise.io/developer/docs/editor-sdk/introduction).
426
+ - **`replace_block` and `remove_blocks` name a range by its last block.**
427
+ `end_id` (inclusive, same container as `id`) replaces `count` in the tool
428
+ definitions and in `ReviseToolInputMap`. Calls with `count` still run, but
429
+ TypeScript callers that pass it need `end_id`. A reversed, unknown, or
430
+ cross-container range fails with `invalid_block_range` before anything
431
+ changes.
432
+ - **`remove_table_rows` replaces `remove_table_row`.** It removes one or more
433
+ rows per call, named by stable row ID (`rowIds`, a string or an array).
434
+ Rows the agent read stay removable after other rows change, without
435
+ reading the table again. `remove_table_row` with `{ tableId, rowIndex }`
436
+ is still accepted.
437
+ - **`read_table` `mode: "cell_text"` pages list their nested blocks**
438
+ (`blocks`: block ID and text offset), and each nested block's text opens
439
+ with an inline `[[block_id]]` marker. Text inside an oversized cell can be
440
+ read with `read_specific_blocks` and edited. A `replace` aimed at a table,
441
+ row, or cell edits the one nested block that contains the text.
442
+ - **`set_header_footer` reports what actually changed.** `clear: true`
443
+ without `slot` or `sectionIndex` removes that side from every page and
444
+ section. A call that changes nothing fails with "No changes detected" and
445
+ the current header/footer listing. An unknown `slot` is an error instead
446
+ of widening a clear. Clearing the first-page or even-page slot while the
447
+ document-wide footer shows there leaves an empty slot that hides it, as in
448
+ Word. `search_document` also matches header and footer text.
449
+ - **Mutation tools refuse empty arrays** (`content`, `replacements`,
450
+ `cells`, `ids`, `rowIds`, style `attrs` or `selectors`) before changing
451
+ anything, and name the tool that fits instead. The definitions mark these
452
+ `minItems: 1`. Empty table-insert content still inserts empty cells.
453
+ - **Edits next to an unresolved paragraph split or merge are refused** with
454
+ `pending_paragraph_boundary`: accept or reject the split first. Such edits
455
+ used to lose or duplicate text on review.
456
+ - **`style_blocks` headings take the document's heading style.** In an
457
+ imported Word document, a paragraph made a heading gets the heading
458
+ style's spacing and run formatting, and exports like the document's other
459
+ headings.
460
+ - **Agent-inserted content follows the surrounding font.** Inserted tables
461
+ take the font and body size at the insertion point. One `insert_block`
462
+ call uses one font for all its pieces. Rows and columns added by
463
+ `insert_table_row` and `insert_table_column` keep the table's font. A
464
+ heading's size no longer carries into paragraphs inserted after it. Cells
465
+ holding only inline markup (`<td><b>Total</b></td>`) keep their
466
+ formatting. Tables inserted from the editor take the caret's font.
467
+ - **DOCX export keeps more of the original file.** Untouched table rows,
468
+ cells, and list items are written as the original bytes when a neighbor
469
+ changes. Paragraphs with only text edits keep their original paragraph
470
+ properties. The original `styles.xml` is kept, with only the missing style
471
+ definitions added. Opening a document with page numbers no longer forces
472
+ headers, footers, and styles to be regenerated. In
473
+ `@reviseio/editor/server`, `exportDocument(room, { mode: "final" })` to
474
+ .docx keeps untouched content as the original bytes too.
475
+ - **The delegated agent** (`agent.run()` and comment agents) sees the
476
+ document's headers and footers. It stays inside a locked user selection
477
+ unless asked to go wider. It may re-read blocks it has already read. It
478
+ puts content asked to be added into the document rather than only in
479
+ chat, and it no longer finishes before results it asked for arrive. With
480
+ Anthropic models, requests that follow edits keep the prompt cache.
481
+
482
+ ### Fixed
483
+
484
+ - **Comment cards sit beside the page**, as in the Revise app, instead of
485
+ at the far right edge of a wide editor.
486
+ - **The ribbon stays centered on the pages** when the comments margin moves
487
+ them aside, as far as its width allows.
488
+ - **Add Comment and Toggle Comments** in the Review ribbon work. They were
489
+ always disabled.
490
+ - **Find shows in the native ribbon.** It was hidden whenever Dictate was,
491
+ which the SDK always hides.
492
+ - **The ribbon keeps text color and the styling menu down to 352px**, where
493
+ they were dropped below 430px.
494
+ - **The selection stays visible, dimmed, when focus leaves the editor**, for
495
+ example to a chat input in the host page, instead of disappearing.
496
+ - **Copy and Cut work in iframes that deny clipboard access** (no
497
+ `clipboard-write` permission).
498
+ - **Agent avatars on suggestion cards load**, where they used to resolve
499
+ against the host page's origin and show a generic avatar.
500
+ - **Hovering Accept all or Reject all previews the decided document.** Blocks
501
+ the decision removes, such as a moved table's source, are hidden, while
502
+ edited code and math blocks stay. Typing ends the preview, so keys never
503
+ edit a hidden block.
504
+ - **Word redlines with inserted or deleted paragraphs accept and reject
505
+ fully.** Consecutive paragraph-mark revisions used to overwrite each
506
+ other, so rejecting inserted clauses left them in place and accepting
507
+ could leave an empty paragraph. Rejecting a split keeps the paragraph's
508
+ current text, formatting, and pending revisions. Settling a
509
+ paragraph-formatting change no longer undoes later inline decisions.
510
+ Accept all and Reject all finish in one call when one decision uncovers
511
+ another.
512
+ - **Tracked table changes export to Word as revisions.** A suggested row
513
+ insertion, alone or combined with cell edits, is a Word row revision with
514
+ attributed inline cell changes instead of an untracked table. A
515
+ repeating header row survives a tracked deletion of the first row.
516
+ - **Moves of images, code, equations, rules, page breaks, and tables of
517
+ contents export once** to DOCX, not as two copies. Accepting or rejecting
518
+ a moved table with code or math in its cells no longer leaves a damaged
519
+ copy. Copied content no longer carries suggestion records.
520
+ - **A DOCX export never brings back a removed paragraph** (for example, a
521
+ rejected insertion) by returning the original file unchanged.
522
+ - **Highlight colors map by hue.** Office tints such as lavender no longer
523
+ show as gray, and mid or dark neutrals no longer show as green or yellow.
524
+ `style_blocks` can restore a block's original highlight.
525
+ - **PDF export draws SVG images** instead of blank space, and fetches an
526
+ image used on every page once.
527
+ - **HTML input with `<!-- comments -->`** no longer fails, and loose text
528
+ before a block keeps its place.
529
+ - **Turning page numbers off keeps an empty first-page footer**, so the
530
+ footer stays hidden on page 1.
531
+ - **Footnote edits.** Text in a just-inserted footnote is edited in place
532
+ instead of moving into the body. A find matches only visible footnote
533
+ text, not pending deletions. A batch that includes a footnote edit fails
534
+ or succeeds as a whole. `leave_comment` accepts a footnote that was read.
535
+ - **`replace` batches apply as planned.** Chained steps
536
+ (`Alpha→Beta`, `Beta→Gamma`), finds over a `search_result_id`, and
537
+ id-less `occurrence: "all"` finds are checked against each block's text
538
+ as earlier steps leave it. A step no longer lands on the wrong block or
539
+ sentence. Errors say when a long find drifts from the block, when the
540
+ block already contains the replacement, and that none of a failed call's
541
+ replacements applied.
542
+ - **`read_specific_blocks` reads a list item inside a table cell.**
543
+ - **NEL, LS, and PS characters read as spaces**, so a find copied from a
544
+ read matches.
545
+
546
+ ## 2.2.0
547
+
548
+ ### Added
549
+
550
+ - **ODT and RTF input.** `ReviseDocumentFormat` and `ReviseServerFormat` gain
551
+ `"odt"` and `"rtf"`, detected from `.odt` / `.rtf` filenames and from the
552
+ `application/vnd.oasis.opendocument.text`, `application/rtf`, and
553
+ `text/rtf` MIME types. Both import fonts, sizes, colors, highlighting,
554
+ character and paragraph formatting, headings, lists with their numbering,
555
+ tables with merged cells and column widths, images, hyperlinks, footnotes
556
+ and endnotes, headers and footers, comments, tracked changes, and page
557
+ size and margins. RTF from Word, WordPad, TextEdit, and LibreOffice is
558
+ supported, in any Windows code page or East Asian encoding. Each converter
559
+ loads only when a host first opens that format. `revise/server`'s
560
+ `parseDocument`, `fileToYDoc`, and `seedYDocFromFile` accept both. Host
561
+ code with an exhaustive `switch` over either type needs cases for the two
562
+ new values.
563
+ - **Delete whole table rows, columns, or tables from a cell selection.**
564
+ Backspace or Delete over fully selected rows or columns removes them, and
565
+ over every cell removes the table; a partial selection still clears only
566
+ the cell contents. Removing several rows is one undo step, and a table that
567
+ was the only block leaves an empty paragraph. Shift+click in another cell
568
+ of the same table now extends a cell selection, as dragging does.
569
+ - **Move connectors.** When a tracked move is focused, a line in the left
570
+ margin links where the text moved from to where it moved to, across pages.
571
+ It is not drawn in print preview.
572
+ - **Pleading-paper line numbers.** Documents whose page layout carries a
573
+ pleading grid show numbered rows (for example 1 to 28) at fixed positions
574
+ on every page, independent of the text, on screen and in PDF export. DOCX
575
+ export writes them as Word line numbers restarting on each page.
29
576
 
30
577
  ### Changed
31
578
 
32
- - **The agent skill knows when revise can't run.** In the Claude and ChatGPT
33
- apps, a document attached to the chat lives in a sandbox that can't install
34
- revise. The skill now stops before running anything there and offers the
35
- Revise app, which opens the document as an editable editor in the chat. If
36
- the app is connected, it uses it. Agents with a terminal are unaffected, and
37
- an install that fails on a network error is treated the same way instead of
38
- being worked around.
579
+ - **Margin line numbers behave like Word's.** Each number sits on its line's
580
+ baseline, table lines are not counted on screen (PDF already skipped
581
+ them), and a section that turns numbering off shows none instead of
582
+ inheriting the document setting. Numbers are set in the font that
583
+ dominates each page's text, on screen and in PDF, where they were always
584
+ Helvetica before.
585
+ - **The delegated agent can move blocks.** `agent.run()` and comment agents
586
+ can move paragraphs, lists, and tables as one tracked move (applied
587
+ directly in editing mode); blocks with anchored comments are not moved.
588
+ `move_blocks` is not part of the embedded tool list for `tools.*` hosts.
589
+ The delegated agent also recovers more reliably: it repairs a run that
590
+ edited and then reported no change, checks table fill work before it
591
+ finishes, and keeps the request and latest tool results when it recovers
592
+ from a context limit.
593
+ - **Suggestion cards show a date once a change is over a week old.** Old
594
+ changes read "Sep 4" or "Oct 11, 2013" instead of "4739d ago".
595
+ - **The footnote card is a compact row.** Clicking a footnote reference shows
596
+ its label with **Go to note** and **Remove**; the note is edited in the
597
+ note itself. In narrow layouts the card is centered under its reference
598
+ mark.
599
+
600
+ ### Fixed
601
+
602
+ - **Links.** Bare email addresses link and autolink as `mailto:`;
603
+ `mailto:` and `tel:` URLs are kept as typed; an `@` before the path is not
604
+ read as `https://` user info. Cmd+K uses the selected text as the link
605
+ target only when it is a full URL or an email address, and the link popup
606
+ finds a link Cmd+K just made on a backward selection.
607
+ - **Link, footnote, and inline-math popups line up at every zoom level.**
608
+ - **Math is no longer clipped when it renders before the KaTeX fonts load.**
609
+ Such results show provisionally and re-render once the fonts arrive, and
610
+ failed font or stylesheet fetches are not cached.
611
+ - **DOCX tracked moves of whole paragraphs, lists, and tables.** On import,
612
+ Word's paragraph-mark `w:moveFrom` / `w:moveTo` make the whole block part
613
+ of the move, so accepting it removes the source paragraph instead of
614
+ leaving an empty one, and a list split across a move becomes two lists.
615
+ Export writes paragraph marks and table rows with the move, and accepting
616
+ or rejecting resolves both halves together.
617
+ - **Accepting the deletion of every row of a table removes the table**, as
618
+ in Word, instead of leaving a table with no rows.
619
+ - **DOCX header and footer line breaks.** `w:br` in headers and footers is
620
+ imported, and export writes `w:br` instead of a raw newline that Word
621
+ showed as a space.
622
+ - **Header and footer layout.** In multi-column sections, headers and
623
+ footers span the full text width instead of one column; a zone is as wide
624
+ as its widest line; a bordered zone, such as a footer rule, spans the whole
625
+ band; and empty zones give up their space.
626
+ - **`replace_block` and `append_to_paragraph` on a non-text target**, such as
627
+ a table, fail with `target_type_mismatch` instead of doing nothing.
628
+ - **DOCX, ODT, and RTF open where `Blob.arrayBuffer` is missing** (Safari
629
+ before 14, jsdom). Files are read with a `FileReader` fallback.
39
630
 
40
- ## 3.1.5
631
+ ### Security
41
632
 
42
- Agents finish document tasks in fewer commands. Measured on the revise
43
- benchmark, Claude Code and Codex finish its tasks for about 40% less with
44
- revise than without it.
633
+ - **ODT and RTF import is hardened against hostile files.** Links pass a
634
+ scheme allowlist (http, https, mailto, tel, ftp, and relative), so
635
+ `javascript:` and similar are dropped. Self-referencing ODT deletions and
636
+ RTF control words such as `\constructor` can no longer overflow the stack
637
+ or swallow text, and imported tables are capped at 1,000 columns and
638
+ 100,000 cells.
639
+
640
+ ## 2.1.0
45
641
 
46
642
  ### Added
47
643
 
48
- - **`revise batch <file> '[...]'`** runs several tool calls (for example a
49
- table row and the total under it, or a `replace_all` and a `replace`) as one
50
- edit with one save. If any step fails, nothing is saved.
51
- - **`read --section 4,7,9`** reads several sections at once, `--blocks a..b`
52
- reads a range of ids, and `--count N` limits how many blocks are shown.
53
- - **`grep` takes several phrases** and shows about 80 characters around each
54
- match instead of the whole block (at most 40 blocks).
55
- - **`outline` lists headings typed as bold body text** first, each with the
56
- command that turns it into a real heading.
57
- - **PDF exports print the page count and paper size.**
644
+ - **`source` on document inputs.** `{ id, source: file }` names the field for
645
+ what it takes: DOCX, Markdown, plain text, or HTML. `docx` still works as the
646
+ same field; passing both with different values throws.
647
+ - **`context_notes` is optional in typed host calls.** `tools.execute()` and
648
+ `tools.call()` (browser and `revise/server`) fill in `"N/A"` for the read and
649
+ search tools, so application code no longer passes a model's working memory.
650
+ `executeDynamic()` keeps the schema requirement for model-provided calls.
651
+ - **`leave_comment` reports a retargeted anchor.** When the anchor text is not
652
+ in the named block and the comment goes to the only read block that has it,
653
+ `data.requestedBlockId` names the block you asked for and the message says so.
654
+
655
+ - **`read_table` and `edit_table_cells` agent tools.** Read a large table in
656
+ bounded windows (a summary, up to 50 rows, or one oversized cell in pages),
657
+ then set the plain text of up to 50 cells per call by row ID and column.
658
+ Cell text is written literally. Only cells a `read_table` call returned in
659
+ full can be edited, and that read stays valid across later `execute()` calls
660
+ on the same document while the cell and table geometry remain unchanged.
661
+ An invalid target rejects the whole batch with no changes. In suggesting mode each cell is its own suggestion. Read-only
662
+ surfaces and viewers get `read_table` only. Both tools are also in the
663
+ `revise/server` session. The SDK's `read_table` does not take the native
664
+ agent's task-declaration arguments (`task_kind`, `scope_*`,
665
+ `source_attachment_id`, `deliberate_blanks`). They are left out of the
666
+ published schema, and a call that supplies one fails with
667
+ `unsupported_argument` without reading anything. Empty placeholders
668
+ (`null`, `""`, `[]`) are ignored.
58
669
 
59
670
  ### Changed
60
671
 
61
- - **One `replace` call can edit several blocks:** leave out `id` and each
62
- `find` edits the one block you've read or grepped that contains it.
63
- - **Saves say what they rewrote:** "Rewrote N edited blocks; the rest of the
64
- file is copied byte for byte."
65
- - **`read` output is shorter:** it leaves out formatting that writing the
66
- block back restores anyway (a heading's own style, default table cell
67
- borders and padding, and the like).
68
- - **`outline` shows one id range per section** (`first..last`) and its word
69
- count.
70
- - **`compare` says what differs outside the redline:** header and footer
71
- text and page setup, or that the rest is formatting only.
72
- - **`--dry-run` with `--out`** previews instead of failing.
73
- - **The agent skill is a third shorter** and lists every field of `replace`
74
- and `leave_comment`, so agents don't need to look them up.
672
+ - **The delegated agent plans long tasks.** `agent.run()`, `revise_run_agent`,
673
+ and comment agents keep a step-by-step plan for multi-step work, update it
674
+ in the same turns as their edits, and save it with the conversation, so
675
+ fewer turns go to bookkeeping. The embedded tool list is unchanged: plan
676
+ tools stay inside the delegated agent.
677
+ - **Faster on long documents.** The scrollbar track and its markers are drawn
678
+ once and reused while scrolling, Find reuses each block's normalized text
679
+ between keystrokes, and tracked-change records are indexed in one pass
680
+ instead of one document walk per suggestion.
75
681
 
76
682
  ### Fixed
77
683
 
78
- - **`read --blocks a,b`** shows only those blocks, not every block between
79
- them.
80
- - **`outline` and `read --section`** see every section, not just the first 100.
81
- - **Rows added with `insert_table_row`** take the alignment, spacing,
82
- indents, and font of the row they're copied from.
684
+ - **DOCX paragraph spacing follows the document's rules.** `w:contextualSpacing` no longer
685
+ zeroes a paragraph's declared space before and after on import. Spacing is
686
+ resolved from neighboring paragraphs on screen, in table cells and
687
+ containers, and in PDF export: the gap between two paragraphs is the larger
688
+ of their spacings, not the sum, and contextual spacing drops it only between
689
+ paragraphs of the same style. PDF keep-with-next reserves the whole gap, and
690
+ exported DOCX keeps the declared spacing. Documents whose paragraphs both
691
+ declare spacing lay out tighter than in 2.0.x.
692
+ - **`style_blocks` with `list-style-type: none` turns list items into plain
693
+ paragraphs**, keeping their spacing and line spacing and applying the call's
694
+ other paragraph attributes in the same step.
695
+ - **Unsupported DOCX content can be suggested for removal.** In suggesting
696
+ mode, removing a block the editor preserves but cannot render (an opaque
697
+ DOCX payload) now becomes a tracked deletion.
698
+ - **Comment previews keep their layout.** In a comment chip's hover preview,
699
+ the avatar holds its size and a long author name is truncated.
700
+ - **An editor with no agent configured sends nothing.** `agent.run()`, the
701
+ `revise_run_agent` tool, and comment agents used to stream the document,
702
+ unauthenticated, to Revise's hosted agent and then report a generic
703
+ connection error. Without a `turnStream`, `baseUrl`, or `token`, they now
704
+ fail at once with `agent_not_configured` (`AgentNotConfiguredError` from
705
+ `agent.run()`), and `getToolDefinitions()` leaves the delegation tool out.
706
+ - **`documents.open()` activates the new document every time.** Opening a
707
+ document straight after another open, or after `documents.activate()`, left
708
+ the earlier one active. `documents.list()` status was also briefly stale
709
+ right after a document became ready.
710
+ - **`tools.getDefinitions()` lists only the native tools.** It included
711
+ `revise_run_agent`, which the docs say it leaves out.
712
+ - **Changing `agent.turnStream` no longer reloads the document.** A new
713
+ `turnStream` or `disableMetrics` value re-created the document runtime,
714
+ re-parsing the source and dropping unsaved edits, so an inline generator in
715
+ JSX reloaded the document on every render. Agent settings now apply to the
716
+ next run in place.
717
+ - **Reads are not refused for the life of the editor.** After a window had
718
+ been read once, every later `read_blocks_from_index` of it failed with
719
+ `no_new_read_context`, so a host agent's second conversation could not read
720
+ the document. The guard now resets with each call, like the other per-turn
721
+ limits.
722
+ - **Tool errors speak to SDK callers.** Messages no longer carry the internal
723
+ `Failed operation: <tool>: <Error>:` prefix or point at `<document_content>`,
724
+ which only Revise's own agent sees; they point at read results instead.
725
+ - **The open-error screen shows a plain message.** A corrupt file showed the
726
+ parser's internals (a zip library's message and link) to the person who
727
+ picked it. `onError` still receives the full detail. Loading text no longer
728
+ says "DOCX" for other formats, and a `File` source's title drops `.md`,
729
+ `.txt`, and `.html` extensions as well as `.docx`.
730
+ - **PDF export requests a failing font once.** When a font download failed
731
+ (a CSP or firewall blocking revise.io, say), export requested the same URL a
732
+ second time. The warning now says a fallback font was used and names
733
+ `setAssetBaseUrl()` for mirroring the fonts.
734
+ - **Readable errors from the package in Node.** Bundled code is wrapped at
735
+ short lines, so an uncaught error (such as the missing-`jsdom` hint) is no
736
+ longer printed under a 100 KB line of minified source.
737
+ - **Quieter host builds.** Vite no longer warns that `"buffer"` was
738
+ externalized, or prints the inlined WebAssembly's base64 as a file that
739
+ "doesn't exist at build time".
83
740
 
84
- ## 3.1.4
741
+ ## 2.0.1
742
+
743
+ ### Added
744
+
745
+ - **`tools.export({ format, mode })`.** Export as DOCX, PDF, HTML, Markdown,
746
+ or plain text from code, not just the ribbon's Export menu. `mode: "final"`
747
+ accepts every pending change and drops comments first for a clean copy;
748
+ the default `"review"` keeps tracked changes and comments in a .docx. The
749
+ editor-level `tools.export(options, documentId?)` routes to any open
750
+ document.
751
+ - **`exportDocument(source, options)` in `revise/server`.** The same export
752
+ for a room or a parsed document on the server: DOCX, HTML, Markdown, and
753
+ plain text, in review or final mode.
754
+ - **`onImageUpload(file, documentId)`.** Store images users insert, paste, or
755
+ drop in your own storage and return the URL the document should use.
85
756
 
86
757
  ### Fixed
87
758
 
88
- - **The package README's heading** reads `revise`.
759
+ - **Inserting, pasting, or dropping an image works.** It used to post to
760
+ Revise's app API, which the SDK cannot reach, so the image never appeared.
761
+ Without `onImageUpload`, images are now embedded in the document as data
762
+ URLs and export into the .docx. `toolbar.insertImage()` resolves `false`
763
+ when an upload fails, and the failure reaches `onError`.
764
+ - **Docs:** linked moves are described correctly in Support, the reserved
765
+ collaboration keys point to `RESERVED_DOCUMENT_KEYS`, and the delegated
766
+ agent page says how to get hosted-agent access.
767
+
768
+ ## 2.0.0
89
769
 
90
- ## 3.1.3
770
+ The SDK is now public: `npm i revise`. No account, token, or contact
771
+ with us is needed to install it. 2.0.0 also ships everything from the
772
+ 2.0.0-alpha releases below.
91
773
 
92
774
  ### Changed
93
775
 
94
- - **The package README** has a plain heading and tagline. No changes to the
95
- CLI or the library.
776
+ - **BREAKING: the package is now `revise`.** The private `@reviseio/sdk`
777
+ package is retired. Update the dependency and imports:
778
+ `@reviseio/sdk` → `revise/editor`, `@reviseio/sdk/full` →
779
+ `revise/editor/full`, `@reviseio/sdk/backend` → `revise/server`, and
780
+ `@reviseio/sdk/style.css` → `revise/style.css`. Remove the `@reviseio`
781
+ scope and token lines from `.npmrc`.
782
+ - **New license: free for evaluation, personal projects, and education.**
783
+ Production use by businesses, nonprofits, and government requires a paid
784
+ license. See `LICENSE` and [the license page](https://revise.io/developer/docs/editor-sdk/license).
785
+ The previous 60-day evaluation terms no longer apply.
786
+ - **The editor fills its container at any size.** The 640×560px minimum is
787
+ gone, so the editor fits phone-width columns and short panels without
788
+ overflowing them. A container with no height gets a 560px fallback and a
789
+ one-time console warning instead of a collapsed editor.
790
+ - **Hosted agent defaults to production.** Without `agent.baseUrl`, the
791
+ delegated Revise agent now targets `https://agent.revise.io` instead of a
792
+ development address.
793
+
794
+ ### Added
795
+
796
+ - **A 4.5 MB package, with assets loaded on demand.** PDF export fonts were
797
+ inlined as base64 and made up three quarters of the package; they, the math
798
+ fonts and stylesheet, the pdf.js worker, and Tree-sitter grammars now load
799
+ from `https://revise.io` when first needed. **`setAssetBaseUrl(url)`**
800
+ points the SDK at a self-hosted mirror.
801
+ - **`import ReviseEditor from "revise/editor"`.** The editor entry now has a
802
+ default export. The named `ReviseEditor` export still works.
803
+ - **`revise` root entry** with `REVISE_SDK_VERSION`, `REVISE_SDK_BUILD`, and
804
+ the shared types, and no runtime weight.
805
+ - **`THIRD-PARTY-NOTICES.md`** lists every bundled open-source package with
806
+ its license.
807
+ - **Anonymous usage ping, and the `telemetry` prop to turn it off.** Once
808
+ per page load, the editor sends Revise its version; the browser adds the
809
+ site's origin. Development hosts are counted per day and version without
810
+ their origin. No cookies, user data, or document content.
811
+ `telemetry={false}` disables it.
812
+
813
+ ### Fixed
96
814
 
97
- ## 3.1.2
815
+ - **Math renders with its real fonts in host apps.** Equations looked for
816
+ their fonts and stylesheet at the host's own `/fonts` and `/katex.min.css`
817
+ and fell back to system fonts; the help link in the editor menu also
818
+ pointed at the host's `/help`. All now resolve to Revise's assets.
819
+ - **The SDK no longer reaches for development servers.** Revise application
820
+ endpoints (document history, preferences, uploads, failure reports) and the
821
+ sync-server addresses no longer resolve to `localhost` in an embedding
822
+ host. Document history in particular fetched from `localhost:3001` in
823
+ browsers without a `process` global.
824
+ - **No debug globals on the host's `window`.** `__getEditor`,
825
+ `__getDocLayout`, and `__aiLogs` are no longer installed.
826
+ - **DOCX math export uses Revise's own MathML → OMML converter.** Equations
827
+ export to native Word math (fractions, radicals, scripts, sums and
828
+ integrals with limits, delimiters, matrices, accents, bars, braces,
829
+ functions, boxed and text runs) with no third-party copyleft code in the
830
+ package. Re-importing them is more faithful: `\left\{ … \right.`,
831
+ `\underline`, `\overbrace`, `\boxed`, `\text{…}`, `\mathbb`, binomials,
832
+ and named functions (`\sin`, `\log`, `\lim_{…}`) now come back as the
833
+ same LaTeX instead of approximations, and symbols no longer run into the
834
+ following letter (`\alpha x`, not `\alphax`).
835
+
836
+ ## 2.0.0-alpha.7
837
+
838
+ ### Fixed
839
+
840
+ - **DOCX round trips keep every modeled mark and block.** A new
841
+ export → import matrix (every formatting mark in every text context,
842
+ every paragraph, list, table, cell, image, code, math, note, header,
843
+ footer, and page-layout attribute, plus a second-pass fixed-point
844
+ check) found and pinned a set of losses: lists inside table cells
845
+ were dropped on export; hanging indents exported as zero and
846
+ `w:hanging` was ignored on import; headings came back as Word's blue
847
+ 16pt built-ins (export now writes the editor's heading sizes with
848
+ inherited color); unscoped header/footer blocks were not exported;
849
+ hyperlinks discarded an explicit text color; links inside footnotes
850
+ were lost on import; header and footer runs used a reduced codec in
851
+ both directions and now share the body run codec, links and inline
852
+ code included; inline code and code blocks flattened to Courier text
853
+ and now travel as `CodeInline` / `CodeBlock_<language>` styles and
854
+ return as the original nodes; todo items exported as literal
855
+ `[x]` text and now use checkbox glyphs that re-import as todo lists
856
+ with their checked state; code-block line breaks doubled on
857
+ re-import; and a single run in another font restamped the whole
858
+ document (the inferred document font is now the character-weighted
859
+ majority).
860
+ - **Table borders export and re-import faithfully.** Export no longer
861
+ throws on non-hex colors such as `TRANSPARENT`, `rgba()`, or CSS
862
+ names — unresolvable values are omitted or written as `auto`. The
863
+ uniform `borderWidth`/`borderColor` pair is honored (width 0 means
864
+ no borders), width-0 spec edges export as `none` instead of a
865
+ hairline, and an explicit `w:sz="0"` imports as hidden rather than a
866
+ 1px line. Table Settings border changes now rewrite the structured
867
+ table spec and clear per-cell overrides, so hiding borders on an
868
+ imported table takes effect.
869
+ - **Byte-preserving DOCX export degrades instead of failing.** A carrier
870
+ that fails to load falls back to the regenerated package like every
871
+ other graft failure; the graft option reports its outcome (exact,
872
+ grafted, regenerated, and the fallback code) through an isolated
873
+ callback that can never break an export. Untouched imports of rich
874
+ documents now export byte-identical: note-body font inheritance,
875
+ header/footer zone ids, and legacy chrome no longer drift the
876
+ fidelity signatures; watermark and settings edits graft instead of
877
+ restoring carrier values; body grafting is invalidated when wrapper
878
+ or style sidecars change; single-quoted and non-numeric relationship
879
+ ids parse; and a changed header image is replaced even when its
880
+ media filename collides.
881
+ - **Formatting suggestions preserve footnotes.** Accepting a
882
+ `style_blocks` suggestion keeps footnote references and bodies.
883
+ - **Large documents no longer stall on batch edits.** Styling 205 blocks
884
+ in a 10,000-block document, applying 100 replacements, and large
885
+ multi-block insertions run without re-decoding the document per
886
+ action; suggestion projection latency is bounded; batch paragraph
887
+ formatting suggestions behave identically through preview,
888
+ acceptance, and rejection.
889
+ - **Semantic tool errors and inputs.** Errors distinguish Markdown find
890
+ syntax from stored plain text; metric CSS paragraph indentation
891
+ (`cm`, `mm`) is accepted; number-dot prose can be parsed as inline
892
+ text instead of a list when requested.
893
+ - **Comments render AI citations.** Structured citations persist on
894
+ replies and render in the panel; unsupported provider citation
895
+ markers are hidden, including on legacy comments.
896
+ - **Agent image rehosting.** Wikimedia thumbnail URLs are recovered by
897
+ rehosting the original image, and rate-limited rehosts surface the
898
+ backend reason and status.
899
+ - **Revision timeline never collapses to zero.** A stale or missing
900
+ server update counter no longer disables history or pins every frame
901
+ to the first update; loaded frames are authoritative.
902
+ - **Pasted images write once.** A pasted image no longer inserts a
903
+ temporary base64 placeholder that is replaced later; the final hosted
904
+ URL is written at the captured paste position when the upload
905
+ completes.
98
906
 
99
907
  ### Changed
100
908
 
101
- - **`revise skill install` installs where the agent running it reads
102
- skills:** `.claude/skills` from Claude Code or in a project with a
103
- `.claude` folder, otherwise `.agents/skills`, which Codex, Cursor, Copilot,
104
- and others read. It used to fall back to `.claude/skills`, which other
105
- agents don't read.
106
- - **It ends by saying to read the installed SKILL.md now:** a running agent
107
- session doesn't load a newly installed skill; new sessions do. The
108
- quickest install for any agent with a terminal is
109
- `npx -y revise@latest skill install`.
909
+ - **Comment margin geometry is direction-aware.** Chip, floating-stack,
910
+ and insert-chip positions are computed along an outward axis with a
911
+ single conversion to physical coordinates. The embedded document
912
+ surface itself is still laid out left-to-right: the margin chrome
913
+ stays on the page's right regardless of the host page's direction.
914
+ Mirroring the embed for right-to-left hosts is not part of this
915
+ release.
916
+
917
+ ## 2.0.0-alpha.6
918
+
919
+ ### Fixed
920
+
921
+ - **A healed seed race now recovers full fidelity — and never loses a
922
+ comment.** Three repair refinements: the winner is the seed whose
923
+ metadata survived the merge (each seed stamps a ballot in the same
924
+ transaction), so the kept content matches the surviving import
925
+ capture; a shared deterministic id keeps the WINNER's element, not an
926
+ arbitrary one; and map records under a shared key (deterministic
927
+ comment ids) are never deleted — the merge already deduplicated them,
928
+ and alpha.5's repair removed the only surviving record. A raced,
929
+ repaired room now reports "exact" and exports byte-identically.
930
+
931
+ ## 2.0.0-alpha.5
932
+
933
+ ### Fixed
934
+
935
+ - **Seed-race repair kept a duplicate footnote.** Deterministic ids that
936
+ every seed generates identically (docx footnotes) were protected from
937
+ repair as a collision safeguard, leaving one copy per seed. Repair now
938
+ keeps exactly one occurrence of a shared id. Supersedes 2.0.0-alpha.4,
939
+ which was deprecated minutes after publish.
940
+
941
+ ## 2.0.0-alpha.4
942
+
943
+ ### Fixed
944
+
945
+ - **Double-seed connect race no longer duplicates the document.** Two
946
+ peers that each found an empty room and seeded the same file before
947
+ syncing used to merge into a perfectly-synced, perfectly-duplicated
948
+ document. Every seed now records a claim in the same transaction as
949
+ its content, and any peer that sees two claims deterministically
950
+ removes the losing seed's content — idempotent, convergent, and
951
+ content added after a seed is never touched. `seedYDocFromFile` is
952
+ now genuinely safe to call on every connection: a later call also
953
+ heals an already-raced room, and every live editor session repairs
954
+ one the moment the second claim syncs in.
955
+ - **Editing no longer rewrites document properties.** A structural edit
956
+ (or a rejected tracked change) permanently dropped the imported core
957
+ properties from the live model, so every later export regenerated
958
+ `docProps/core.xml` with an "Un-named" creator, the title removed,
959
+ and the creation date reset to export time. Core properties now
960
+ survive every model rebuild, and when core.xml IS legitimately
961
+ regenerated it is a faithful merge: `cp:revision` round-trips and
962
+ fields the original never had are not invented.
963
+ - **`docProps/app.xml` passes through untouched.** It is never
964
+ regenerated (preserving Application/Company/TotalTime) and never
965
+ added to a package that did not have one.
966
+
967
+ ### Added
110
968
 
111
- ## 3.1.1
969
+ - **`repairSeedRace(ydoc)`** on the backend entry (with
970
+ `SeedRaceRepairResult`): detect and repair a double-seed race on
971
+ demand. Editor sessions and `seedYDocFromFile` run it for you.
112
972
 
113
973
  ### Changed
114
974
 
115
- - **The agent skill is `revise-cli`.** `revise skill install` writes
116
- `.agents/skills/revise-cli/` (or `.claude/skills/revise-cli/`) and replaces
117
- the `revise/` folder earlier versions installed. As plugins it's
118
- `cli@revise`: `claude plugin install cli@revise`,
119
- `codex plugin add cli@revise`, or
120
- `npx skills add reviseio/skills --skill revise-cli`.
975
+ - **New reserved top-level key in shared documents: `"seed-claims"`**
976
+ (see `RESERVED_DOCUMENT_KEYS`) — where seed claims live.
977
+
978
+ ## 2.0.0-alpha.3
121
979
 
122
- ## 3.1.0
980
+ ### Fixed
981
+
982
+ - **Backspace before a chip deleted the chip.** A preserved-object chip
983
+ has two caret stops — before and after — and a delete now respects
984
+ which side the caret is on, like a caret between two characters:
985
+ backspace at the before-stop targets the block BEFORE the chip (an
986
+ atomic neighbor is deleted whole, a text neighbor loses its last
987
+ character), and forward delete at the after-stop targets the block
988
+ after. Deletes pointing AT the chip still remove it.
989
+ - **Up/down arrows at a chip slid the caret to the chip's other side**
990
+ instead of changing lines. Vertical movement now leaves the chip's
991
+ line and lands on the neighboring block's stop nearest the caret's
992
+ column — arrowing through a stack of chips keeps the caret on the
993
+ same side all the way down.
994
+
995
+ ## 2.0.0-alpha.2
996
+
997
+ ### Fixed
998
+
999
+ - **Exporting .docx could crash in production builds of the host app**
1000
+ ("Cannot destructure property 'default' … as it is undefined" from
1001
+ the converter's zip loader). The SDK's build emitted duplicate
1002
+ interop chunks for its zip dependency behind dynamic imports, and
1003
+ some consumer bundlers resolved one family to `undefined` when
1004
+ producing production builds — development builds were unaffected,
1005
+ which is why the crash only appeared after deployment. The dependency
1006
+ is now a static import inside the (still lazily loaded) converter
1007
+ modules: the load profile is unchanged and the chunk graph no longer
1008
+ depends on the host bundler's interop handling.
1009
+ - **Backspace in an empty paragraph directly after a chip deleted the
1010
+ chip** instead of the paragraph. Preserved payloads are content the
1011
+ source file owns, not editor furniture: the empty paragraph dies, the
1012
+ chip survives. (Page and section breaks keep their old
1013
+ consume-on-backspace behavior.)
1014
+ - **Chips gained real before/after caret stops.** The caret can now be
1015
+ placed on either side of a chip — arrow keys walk across it, and
1016
+ clicking the left or right half of the chip places the caret on the
1017
+ matching side.
1018
+
1019
+ ## 2.0.0-alpha.1
1020
+
1021
+ Prerelease for evaluation. The 2.0 line's headline is DOCX source
1022
+ fidelity: a document imported from .docx can now leave the editor as the
1023
+ file it came from, not a reconstruction of it.
123
1024
 
124
1025
  ### Added
125
1026
 
126
- - **`--blocks` on `changes`, `accept`, and `reject`.** Select tracked
127
- changes by block: ids (`--blocks a1B2c3,d4E5f6`) or a range in document
128
- order (`--blocks a1B2c3..d4E5f6`). Ids of list items, table cells, and
129
- paragraphs inside them work. In the library: `{ blocks: [...] }`, with
130
- ranges as `{ from, to }`.
131
- - **`--view tracked|accepted|original`** on `read`, `grep`, `search`,
132
- `export`, and `convert`. `read` now shows pending changes inline as
133
- `<del>` and `<ins>` with their change ids and authors; `grep` and `search`
134
- find text on both sides of a change and say which side it's on. `export`
135
- and `convert` with `--view original` write the document as it was before
136
- every pending change. `--final` still means `--view accepted`.
137
- - **`replace-all --ignore-case` and `--exact`.**
1027
+ - **DOCX source-fidelity mode (default on).** Importing a .docx keeps the
1028
+ original package inside the document (the "carrier", shared documents
1029
+ included, capped at 25MB). On export, content you did not touch is
1030
+ emitted as the exact bytes that arrived — byte-for-byte, unannotated —
1031
+ and only changed content is regenerated. A verification stage inspects
1032
+ every composed package and falls back to full regeneration rather than
1033
+ ship anything it cannot verify.
1034
+ - **`handle.getSourceFidelity()`** (and `ydocSourceFidelity(ydoc)` /
1035
+ `documentToDocx(doc, { originalDocx })` on the backend entry) reports
1036
+ the honest relationship of the next export to the original file:
1037
+ `"exact"` (byte-identical), `"grafted"` (original bytes plus your
1038
+ edits), or `"converted"` (no usable original; the report says why).
1039
+ - **Unmodeled Word formatting survives editing.** Run, paragraph, table,
1040
+ row, cell, and section properties the editor does not model (vendor
1041
+ effects such as `w14:glow`, revision-save ids, row heights, table
1042
+ look flags, page borders, note-numbering properties…) are carried
1043
+ through the model and re-emitted — so an EDITED paragraph keeps them
1044
+ too, with or without the carrier.
1045
+ - **Preserved objects render as labeled chips.** OLE embeds (Excel,
1046
+ Visio), SmartArt without a raster fallback, and unknown OOXML
1047
+ constructs import as atomic blocks labeled with their source tag
1048
+ (e.g. "w:object · Excel.Sheet.12"), render as chips on canvas and in
1049
+ PDF export, and re-export verbatim. In agent HTML they appear as
1050
+ `<docx-raw id tag/>`: an agent can keep, move, or omit one
1051
+ (omission deletes), but can never inject raw OOXML of its own.
1052
+ - **Editable-region permissions preserved.** `w:permStart`/`w:permEnd`
1053
+ pairs (and future paired ranges) survive import, editing, and export
1054
+ with balance guaranteed by construction: typing inside extends the
1055
+ region, deleting its text retires it, and unbalanced pairs in source
1056
+ files are repaired at import.
138
1057
 
139
1058
  ### Changed
140
1059
 
141
- - **`replace-text` is now `replace-all`** (`replaceAll` in the library). It
142
- replaces in page headers and footers and in footnotes and endnotes as well
143
- as the body, and says where. Curly and straight quotes, no-break and plain
144
- spaces, and no-break and plain hyphens match each other unless `--exact`,
145
- and the replacement keeps the document's characters: `"net 30"` →
146
- `"net 45"` keeps its no-break space. Matches it leaves alone, like other
147
- capitalization, are reported as `nearMisses`. `replace-text` and
148
- `replaceText` still work, and JSON output run under `replace-text` still
149
- names it.
150
- - **`--section` is a heading and everything under it.** `--section 8`
151
- includes 8.1 and 8.2. Numbers match whether typed or Word's automatic
152
- numbering. A title matches in full, or by text in only one heading; text in
153
- several headings is an error (`section_ambiguous`), and a section that
154
- doesn't exist is `section_not_found` instead of an empty result.
155
- - **Clearer flag names:** `new --content` (was `--from`), `new --page-size`
156
- (was `--page`), `search --results-page` (was `--page`), and `--blocks` for
157
- block ids on `read` and `replace-all` (was `--ids`). The old names still
158
- work.
159
- - **`changes` lists header, footer, and note changes as such** ("Header",
160
- "Footnote 1"), with their text.
161
-
162
- ### Fixed
163
-
164
- - **Word-numbered headings.** Headings numbered by Word's heading styles, how
165
- most contracts number clauses, are headings again: `outline` lists them
166
- with their numbers ("8.1 Cap on liability") and `--section 8` finds them.
167
- - **Comparing numbered documents.** Two copies of the same numbered document
168
- compare as unchanged, instead of every numbered clause deleted and
169
- reinserted.
170
- - **Comparing against a file revise edited.** A one-word edit compares as a
171
- one-word change, not a whole paragraph replaced: editing a paragraph no
172
- longer adds fonts and sizes to it or its neighbors.
173
- - **Tracked changes in headers and footers** are saved as Word revisions, and
174
- ones made in Word open as pending changes.
175
- - **Markdown export** numbers nested list items per level (8.1 was written
176
- as "9."), and writes numbered headings as headings: `## 8.1 Cap on
177
- liability`.
178
-
179
- ## 3.0.1
180
-
181
- ### Fixed
182
-
183
- - **Windows-1252 text on Node 20.** Text that isn't UTF-8, like a .txt file
184
- from a Windows editor piped to `convert`, and RTF files read € “ ” ‘ ’ – —
185
- and the other characters Windows-1252 stores in bytes 0x80–0x9F as
186
- invisible control characters. Node 22 and later were not affected.
187
-
188
- ## 3.0.0
189
-
190
- The first release of `revise` as a command-line tool and TypeScript library
191
- for reading, editing, and redlining Word documents.
192
-
193
- Versions 2.x of this package were the Revise editor for React. The editor is
194
- now [`@reviseio/editor`](https://www.npmjs.com/package/@reviseio/editor); 2.x
195
- stays installable.
196
-
197
- ### Added
198
-
199
- - **The `revise` CLI.** Read a document as HTML with block ids, search it,
200
- edit it with the same tools the Revise agent uses, and save the file in
201
- place, as tracked changes by default in .docx. Review with `changes`,
202
- `diff`, `accept`, and `reject`; `undo` and `restore` work across edits;
203
- `render` draws pages as images; `export`, `convert`, `compare`, and `new`
204
- write .docx, PDF, Markdown, HTML, and text. `convert` also works in a
205
- pipe: `-` reads stdin (the format is recognized from its bytes) or writes
206
- stdout. `--out new.docx` on an edit saves the result as a new file and
207
- leaves the original as it is. Every command has its own
208
- `--help`, and colored output on a terminal (not in pipes unless
209
- `FORCE_COLOR` is set; never with `--json`).
210
- - **`--json` on every command**: one envelope (`schema`, `ok`, `command`,
211
- `meta`, `data`, `warnings`, `error`) with stable error codes, structured
212
- partial results, and exit codes that say whether anything was saved.
213
- Specified in [JSON output](https://revise.io/developer/docs/revise/json) and shipped as a JSON Schema,
214
- `revise/cli-output.schema.json`.
215
- - **`ReviseDocument`**, the same operations as a library: open a file or
216
- bytes, run typed tools, review changes, export with a fidelity report,
217
- and snapshot and restore state.
218
- - **`agentTools(doc, { provider })`**: the editing tools in the shapes the
219
- Anthropic and OpenAI SDKs expect, with a matching result formatter.
220
- - **Collaboration rooms.** `seedYDoc(room, file)` seeds a sync server's
221
- Y.Doc on every connection (idempotent, repairs two peers that seeded at
222
- once, keeps the original Word file in the room), and
223
- `ReviseDocument.fromYDoc(room)` edits and exports a live room.
224
- - **Word fidelity.** Untouched content in a .docx exports byte for byte;
225
- `xml` commands read and patch the raw package for what the tools don't
226
- cover (styles, numbering, settings).
227
- - **An agent skill**: `revise skill install` writes a SKILL.md that teaches
228
- coding agents the CLI.
1060
+ - **BREAKING: two new reserved top-level keys in shared documents** —
1061
+ `"docx-carrier"` and `"oxml-ranges"` (see
1062
+ `RESERVED_DOCUMENT_KEYS`). A host-built Y.Doc already using these
1063
+ names is rejected by `assertUsableSharedDocument`.
1064
+ - **BREAKING: docx-sourced exports are byte-preserving by default.**
1065
+ 1.x regenerated every export from the model; 2.0 reproduces original
1066
+ bytes for untouched content. Hosts that depended on exports being
1067
+ normalized into the generated dialect should convert explicitly.
1068
+ - `ReviseDocument` block children may now include the `"docx-raw"`
1069
+ node type (opaque; convert rather than inspect, as ever).
1070
+ - Shared documents built from a .docx are larger by roughly the size of
1071
+ the source file (the carrier). It is stored once, chunked, and synced
1072
+ like any other document state.
229
1073
 
230
- ### Removed
1074
+ ## 1.3.1
1075
+
1076
+ ### Fixed
1077
+
1078
+ - **Delegated page inspection now reaches the embedded editor canvas.** The
1079
+ SDK connects the delegated agent's `render_document_pages` tool to the
1080
+ mounted document renderer, so appearance and layout requests return the
1081
+ actual pages instead of reporting that canvas inspection is unavailable.
1082
+ - **Agent-tool documentation now matches the generated SDK catalog.** The
1083
+ public docs use the canonical `remove_blocks` name, distinguish the
1084
+ deterministic document-local tool subset from delegated-agent-only tools,
1085
+ and explain where visual page inspection is available.
1086
+
1087
+ ## 1.3.0
1088
+
1089
+ ### Added
1090
+
1091
+ - **The built-in editor UI now localizes itself in English, Spanish, and
1092
+ German.** Ribbon controls, menus, dialogs, comments, Review mode, and agent
1093
+ chrome follow the browser language or the persisted Revise UI-language
1094
+ preference, while English remains the fallback if a locale chunk cannot be
1095
+ loaded.
1096
+ - **The delegated browser agent can inspect the document's rendered pages.**
1097
+ It can request bounded appearance contact sheets or layout diagnostics from
1098
+ the real canvas renderer, including page geometry, tables, images, math,
1099
+ headers, footers, and safe placeholders for unavailable visual assets.
1100
+
1101
+ ### Changed
1102
+
1103
+ - **Tab editing and layout now follow Word-style paragraph behavior.** Tab and
1104
+ Shift+Tab at the start of a block keep indenting or outdenting, while either
1105
+ key inside paragraph text inserts a tab. Long tabbed lines wrap at word
1106
+ boundaries, restart their ruler on each visual line, and preserve custom,
1107
+ aligned, leader, and right-to-left tab stops.
1108
+
1109
+ ### Fixed
1110
+
1111
+ - **DOCX named styles remain stable through editing and repeated round trips.**
1112
+ Imported paragraph styles and document defaults now drive newly created
1113
+ headings and agent-created styled blocks, survive Yjs persistence, suppress
1114
+ redundant direct formatting on export, and converge without accumulating
1115
+ unused generated Word styles. Explicit formatting resets, borders, spacing,
1116
+ fonts, and styles inside table cells remain intact.
1117
+ - **Agent document measurements reconcile pending Review changes.** Primary
1118
+ totals consistently measure the final, as-if-accepted document and include
1119
+ the original review projection when pending suggestions make the visible
1120
+ word or character count differ.
1121
+
1122
+ ## 1.2.0
1123
+
1124
+ ### Added
1125
+
1126
+ - **International text support now extends across the editing and conversion
1127
+ pipeline.** Unicode-aware line breaking, search, list numbering, font
1128
+ fallback, and IME composition preserve multilingual text more reliably, and
1129
+ text import now detects UTF-8 and UTF-16 files. HTML, DOCX, RTF, ODT, and
1130
+ plain-text conversions keep the expanded script coverage intact.
1131
+ - **Orange and purple join the SDK highlight palette.** The editor UI,
1132
+ `find_highlights`, `style_blocks`, agent HTML, and DOCX round trips now
1133
+ share the same seven canonical highlight colors.
1134
+ - **Agent styling covers richer document structures.** `style_blocks` adds
1135
+ span, descendant-wildcard, first-row, and named-paragraph-style selectors,
1136
+ with durable mappings for image sizing and alignment, paragraph borders,
1137
+ nested tables and lists, per-edge cell borders, cell fills, padding, and
1138
+ table-cell text styles.
1139
+
1140
+ ### Fixed
1141
+
1142
+ - **DOCX import follows Word's effective paragraph and table styling.**
1143
+ Unstyled paragraphs inherit the document's default style; exact and
1144
+ at-least line rules use the resolved font size; paragraph before/after and
1145
+ contextual spacing replace the editor's fallback gap; missing table borders
1146
+ remain borderless; and non-uniform cell margins survive import. The imported
1147
+ spacing persists through Yjs, paragraph splits and merges, HTML, DOCX, and
1148
+ PDF output, keeping compact Word layouts from growing onto extra pages.
1149
+ - **Unavailable Word fonts use the document's own substitution hints.** DOCX
1150
+ import reads `fontTable.xml` alternate names and PANOSE/family/pitch
1151
+ metadata, persists them with the document, and chooses metric-compatible
1152
+ fallbacks before resorting to a generic family.
1153
+ - **Multilingual PDF export embeds and shapes the scripts it needs.** Chinese,
1154
+ Japanese, Korean, Indic, Southeast Asian, Tibetan, Ethiopic, Armenian,
1155
+ Georgian, Syriac, Thaana, symbols, emoji, and rare Han use bundled lazy
1156
+ fallback faces, while a hidden logical-text layer preserves search and text
1157
+ extraction.
1158
+ - **Agent edits preserve complex formatting and pending review state.** Styled
1159
+ tables, nested content, list-item formatting, explicit text overrides,
1160
+ comments, and edits layered over pending insertions now survive preview,
1161
+ acceptance, and rejection without duplicating or flattening structure.
1162
+ - **Borderless layout tables stay visually borderless while editing.** The
1163
+ canvas now reveals only the specific invisible vertical edge under a resize
1164
+ pointer instead of ghosting the table's entire grid on hover or focus.
1165
+ - **Imported pale-yellow highlights remain highlights.** HTML clipboard import
1166
+ no longer remaps Word's pale yellow to the editor's green palette entry.
1167
+
1168
+ ## 1.1.0
1169
+
1170
+ ### Added
1171
+
1172
+ - **First-class right-to-left editing.** The built-in toolbar can set paragraph
1173
+ and list direction to automatic, LTR, or RTL. Mixed Hebrew, Arabic, and
1174
+ left-to-right text now uses bidi-aware line layout, visual arrow-key
1175
+ movement, stable caret and selection geometry, direction-aware alignment and
1176
+ indents, mirrored list markers, and RTL tab stops. Direction survives Yjs,
1177
+ clipboard and agent edits, HTML, and DOCX round trips; PDF export preserves
1178
+ mixed-direction reading order and positioning.
1179
+ - **Multi-column sections.** Page layout now supports one, two, or three
1180
+ newspaper-style columns with a configurable gap. Continuous section breaks
1181
+ balance their final columns, while page and next-page sections keep ordinary
1182
+ pagination. The canvas editor and PDF export share the flow rules, DOCX and
1183
+ HTML import/export preserve the settings, and `set_page_layout` exposes
1184
+ `columnCount`, `columnGap`, and section-scoped updates to browser and
1185
+ server agent sessions.
1186
+ - **Native document-structure tools.** `insert_block` can create a live table
1187
+ of contents with `<toc levels="3"></toc>`. The canonical
1188
+ `remove_blocks` tool can delete a counted range, exact IDs, a saved search
1189
+ result, or an explicitly authorized document tail with `through_end`.
1190
+
1191
+ ### Changed
1192
+
1193
+ - **Agent tool sessions avoid unproductive read cycles.** Sequential reads now
1194
+ reject windows containing only blocks already returned in the same request
1195
+ with `no_new_read_context`; `read_specific_blocks` remains available for
1196
+ intentional revisits. `remove_blocks` is now the model-facing name, while
1197
+ the previous `remove_block` name remains an executable compatibility alias.
1198
+
1199
+ ### Fixed
1200
+
1201
+ - **Strict-provider nulls behave like omitted optional tool fields.** Browser
1202
+ and server tool execution normalize provider-materialized `null` values
1203
+ from the generated schema before dispatch, without stripping required or
1204
+ deliberately nullable values. Optional layout and mutation inputs therefore
1205
+ no longer take invalid branches merely because a provider filled them in.
1206
+ - **Agent-generated Unicode escapes become the intended text.** Literal
1207
+ `\uXXXX` sequences in agent HTML and replacement paths are decoded without
1208
+ disturbing escaped backslashes or code spans, preventing visible escape text
1209
+ in edited documents.
1210
+ - **Review decisions preserve the reader's place.** Accepting or rejecting a
1211
+ tracked change no longer forces the embedded editor to scroll back to the
1212
+ active suggestion.
1213
+ - **SDK PDF export keeps Hebrew and Arabic text self-contained.** The package
1214
+ now bundles the Noto fallback faces used by RTL export, so embedding hosts do
1215
+ not need to mirror Revise's public font directory to avoid dropped glyphs.
1216
+
1217
+ ## 1.0.1
1218
+
1219
+ ### Fixed
1220
+
1221
+ - **Malformed model input can no longer crash a host's agent loop.** A bare
1222
+ string where `search_document` expects a `queries` array — the most
1223
+ common model slip — threw a raw `TypeError` out of `execute()` /
1224
+ `executeDynamic()` instead of returning a structured failure. Bare
1225
+ strings are now coerced to one-element arrays (also for
1226
+ `read_specific_blocks`' `block_ids`), anything uncoercible fails
1227
+ structurally, and both surfaces gained a safety net that converts an
1228
+ unexpected handler throw into an `internal_error` result. The documented
1229
+ contract — expected failures as results, only environment errors reject —
1230
+ now holds for arbitrary input.
1231
+ - **Invalid enum values no longer mutate the wrong target silently.** An
1232
+ insert tool called with `position: "above"` placed content _after_ the
1233
+ reference block while reporting success, and `set_header_footer` with a
1234
+ misspelled or missing `side` edited the header. Both now return a
1235
+ structured failure naming the valid values.
1236
+
1237
+ ## 1.0.0
1238
+
1239
+ One package, one tool contract. The browser and server surfaces now speak
1240
+ the same canonical envelope, so host result-handling code is shared verbatim
1241
+ between web and Node. That convergence is breaking on the browser side —
1242
+ every change is listed below.
1243
+
1244
+ ### Breaking
1245
+
1246
+ - **`tools.execute()` returns the canonical discriminated envelope.** The
1247
+ flat `{ toolCallId, name, success, error?, agentFeedback?, output?,
1248
+ documentContent? }` result is gone. Both surfaces now return
1249
+ `{ ok: true, value: { callId, tool, message, data, context, suggestionIds } }`
1250
+ or `{ ok: false, error: { callId, tool, code, message } }`
1251
+ (`ReviseToolResult`). Field mapping: `toolCallId → value.callId`,
1252
+ `name → value.tool`, `agentFeedback → value.message`,
1253
+ `output → value.data`, `documentContent → value.context.html`;
1254
+ `view_image`'s attachment lives on `value.image`.
1255
+ `ReviseEditorToolExecutionResult` no longer exists.
1256
+ - **`tools.execute()` is typed and no longer routes `document_id`.**
1257
+ `execute()`/`call()` take the generated per-tool input types and
1258
+ cover the shared 24-tool contract; untrusted model calls — including the
1259
+ browser-only `get_selection`, `view_image`, and
1260
+ `revise_run_agent`, and model-facing `document_id` routing — go
1261
+ through the new `executeDynamic()`, exactly as on the server.
1262
+ - **Unknown tools and role denials are results, not throws.** `execute()`
1263
+ returns `{ ok: false }` with `code: "unknown_tool"` or
1264
+ `"role_not_permitted"` instead of throwing; the new `tools.call()`
1265
+ throws a typed `ReviseToolError` for hosts that prefer exceptions.
1266
+ `ReviseRoleError` is still thrown by `agent.run()` and UI
1267
+ controllers.
1268
+ - **ID-keyed suggestion decisions return per-ID outcomes.**
1269
+ `review.acceptSuggestions`/`rejectSuggestions`,
1270
+ `review.acceptCommentSuggestions`/`rejectCommentSuggestions`, and
1271
+ `tools.acceptAllSuggestions`/`rejectAllSuggestions`, and the server
1272
+ session's `acceptSuggestions`/`rejectSuggestions` return
1273
+ `{ resolved, missing, unresolved }` (`ReviseSuggestionDecision`)
1274
+ instead of a bare count. Stale IDs land in `missing`; a role that may
1275
+ not resolve reports everything `unresolved`. `review.acceptAll()` /
1276
+ `rejectAll()` keep their boolean UI-gesture contract.
1277
+ - **Server sessions default to suggesting mode.** `createServerDocumentSession`
1278
+ without `mode` now proposes tracked changes instead of applying edits
1279
+ directly — the same default posture as the browser surface, and the safe
1280
+ one. Pass `mode: "editing"` (or per-call `directMode: true`) for
1281
+ direct application.
1282
+
1283
+ ### Added
1284
+
1285
+ - **Browser mutation results report created suggestion IDs.** Successful
1286
+ mutations carry `suggestionIds` — the tracked records that call created
1287
+ (empty for direct edits, `null` for read/search/measure tools) — with a
1288
+ concurrent human suggestion never attributed to the tool call. Feed them
1289
+ straight to `review.acceptSuggestions()`.
1290
+ - **The tool contract types ship from both entries.** `ReviseToolResult`,
1291
+ `ReviseToolResponse`, `ReviseToolFailure`, `ReviseToolError`,
1292
+ `ReviseSuggestionDecision`, the generated `ReviseToolInputMap`, and
1293
+ friends are exported by `@reviseio/sdk` and `@reviseio/sdk/backend`
1294
+ alike.
1295
+
1296
+ - **Server mutation results report the tracked records they created.**
1297
+ Successful mutation calls from `createServerDocumentSession` now carry
1298
+ `suggestionIds` — the tracked suggestion records that call created (empty
1299
+ for direct edits, `null` for read/search/measure tools) — so a host can
1300
+ persist per-edit IDs with its review workflow instead of diffing the
1301
+ document-global pending set.
1302
+ - **`listSuggestions()`** returns every pending suggestion as a reviewable
1303
+ record with authorship metadata (`authorType`, `agentName`,
1304
+ `agentModel`, `source`, `label`, `createdAt`), so hosts can decide on
1305
+ their own agent's suggestions and leave collaborators' pending work alone.
1306
+ - **`acceptAllSuggestions()` / `rejectAllSuggestions()`** make the
1307
+ whole-document decision an explicit, greppable call instead of the
1308
+ `acceptSuggestions(getPendingSuggestionIds())` idiom.
1309
+
1310
+ ### Fixed
1311
+
1312
+ - **Server tool types now resolve for `moduleResolution: "NodeNext"`
1313
+ consumers.** The packaged declarations re-exported the server tool contract
1314
+ through extensionless relative specifiers, which NodeNext cannot resolve —
1315
+ every tool input/output type silently degraded to `any`, and importing a
1316
+ contract type by name (e.g. `ServerDocumentSession`) failed to compile.
1317
+ The declarations now use explicit `.js` specifiers, which every supported
1318
+ resolution mode maps to the sibling `.d.ts` files.
1319
+ - **Importing a document with code blocks no longer risks crashing a Node
1320
+ host.** The canvas syntax highlighter tried to fetch its tree-sitter wasm
1321
+ under Node (the server DOM shims install a jsdom `window`, defeating its
1322
+ browser check), failing as an unhandled promise rejection. Highlighting now
1323
+ recognizes the server runtime explicitly and stays off, and a failed
1324
+ highlighter init in the browser no longer poisons later attempts.
1325
+ - **Table and list mutations no longer spam `Invalid access` warnings.**
1326
+ Building table rows, cells, and list items called Yjs `push()` on
1327
+ elements not yet integrated into a document, which logs a warning per
1328
+ child. Construction now inserts children at explicit indices — dozens of
1329
+ stderr lines per table insert in server logs, gone.
1330
+ - **Editing mode applies server edits directly again.** A server session in
1331
+ `"editing"` mode quietly recorded every mutation as a
1332
+ pending tracked suggestion instead of applying it. Editing-mode calls now
1333
+ run in the runtime's direct mode and settle within the call, matching the
1334
+ documented behavior; an explicit per-call `directMode` still overrides in
1335
+ either direction.
1336
+
1337
+ ## 0.9.0
1338
+
1339
+ ### Added
1340
+
1341
+ - **`review.listChanges()` now reports linked moves as moves.** A move pair
1342
+ surfaces as ONE `ReviseTrackedChange` with `kind: "move"`,
1343
+ `moveSourceBlockIds`/`moveDestinationBlockIds` locating each half, and
1344
+ `deletedText`/`insertedText` carrying the text as it left and as it
1345
+ arrived. Previously both halves were folded into a single change labeled
1346
+ `"delete"`, leaving a host review panel no way to distinguish a move from
1347
+ a replacement. Accept/reject semantics are unchanged: resolving the change
1348
+ settles both locations atomically.
1349
+
1350
+ ## 0.8.0
1351
+
1352
+ ### Added
1353
+
1354
+ - **Cut and paste now creates native linked moves in Suggesting mode.** Cutting
1355
+ text from supported paragraphs and pasting that same internal clipboard
1356
+ payload elsewhere in the document produces one atomic “Moved from”/“Moved
1357
+ here” pair. Accepting or rejecting either half resolves both locations, undo
1358
+ cannot strand an orphaned half, and DOCX export/reimport preserves native
1359
+ linked move markup. Copy/paste, editing mode, reused or mismatched clipboard
1360
+ payloads, and unsupported structural selections continue to use ordinary
1361
+ insertion/deletion behavior.
1362
+
1363
+ ## 0.7.0
1364
+
1365
+ ### Added
1366
+
1367
+ - **Server-side semantic tools.** `await createServerDocumentSession(ydoc,
1368
+ { documentId, mode })` in `@reviseio/sdk/backend` binds the canonical
1369
+ document-local agent tools — read, search, measure, mutate, layout,
1370
+ footnotes, tables, comments — to a host-owned Y.Doc under plain Node.
1371
+ `mode: "suggesting"` produces Word-compatible tracked changes with
1372
+ accept/reject; concurrent calls are serialized; literal tool calls infer
1373
+ their schema inputs and structured outputs. See the README's "Server semantic
1374
+ tools" section.
1375
+ - **Linked Word moves now round-trip as atomic move suggestions.** DOCX import
1376
+ pairs native `w:moveFrom` and `w:moveTo` ranges across runs, paragraphs,
1377
+ and table cells. Accepting either half keeps the text at its
1378
+ destination; rejecting either half restores its original location; export
1379
+ re-emits native paired move markup. Suggestion cards distinguish “Moved from”
1380
+ and “Moved here”, and focusing either half highlights its partner even across
1381
+ paragraphs.
1382
+
1383
+ ### Fixed
1384
+
1385
+ - **Node-side DOCX imports preserve tracked table-row revisions without a
1386
+ browser `FileReader`.** The backend DOM shims and table-revision
1387
+ postprocessor now work from `Blob.arrayBuffer()`, retaining row insertion
1388
+ and deletion metadata in server integrations.
1389
+ - **Word comment anchors preserve their identity and semantic range.** Safe
1390
+ native numeric IDs no longer shift, cross-paragraph and table-cell ranges
1391
+ emit one anchor triple instead of duplicates, and collapsed, overlapping,
1392
+ threaded, and resolved comments survive repeated round trips.
1393
+ - **Visible drawing text survives DOCX import when shape geometry is
1394
+ flattened.** Inline and anchored DrawingML, grouped shapes, legacy VML,
1395
+ headers, and standards-valid `mc:AlternateContent` Choice/Fallback content
1396
+ become editable paragraphs in reading order without duplicate fallback text.
1397
+ - **DOCX archives no longer inflate and large imports avoid repeated work.**
1398
+ Generated packages use DEFLATE compression, parse the main document XML once,
1399
+ and skip move indexing when a file has no moves, preventing the reported
1400
+ multi-fold output growth and superlinear no-move scan.
1401
+
1402
+ ## 0.6.0
1403
+
1404
+ ### Added
1405
+
1406
+ - **Horizontal rules and ornamental dividers are now supported throughout the
1407
+ editor.** Insert thin, thick, double, dashed, dotted, star, or diamond
1408
+ dividers from the toolbar or context menu, or create them with text triggers
1409
+ such as `---`, `===`, `-**-`, and `-<>-`. DOCX, HTML, Markdown, agent HTML,
1410
+ PDF, and plain-text output preserve the divider where the format permits;
1411
+ DOCX, HTML, Markdown, RTF, and ODT imports recognize their native divider or
1412
+ paragraph-border representations.
1413
+
1414
+ ### Changed
1415
+
1416
+ - **Em-dash autocorrection now waits for a word boundary.** Typing `--` remains
1417
+ literal until Space or Enter, allowing `---` to be used for horizontal-rule
1418
+ insertion and preserving word-initial values such as `--flag`.
1419
+
1420
+ ### Fixed
1421
+
1422
+ - **Words no longer wrap in the middle at formatting or tracked-change run
1423
+ boundaries.** A word split across differently styled text nodes now wraps as
1424
+ one unit and keeps a stable layout when suggestions are accepted.
1425
+ - **Suggestion editing produces stable runs and caret placement.** Continued
1426
+ typing or backspacing merges into the existing suggestion instead of creating
1427
+ one run per keystroke, replacement normalization no longer leaves the caret
1428
+ inside hidden deleted text, and Enter after a pending deletion creates the
1429
+ expected paragraph or list item without moving the deleted content.
1430
+ - **Structural editing keeps the expected document shape and keyboard focus.**
1431
+ Backspace exits or splits empty list items correctly, compatible lists rejoin
1432
+ when their separating empty paragraph is removed, Enter at the start of a
1433
+ leading heading or code block creates a body paragraph above it, and toolbar
1434
+ commands no longer steal keyboard focus from the editor.
1435
+
1436
+ ## 0.5.1
1437
+
1438
+ ### Fixed
1439
+
1440
+ - **PDF table-of-contents page numbers stay accurate when a heading moves to
1441
+ the next page.** Export now records a heading's destination after paragraph
1442
+ pagination, so a keep-with-next or end-of-page preflight cannot leave the
1443
+ TOC pointing at the page the heading would have occupied before it moved.
1444
+
1445
+ ## 0.5.0
1446
+
1447
+ ### Added
1448
+
1449
+ - **Comments now work on list items, including nested items.** Selecting list
1450
+ text, expanding a word from the caret, and commenting on a whole item all
1451
+ create item-local anchors. Returning the caret to that text activates the
1452
+ thread, list-item threads survive agent-HTML round trips, and the
1453
+ `leave_comment` agent tool accepts list-item IDs.
1454
+
1455
+ ### Changed
1456
+
1457
+ - **PDF export now follows the editor's layout and print semantics much more
1458
+ closely.** It shares wrapping and pagination rules for tab stops and
1459
+ leaders, hyphenation, keep-with-next, keep-lines, widows and orphans, code
1460
+ blocks, nested tables, footnotes, page and section breaks, live TOC page
1461
+ numbers, line numbers, and watermarks. Editor-only placeholders and review
1462
+ chrome are not printed, and Word hidden text remains hidden in ordinary PDF
1463
+ output. The SDK now carries its metric-compatible PDF fonts itself, so an
1464
+ embedding host does not need to mirror Revise's public font directory.
1465
+ - **Agent tool sessions reject redundant full-document read loops.** After a
1466
+ session has read the complete document, another sequential `read_document`
1467
+ returns `no_new_read_context`; agents can still revisit known content with
1468
+ `read_specific_blocks`.
1469
+
1470
+ ### Fixed
1471
+
1472
+ - **DOCX formatting exceptions survive a complete edit and export cycle.**
1473
+ Explicit run-property clears over named styles, zero paragraph indents,
1474
+ paragraph border and shading clears, decimal font sizes, and mixed small-cap
1475
+ and all-cap overrides now remain distinct from inherited formatting and do
1476
+ not leak into adjacent text.
1477
+ - **Complex Word structures no longer lose modeled content on re-export.**
1478
+ Internal bookmark links stay internal; exact table widths, columns,
1479
+ alignment, cell padding, and vertical alignment survive; nested tables keep
1480
+ the paragraphs around them; display equations are not flattened when a file
1481
+ is immediately re-exported; and multi-block footnotes and endnotes can retain
1482
+ their lists and tables.
1483
+ - **Accepting or rejecting a compound agent edit is atomic.** Mixed text,
1484
+ formatting, and structural suggestions are resolved together, so accepting
1485
+ a rewrite no longer retains deleted fragments and rejecting it restores the
1486
+ original content and formatting.
1487
+ - **Comment cards stay where users put them.** A previously active card no
1488
+ longer drifts with the viewport, and selecting text inside a card no longer
1489
+ jumps focus back to the document or clears the selection. Inline code in
1490
+ comment bodies is also styled as code.
1491
+ - **Package managers can no longer omit the Yjs runtime.** Every editor session
1492
+ is Yjs-backed even without a collaboration provider, so `yjs` and
1493
+ `y-protocols` are now required peers instead of optional peers. This makes
1494
+ package managers install or validate them instead of letting bundlers
1495
+ substitute empty optional-peer modules and fail the consumer build.
1496
+
1497
+ ## 0.4.5
1498
+
1499
+ ### Fixed
1500
+
1501
+ - **Starting a list no longer drops the font.** Typing a list trigger
1502
+ (`- `, `1. `, `[] `) in a paragraph set in a non-default font produced
1503
+ a list item that fell back to the default font: clearing the trigger text
1504
+ left an empty item with nowhere to carry its formatting. The formatting at
1505
+ the trigger's trailing edge — the font family included — is now preserved
1506
+ on the empty item and applies to the next character typed.
1507
+
1508
+ ## 0.4.4
1509
+
1510
+ ### Fixed
1511
+
1512
+ - **Suggestion cards now hang from the suggested text.** The floating
1513
+ accept/reject card anchored to the caret; it now follows the suggested
1514
+ fragment (or your selection) and sits centered below its line, the same
1515
+ placement the revise.io app uses, falling back to the caret only when the
1516
+ fragment cannot be measured. Wide cards are clamped to the page edges
1517
+ instead of a fixed margin.
1518
+
1519
+ ## 0.4.3
1520
+
1521
+ Identical in content to 0.4.2; republished.
1522
+
1523
+ ## 0.4.2
1524
+
1525
+ ### Fixed
1526
+
1527
+ - **Word-level diffs misplaced edits next to repeated words.** When the text
1528
+ adjacent to an edit repeated a word from the edit itself (replacing
1529
+ "[Berkshire County / appropriate Massachusetts county]," with "Suffolk
1530
+ County, Massachusetts," just before "Massachusetts will"), the unchanged
1531
+ suffix could be drawn as deleted and retyped. Unchanged repeated words now
1532
+ stay anchored as unchanged, in tracked changes and the diff view alike.
1533
+ - **Writing a comment no longer collapses the comments margin.** Finishing a
1534
+ draft that had itself opened the margin always collapsed it — even when
1535
+ submitting had just created a thread, so the pages jerked sideways in both
1536
+ directions and hid the card the user just wrote. The margin now stays open
1537
+ on the new thread; only an abandoned draft with no other open thread
1538
+ collapses it.
1539
+ - **Comment card placement around drafts and tracked changes.** A comment
1540
+ draft started while hovering the card stack could pin its card — and drag
1541
+ the viewport — to the top of page 1; it now anchors where the draft was
1542
+ made. A caret inside a resolved thread's highlight, or inside an imported
1543
+ thread's replies, activated no card at all; it now activates the right
1544
+ open thread. And when a commented paragraph also contains tracked changes,
1545
+ the card describes the change under the cursor instead of jumping to the
1546
+ top of the paragraph.
1547
+ - **The selection card no longer chases the pointer mid-drag.** While the
1548
+ mouse button is down nothing pops up under the pointer; the card appears
1549
+ on release, anchored below the selection the user meant.
1550
+
1551
+ ## 0.4.1
1552
+
1553
+ ### Fixed
1554
+
1555
+ - **Opening the export menu crashed.** An icon component in the export menu
1556
+ referenced React without importing it, which the packaged build has no
1557
+ global to fall back on.
1558
+
1559
+ ## 0.4.0
1560
+
1561
+ ### Changed
1562
+
1563
+ - **The default entry no longer ships Tree-sitter syntax highlighting or the
1564
+ embedded WASM payload.** Code blocks still render as code, and every WASM
1565
+ hot path has a TypeScript implementation. This keeps the normal
1566
+ integration smaller and compatible with strict Content Security Policies.
1567
+ Optional features now load as async chunks inside the package.
1568
+
1569
+ ### Added
1570
+
1571
+ - **`@reviseio/sdk/full`** — an opt-in entry point that keeps token-colored
1572
+ code blocks and the WASM hot paths. The API and stylesheet are identical
1573
+ between the two entries.
1574
+
1575
+ ## 0.3.4
1576
+
1577
+ ### Fixed
1578
+
1579
+ - **The SDK no longer attempts any telemetry.** Earlier builds emitted
1580
+ editor health metrics toward a Revise backend that does not exist in your
1581
+ deployment, which could only fail — loudly, as console CORS errors — and
1582
+ represented network calls you never asked for. Telemetry is now something
1583
+ only the revise.io application itself can switch on; embedded editors
1584
+ send nothing anywhere: no metric POSTs, no analytics vendor code, no
1585
+ beacons.
1586
+
1587
+ ### Added
1588
+
1589
+ - **`onAnalyticsEvent`** — the editor's own instrumentation, delivered to
1590
+ the host instead:
1591
+ `<ReviseEditor onAnalyticsEvent={(event, properties) => ...} />`.
1592
+ Forward events to your own analytics service; a throwing handler never
1593
+ breaks the editor. Event names and property shapes are internal and
1594
+ version-unstable.
1595
+
1596
+ ## 0.3.3
1597
+
1598
+ Four suggesting-mode fixes, two of them content corruption. If your users
1599
+ edit in `suggesting` mode — the mode this SDK exists for — take this
1600
+ release.
1601
+
1602
+ ### Fixed
1603
+
1604
+ - **Pasting in suggesting mode corrupted the document.** The paste path
1605
+ predated suggesting mode: it duplicated the rest of the paragraph and
1606
+ inserted the pasted text without tracked-change marks, so the paste was
1607
+ invisible to review and survived reject. Pasting is now recorded exactly
1608
+ as if the pasted characters had been typed — an insertion suggestion, plus
1609
+ a deletion suggestion for any replaced selection.
1610
+ - **Formatting across a pending change destroyed it.** Applying bold (or any
1611
+ inline format) over a range touching a pending insertion or deletion
1612
+ overwrote the change's identity; resolving the format then silently turned
1613
+ a pending insertion into accepted text, or resurrected deleted text.
1614
+ Formatting now leaves deletion spans alone, folds into insertion spans (as
1615
+ Word nests run properties inside `w:ins`), and records a reviewable
1616
+ format change only on unmarked text.
1617
+ - **Accepting a deletion that crossed a paragraph boundary left the
1618
+ paragraphs unmerged.** The boundary is now part of the suggestion, as the
1619
+ pilcrow is in Word: accepting merges the paragraphs, in any resolution
1620
+ order, for any number of paragraphs in the selection.
1621
+ - **Copying a selection inside your own pending insertion copied nothing.**
1622
+ It now copies the selected text. Clipboard payloads are also sanitized so
1623
+ tracked-change marks never travel with copied content.
1624
+
1625
+ ### Console
1626
+
1627
+ - Opening a document no longer logs to the console (previously one Yjs
1628
+ warning per block plus two internal debug lines). `console.warn` and
1629
+ `console.error` remain for genuinely actionable problems.
1630
+
1631
+ ## 0.3.2
1632
+
1633
+ ### Fixed
1634
+
1635
+ - `editor.whenReady()` was missing from the published type declarations. It
1636
+ worked at runtime, but TypeScript rejected the call the documentation tells
1637
+ you to make.
1638
+
1639
+ ## 0.3.1
1640
+
1641
+ ### Fixed
1642
+
1643
+ - Using the editor handle from `onReady` no longer throws. `onReady` fires
1644
+ before any document exists, and "subscribe to everything on ready" is the
1645
+ first thing a host writes — a subscription placed then now waits and
1646
+ attaches when a document arrives. `selection.observe()` was affected too.
1647
+ Methods that act on a document still fail loudly, and the message now names
1648
+ the fix.
1649
+
1650
+ ### Added
1651
+
1652
+ - `editor.whenReady()` — resolves once a document is open and its
1653
+ controllers are usable.
1654
+ - `REVISE_SDK_VERSION` and `REVISE_SDK_BUILD` exports, and a `bugs` entry
1655
+ in the manifest: a support ticket can name the exact build it came from.
1656
+
1657
+ ## 0.3.0
1658
+
1659
+ ### Collaboration
1660
+
1661
+ Multi-user editing over a Yjs transport you own. The editor builds the
1662
+ document; you attach the connection:
1663
+
1664
+ ```ts
1665
+ collaboration: {
1666
+ connect: (doc, awareness) =>
1667
+ new HocuspocusProvider({ url, name, document: doc, awareness }),
1668
+ synced,
1669
+ }
1670
+ ```
1671
+
1672
+ Remote carets, a presence roster (`editor.collaboration`), seed-or-join
1673
+ semantics, and validation of any document you supply. See the collaboration
1674
+ guide.
1675
+
1676
+ ### Roles
1677
+
1678
+ `role="editor" | "suggester" | "viewer"`, editor-wide or per document, and
1679
+ enforced on every surface: typing, the built-in chrome, the handle, and agent
1680
+ tool calls. A suggester cannot leave suggesting mode, apply anything directly,
1681
+ or accept and reject.
1682
+
1683
+ ### Tracked changes you can list
1684
+
1685
+ `review.listChanges()` and `review.getChange(id)` return each pending change
1686
+ with its kind, author, timestamp, affected blocks, and text — enough to build
1687
+ your own review panel. Imported Word redlines keep their original reviewers.
1688
+
1689
+ ### Server-side primitives
1690
+
1691
+ New subpath export `@reviseio/sdk/backend` (Node only): `parseDocument`,
1692
+ `fileToYDoc`, `seedYDocFromFile`, `ydocToDocx`, `encodeYDoc`/`decodeYDoc`.
1693
+ Your server can create a collaborative room from a .docx before any browser
1694
+ connects, and export a live room without one. Requires `jsdom`.
1695
+
1696
+ ### Breaking
1697
+
1698
+ - **`yjs` and `y-protocols` are now peer dependencies** and are no longer
1699
+ bundled. Install them yourself, and make sure your bundler resolves ONE copy
1700
+ — Yjs identifies its own types with `instanceof`, so a second copy breaks a
1701
+ shared document. Only collaboration needs them; they are optional peers.
1702
+ - **`ReviseDocumentInput.docx` is now optional**, since a document joining a
1703
+ collaborative room needs no source file. Inputs must supply `docx`,
1704
+ `collaboration`, or both.
1705
+
1706
+ ### Fixed
1707
+
1708
+ - `search_result_id`, which the agent tool schemas advertise for bulk edits,
1709
+ was unusable: tool state did not survive between `tools.execute()` calls.
1710
+ - `exportDocx()` omitted TOC page numbers, which only the live layout knows.
1711
+ - Exports lost imported named styles and reset core property dates in any
1712
+ non-browser environment.
1713
+ - `collaboration.synced` was read once at mount, so a host reporting sync
1714
+ later was ignored and the document never opened.
1715
+ - The margin insert-comment chip was missing from the embedded editor.
1716
+ - Presence colors: an explicit `currentUser.color` was ignored whenever the
1717
+ user had an id.
1718
+
1719
+ ## 0.2.0
1720
+
1721
+ Multi-document sessions, host-owned chrome, skinning props, per-embed
1722
+ theming, the selection controller, and comment-thread agents.
1723
+
1724
+ ## 0.1.0
231
1725
 
232
- - **The editor entry points of 2.x.** `revise/editor`, `revise/editor/full`,
233
- and `revise/server` now throw an error pointing to `@reviseio/editor`, and
234
- `revise/style.css` is an empty stylesheet that says the same.
1726
+ First release: the editor, DOCX in and out, tracked changes, comments, and
1727
+ the agent tool surface.