@agent-native/toolkit 0.4.10 → 0.5.0

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 (143) hide show
  1. package/README.md +17 -6
  2. package/dist/collab-ui/agent-identity.d.ts +9 -0
  3. package/dist/collab-ui/agent-identity.d.ts.map +1 -0
  4. package/dist/collab-ui/agent-identity.js +9 -0
  5. package/dist/collab-ui/agent-identity.js.map +1 -0
  6. package/dist/collab-ui/index.d.ts +2 -0
  7. package/dist/collab-ui/index.d.ts.map +1 -1
  8. package/dist/collab-ui/index.js +2 -0
  9. package/dist/collab-ui/index.js.map +1 -1
  10. package/dist/collab-ui/lead-client.d.ts +3 -0
  11. package/dist/collab-ui/lead-client.d.ts.map +1 -0
  12. package/dist/collab-ui/lead-client.js +29 -0
  13. package/dist/collab-ui/lead-client.js.map +1 -0
  14. package/dist/context-ui/ContextMeter.d.ts +10 -0
  15. package/dist/context-ui/ContextMeter.d.ts.map +1 -0
  16. package/dist/context-ui/ContextMeter.js +20 -0
  17. package/dist/context-ui/ContextMeter.js.map +1 -0
  18. package/dist/context-ui/ContextSegmentRow.d.ts +14 -0
  19. package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -0
  20. package/dist/context-ui/ContextSegmentRow.js +25 -0
  21. package/dist/context-ui/ContextSegmentRow.js.map +1 -0
  22. package/dist/context-ui/ContextTreemap.d.ts +7 -0
  23. package/dist/context-ui/ContextTreemap.d.ts.map +1 -0
  24. package/dist/context-ui/ContextTreemap.js +55 -0
  25. package/dist/context-ui/ContextTreemap.js.map +1 -0
  26. package/dist/context-ui/ContextXRayPanel.d.ts +13 -0
  27. package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -0
  28. package/dist/context-ui/ContextXRayPanel.js +120 -0
  29. package/dist/context-ui/ContextXRayPanel.js.map +1 -0
  30. package/dist/context-ui/format.d.ts +6 -0
  31. package/dist/context-ui/format.d.ts.map +1 -0
  32. package/dist/context-ui/format.js +58 -0
  33. package/dist/context-ui/format.js.map +1 -0
  34. package/dist/context-ui/index.d.ts +7 -0
  35. package/dist/context-ui/index.d.ts.map +1 -0
  36. package/dist/context-ui/index.js +6 -0
  37. package/dist/context-ui/index.js.map +1 -0
  38. package/dist/context-ui/types.d.ts +39 -0
  39. package/dist/context-ui/types.d.ts.map +1 -0
  40. package/dist/context-ui/types.js +2 -0
  41. package/dist/context-ui/types.js.map +1 -0
  42. package/dist/design-tweaks/index.d.ts +2 -0
  43. package/dist/design-tweaks/index.d.ts.map +1 -0
  44. package/dist/design-tweaks/index.js +2 -0
  45. package/dist/design-tweaks/index.js.map +1 -0
  46. package/dist/design-tweaks/visual-style-controls.d.ts +90 -0
  47. package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -0
  48. package/dist/design-tweaks/visual-style-controls.js +499 -0
  49. package/dist/design-tweaks/visual-style-controls.js.map +1 -0
  50. package/dist/editor/BubbleToolbar.d.ts +37 -0
  51. package/dist/editor/BubbleToolbar.d.ts.map +1 -0
  52. package/dist/editor/BubbleToolbar.js +171 -0
  53. package/dist/editor/BubbleToolbar.js.map +1 -0
  54. package/dist/editor/CodeBlockNode.d.ts +49 -0
  55. package/dist/editor/CodeBlockNode.d.ts.map +1 -0
  56. package/dist/editor/CodeBlockNode.js +127 -0
  57. package/dist/editor/CodeBlockNode.js.map +1 -0
  58. package/dist/editor/DragHandle.d.ts +97 -0
  59. package/dist/editor/DragHandle.d.ts.map +1 -0
  60. package/dist/editor/DragHandle.js +1066 -0
  61. package/dist/editor/DragHandle.js.map +1 -0
  62. package/dist/editor/DragHandle.spec.d.ts +2 -0
  63. package/dist/editor/DragHandle.spec.d.ts.map +1 -0
  64. package/dist/editor/DragHandle.spec.js +407 -0
  65. package/dist/editor/DragHandle.spec.js.map +1 -0
  66. package/dist/editor/ImageExtension.d.ts +63 -0
  67. package/dist/editor/ImageExtension.d.ts.map +1 -0
  68. package/dist/editor/ImageExtension.js +243 -0
  69. package/dist/editor/ImageExtension.js.map +1 -0
  70. package/dist/editor/ImageExtension.roundtrip.spec.d.ts +2 -0
  71. package/dist/editor/ImageExtension.roundtrip.spec.d.ts.map +1 -0
  72. package/dist/editor/ImageExtension.roundtrip.spec.js +103 -0
  73. package/dist/editor/ImageExtension.roundtrip.spec.js.map +1 -0
  74. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts +2 -0
  75. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts.map +1 -0
  76. package/dist/editor/RichMarkdownEditor.collab.spec.js +65 -0
  77. package/dist/editor/RichMarkdownEditor.collab.spec.js.map +1 -0
  78. package/dist/editor/RichMarkdownEditor.d.ts +52 -0
  79. package/dist/editor/RichMarkdownEditor.d.ts.map +1 -0
  80. package/dist/editor/RichMarkdownEditor.js +38 -0
  81. package/dist/editor/RichMarkdownEditor.js.map +1 -0
  82. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts +2 -0
  83. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts.map +1 -0
  84. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js +186 -0
  85. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js.map +1 -0
  86. package/dist/editor/RunId.d.ts +28 -0
  87. package/dist/editor/RunId.d.ts.map +1 -0
  88. package/dist/editor/RunId.js +60 -0
  89. package/dist/editor/RunId.js.map +1 -0
  90. package/dist/editor/SharedRichEditor.d.ts +110 -0
  91. package/dist/editor/SharedRichEditor.d.ts.map +1 -0
  92. package/dist/editor/SharedRichEditor.js +144 -0
  93. package/dist/editor/SharedRichEditor.js.map +1 -0
  94. package/dist/editor/SlashCommandMenu.d.ts +41 -0
  95. package/dist/editor/SlashCommandMenu.d.ts.map +1 -0
  96. package/dist/editor/SlashCommandMenu.js +221 -0
  97. package/dist/editor/SlashCommandMenu.js.map +1 -0
  98. package/dist/editor/disableHistory.spec.d.ts +2 -0
  99. package/dist/editor/disableHistory.spec.d.ts.map +1 -0
  100. package/dist/editor/disableHistory.spec.js +73 -0
  101. package/dist/editor/disableHistory.spec.js.map +1 -0
  102. package/dist/editor/extensions.d.ts +178 -0
  103. package/dist/editor/extensions.d.ts.map +1 -0
  104. package/dist/editor/extensions.js +224 -0
  105. package/dist/editor/extensions.js.map +1 -0
  106. package/dist/editor/gfmDoc.d.ts +24 -0
  107. package/dist/editor/gfmDoc.d.ts.map +1 -0
  108. package/dist/editor/gfmDoc.js +83 -0
  109. package/dist/editor/gfmDoc.js.map +1 -0
  110. package/dist/editor/gfmDoc.spec.d.ts +2 -0
  111. package/dist/editor/gfmDoc.spec.d.ts.map +1 -0
  112. package/dist/editor/gfmDoc.spec.js +194 -0
  113. package/dist/editor/gfmDoc.spec.js.map +1 -0
  114. package/dist/editor/index.d.ts +13 -0
  115. package/dist/editor/index.d.ts.map +1 -0
  116. package/dist/editor/index.js +13 -0
  117. package/dist/editor/index.js.map +1 -0
  118. package/dist/editor/structuralReorderUndo.spec.d.ts +2 -0
  119. package/dist/editor/structuralReorderUndo.spec.d.ts.map +1 -0
  120. package/dist/editor/structuralReorderUndo.spec.js +120 -0
  121. package/dist/editor/structuralReorderUndo.spec.js.map +1 -0
  122. package/dist/editor/surgical-apply.d.ts +66 -0
  123. package/dist/editor/surgical-apply.d.ts.map +1 -0
  124. package/dist/editor/surgical-apply.js +147 -0
  125. package/dist/editor/surgical-apply.js.map +1 -0
  126. package/dist/editor/surgical-apply.spec.d.ts +2 -0
  127. package/dist/editor/surgical-apply.spec.d.ts.map +1 -0
  128. package/dist/editor/surgical-apply.spec.js +257 -0
  129. package/dist/editor/surgical-apply.spec.js.map +1 -0
  130. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts +2 -0
  131. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts.map +1 -0
  132. package/dist/editor/useCollabReconcile.concurrent.spec.js +329 -0
  133. package/dist/editor/useCollabReconcile.concurrent.spec.js.map +1 -0
  134. package/dist/editor/useCollabReconcile.d.ts +110 -0
  135. package/dist/editor/useCollabReconcile.d.ts.map +1 -0
  136. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts +2 -0
  137. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts.map +1 -0
  138. package/dist/editor/useCollabReconcile.idempotent.spec.js +248 -0
  139. package/dist/editor/useCollabReconcile.idempotent.spec.js.map +1 -0
  140. package/dist/editor/useCollabReconcile.js +440 -0
  141. package/dist/editor/useCollabReconcile.js.map +1 -0
  142. package/dist/editor.css +510 -0
  143. package/package.json +63 -9
@@ -0,0 +1,120 @@
1
+ // @vitest-environment happy-dom
2
+ import { Editor, Node } from "@tiptap/core";
3
+ import { describe, expect, it } from "vitest";
4
+ import { createRichMarkdownExtensions } from "./RichMarkdownEditor.js";
5
+ /**
6
+ * Structural block reorder must be undoable with cmd+z (Notion parity).
7
+ *
8
+ * The plan editor renders the whole document as ONE ProseMirror doc; structured
9
+ * blocks are atomic `planBlock` nodes. Dragging a block to reorder it repaints
10
+ * the doc via a whole-document `replaceWith` (the plan editor's
11
+ * `replaceEditorViewBlocks`). That repaint used to be dispatched with
12
+ * `addToHistory: false`, so the editor's (already working) undo keymap had
13
+ * nothing to revert — cmd+z after a drag did nothing. The fix makes a
14
+ * single-editor drag repaint a HISTORICAL transaction, so the existing undo
15
+ * stack captures the reorder and interleaves it with text edits, exactly like
16
+ * Notion.
17
+ *
18
+ * This reproduces that exact mechanism headlessly: a minimal block-level ATOM
19
+ * (the analog of `planBlock`, but with a plain-DOM render so no React NodeView
20
+ * is needed) reordered by a whole-document `replaceWith`, dispatched the two
21
+ * ways — and asserts cmd+z reverts ONLY the historical one.
22
+ */
23
+ // Minimal stand-in for the plan's atomic `planBlock` node.
24
+ const BlockAtom = Node.create({
25
+ name: "blockAtom",
26
+ group: "block",
27
+ atom: true,
28
+ selectable: true,
29
+ draggable: true,
30
+ addAttributes() {
31
+ return { blockId: { default: null } };
32
+ },
33
+ parseHTML() {
34
+ return [{ tag: "div[data-block-atom]" }];
35
+ },
36
+ renderHTML({ HTMLAttributes }) {
37
+ return ["div", { ...HTMLAttributes, "data-block-atom": "" }];
38
+ },
39
+ });
40
+ function docOf(ids) {
41
+ return {
42
+ type: "doc",
43
+ content: ids.map((id) => ({ type: "blockAtom", attrs: { blockId: id } })),
44
+ };
45
+ }
46
+ // Initial content goes through the constructor, NOT setContent, so the seed is
47
+ // the baseline doc and is NOT itself an undoable history entry — the first
48
+ // undoable step is whatever the test dispatches next.
49
+ function makeEditor(ids) {
50
+ const element = document.createElement("div");
51
+ document.body.appendChild(element);
52
+ return new Editor({
53
+ element,
54
+ extensions: [...createRichMarkdownExtensions(), BlockAtom],
55
+ content: docOf(ids),
56
+ });
57
+ }
58
+ function atomOrder(editor) {
59
+ const ids = [];
60
+ editor.state.doc.forEach((node) => {
61
+ if (node.type.name === "blockAtom")
62
+ ids.push(node.attrs.blockId);
63
+ });
64
+ return ids;
65
+ }
66
+ /** Reorder by replacing the whole doc — the shape of `replaceEditorViewBlocks`. */
67
+ function reorderViaReplace(editor, ids, addToHistory) {
68
+ const view = editor.view;
69
+ const next = view.state.schema.nodeFromJSON(docOf(ids));
70
+ const tr = view.state.tr.replaceWith(0, view.state.doc.content.size, next.content);
71
+ if (!addToHistory)
72
+ tr.setMeta("addToHistory", false);
73
+ view.dispatch(tr);
74
+ }
75
+ /** Fire a real Mod-z (or Shift-Mod-z) through the ProseMirror undo keymap. */
76
+ function pressModZ(editor, opts = {}) {
77
+ const isMac = typeof navigator !== "undefined" &&
78
+ /Mac|iP(hone|ad|od)/.test(navigator.platform || "");
79
+ const event = new KeyboardEvent("keydown", {
80
+ key: opts.shift ? "Z" : "z",
81
+ code: "KeyZ",
82
+ // prosemirror-keymap resolves a shifted letter (Shift-Mod-Z → redo) through
83
+ // the physical key via `event.keyCode`; a real browser sends it, so the
84
+ // synthetic event must too or the redo binding never matches.
85
+ keyCode: 90,
86
+ which: 90,
87
+ metaKey: isMac,
88
+ ctrlKey: !isMac,
89
+ shiftKey: !!opts.shift,
90
+ bubbles: true,
91
+ cancelable: true,
92
+ });
93
+ return (editor.view.someProp("handleKeyDown", (f) => f(editor.view, event)) ?? false);
94
+ }
95
+ describe("structural block reorder undo", () => {
96
+ it("OLD behavior: a non-historical reorder repaint is NOT undoable", () => {
97
+ const editor = makeEditor(["a", "b", "c"]);
98
+ expect(atomOrder(editor)).toEqual(["a", "b", "c"]);
99
+ reorderViaReplace(editor, ["c", "a", "b"], /* addToHistory */ false);
100
+ expect(atomOrder(editor)).toEqual(["c", "a", "b"]);
101
+ pressModZ(editor);
102
+ // Nothing to undo — the reorder was deliberately excluded from history.
103
+ expect(atomOrder(editor)).toEqual(["c", "a", "b"]);
104
+ editor.destroy();
105
+ });
106
+ it("FIX: a historical reorder repaint is reverted by cmd+z and redone by cmd+shift+z", () => {
107
+ const editor = makeEditor(["a", "b", "c"]);
108
+ expect(atomOrder(editor)).toEqual(["a", "b", "c"]);
109
+ reorderViaReplace(editor, ["c", "a", "b"], /* addToHistory */ true);
110
+ expect(atomOrder(editor)).toEqual(["c", "a", "b"]);
111
+ const undid = pressModZ(editor);
112
+ expect(undid).toBe(true);
113
+ expect(atomOrder(editor)).toEqual(["a", "b", "c"]);
114
+ const redid = pressModZ(editor, { shift: true });
115
+ expect(redid).toBe(true);
116
+ expect(atomOrder(editor)).toEqual(["c", "a", "b"]);
117
+ editor.destroy();
118
+ });
119
+ });
120
+ //# sourceMappingURL=structuralReorderUndo.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuralReorderUndo.spec.js","sourceRoot":"","sources":["../../src/editor/structuralReorderUndo.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Surgical reconcile — apply an authoritative external document into the live
3
+ * editor by replacing only the changed top-level node run, instead of a
4
+ * whole-document `setContent`.
5
+ *
6
+ * Why: under the Collaboration extension, `setContent` routes through
7
+ * y-prosemirror and rewrites the ENTIRE `Y.XmlFragment`. Every block-level
8
+ * NodeView is torn down and recreated (each `ReactRenderer` constructor calls
9
+ * `flushSync`, firing inside a React lifecycle), remote carets jump, and the
10
+ * CRDT sees a delete-all + insert-all instead of a small edit. Diffing the
11
+ * top-level children and dispatching one `tr.replaceWith(from, to, changed)`
12
+ * leaves unchanged NodeViews untouched and produces minimal Yjs ops.
13
+ *
14
+ * This is the core mechanism behind re-enabling single-doc collab in the plan
15
+ * editor (see templates/plan/shared/plan-doc.collab-stability.spec.ts, "Option
16
+ * B") and removing agent-edit NodeView churn in content.
17
+ */
18
+ import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
19
+ import type { Editor } from "@tiptap/react";
20
+ /**
21
+ * Transaction meta marking programmatic (non-user) rich-markdown transactions.
22
+ * Declared here (not in useCollabReconcile) so the module dependency stays
23
+ * one-directional; useCollabReconcile re-exports it for consumers.
24
+ */
25
+ export declare const RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION = "an-rich-md-programmatic-transaction";
26
+ export interface TopLevelDiff {
27
+ /** Index of the first differing top-level child. */
28
+ fromIndex: number;
29
+ /** Exclusive end index of the differing run in the OLD doc. */
30
+ oldToIndex: number;
31
+ /** Exclusive end index of the differing run in the NEW doc. */
32
+ newToIndex: number;
33
+ /** Document position where the differing run starts. */
34
+ fromPos: number;
35
+ /** Document position where the differing run ends in the OLD doc. */
36
+ toPos: number;
37
+ }
38
+ /**
39
+ * Diff two documents at top-level-node granularity: trim the common prefix and
40
+ * suffix (node equality via ProseMirror's `Node.eq`, which is deep) and return
41
+ * the remaining changed run. Returns null when the documents are equal.
42
+ */
43
+ export declare function diffTopLevel(oldDoc: ProseMirrorNode, newDoc: ProseMirrorNode): TopLevelDiff | null;
44
+ /**
45
+ * Replace only the changed top-level run of the live document with the
46
+ * corresponding run from `newDoc`, in one programmatic, history-free
47
+ * transaction. Returns:
48
+ * - "applied" — a targeted replacement was dispatched
49
+ * - "noop" — the documents were already equal (nothing dispatched)
50
+ * - "failed" — the diff/transaction could not be applied (schema mismatch,
51
+ * invalid content, …); caller should fall back to setContent.
52
+ */
53
+ export declare function applyDocSurgically(editor: Editor, newDoc: ProseMirrorNode): "applied" | "noop" | "failed";
54
+ /**
55
+ * Best-effort default parser for the surgical path: use the tiptap-markdown
56
+ * storage parser (present when the shared editor's `features.markdown` is on)
57
+ * to turn the authoritative markdown into a ProseMirror document. Returns null
58
+ * when unavailable or when parsing fails — the caller falls back to the full
59
+ * `setContent` path.
60
+ *
61
+ * Apps with their own serializers (Content's NFM, Plan's blocks[] doc) should
62
+ * pass an explicit `parseValue` producing the exact doc their `setContent`
63
+ * would have written.
64
+ */
65
+ export declare function defaultParseValue(editor: Editor, value: string): ProseMirrorNode | null;
66
+ //# sourceMappingURL=surgical-apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surgical-apply.d.ts","sourceRoot":"","sources":["../../src/editor/surgical-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAY,IAAI,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,sCAAsC,wCACZ,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,eAAe,GACtB,YAAY,GAAG,IAAI,CAkCrB;AA0CD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,eAAe,GACtB,SAAS,GAAG,MAAM,GAAG,QAAQ,CAuB/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,eAAe,GAAG,IAAI,CAaxB"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Surgical reconcile — apply an authoritative external document into the live
3
+ * editor by replacing only the changed top-level node run, instead of a
4
+ * whole-document `setContent`.
5
+ *
6
+ * Why: under the Collaboration extension, `setContent` routes through
7
+ * y-prosemirror and rewrites the ENTIRE `Y.XmlFragment`. Every block-level
8
+ * NodeView is torn down and recreated (each `ReactRenderer` constructor calls
9
+ * `flushSync`, firing inside a React lifecycle), remote carets jump, and the
10
+ * CRDT sees a delete-all + insert-all instead of a small edit. Diffing the
11
+ * top-level children and dispatching one `tr.replaceWith(from, to, changed)`
12
+ * leaves unchanged NodeViews untouched and produces minimal Yjs ops.
13
+ *
14
+ * This is the core mechanism behind re-enabling single-doc collab in the plan
15
+ * editor (see templates/plan/shared/plan-doc.collab-stability.spec.ts, "Option
16
+ * B") and removing agent-edit NodeView churn in content.
17
+ */
18
+ import { createNodeFromContent } from "@tiptap/core";
19
+ /**
20
+ * Transaction meta marking programmatic (non-user) rich-markdown transactions.
21
+ * Declared here (not in useCollabReconcile) so the module dependency stays
22
+ * one-directional; useCollabReconcile re-exports it for consumers.
23
+ */
24
+ export const RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION = "an-rich-md-programmatic-transaction";
25
+ /**
26
+ * Diff two documents at top-level-node granularity: trim the common prefix and
27
+ * suffix (node equality via ProseMirror's `Node.eq`, which is deep) and return
28
+ * the remaining changed run. Returns null when the documents are equal.
29
+ */
30
+ export function diffTopLevel(oldDoc, newDoc) {
31
+ const oldCount = oldDoc.childCount;
32
+ const newCount = newDoc.childCount;
33
+ let prefix = 0;
34
+ const maxPrefix = Math.min(oldCount, newCount);
35
+ while (prefix < maxPrefix && oldDoc.child(prefix).eq(newDoc.child(prefix))) {
36
+ prefix++;
37
+ }
38
+ if (prefix === oldCount && prefix === newCount)
39
+ return null; // identical
40
+ let suffix = 0;
41
+ const maxSuffix = Math.min(oldCount, newCount) - prefix;
42
+ while (suffix < maxSuffix &&
43
+ oldDoc.child(oldCount - 1 - suffix).eq(newDoc.child(newCount - 1 - suffix))) {
44
+ suffix++;
45
+ }
46
+ const fromIndex = prefix;
47
+ const oldToIndex = oldCount - suffix;
48
+ const newToIndex = newCount - suffix;
49
+ // Positions: sum nodeSize of the preserved prefix, then of the changed run.
50
+ let fromPos = 0;
51
+ for (let i = 0; i < fromIndex; i++)
52
+ fromPos += oldDoc.child(i).nodeSize;
53
+ let toPos = fromPos;
54
+ for (let i = fromIndex; i < oldToIndex; i++) {
55
+ toPos += oldDoc.child(i).nodeSize;
56
+ }
57
+ return { fromIndex, oldToIndex, newToIndex, fromPos, toPos };
58
+ }
59
+ function changedFragment(newDoc, diff) {
60
+ return newDoc.content.cut(positionOfChild(newDoc, diff.fromIndex), positionOfChild(newDoc, diff.newToIndex));
61
+ }
62
+ function positionOfChild(doc, index) {
63
+ let pos = 0;
64
+ for (let i = 0; i < index; i++)
65
+ pos += doc.child(i).nodeSize;
66
+ return pos;
67
+ }
68
+ function isEmptyParagraph(node) {
69
+ return !!node && node.type.name === "paragraph" && node.content.size === 0;
70
+ }
71
+ /**
72
+ * Markdown can't represent a trailing empty paragraph (the cursor line users
73
+ * keep below a list/code block), so a parsed authoritative value never has
74
+ * one — but the live doc often does, and the legacy `setContent` path
75
+ * preserves it. Without this, every surgical reconcile whose old doc ends
76
+ * with an empty paragraph would DELETE the user's trailing cursor line.
77
+ */
78
+ function withPreservedTrailingParagraph(oldDoc, newDoc) {
79
+ const oldLast = oldDoc.childCount > 0 ? oldDoc.child(oldDoc.childCount - 1) : null;
80
+ if (!isEmptyParagraph(oldLast))
81
+ return newDoc;
82
+ const newLast = newDoc.childCount > 0 ? newDoc.child(newDoc.childCount - 1) : null;
83
+ if (isEmptyParagraph(newLast))
84
+ return newDoc;
85
+ return newDoc.copy(newDoc.content.addToEnd(oldLast.type.create()));
86
+ }
87
+ /**
88
+ * Replace only the changed top-level run of the live document with the
89
+ * corresponding run from `newDoc`, in one programmatic, history-free
90
+ * transaction. Returns:
91
+ * - "applied" — a targeted replacement was dispatched
92
+ * - "noop" — the documents were already equal (nothing dispatched)
93
+ * - "failed" — the diff/transaction could not be applied (schema mismatch,
94
+ * invalid content, …); caller should fall back to setContent.
95
+ */
96
+ export function applyDocSurgically(editor, newDoc) {
97
+ try {
98
+ const oldDoc = editor.state.doc;
99
+ // The parsed doc MUST come from this editor's schema — NodeType identity
100
+ // is per-Schema-instance, so a foreign-schema doc can never diff or apply.
101
+ if (newDoc.type.schema !== editor.schema || newDoc.type !== oldDoc.type) {
102
+ return "failed";
103
+ }
104
+ const target = withPreservedTrailingParagraph(oldDoc, newDoc);
105
+ const diff = diffTopLevel(oldDoc, target);
106
+ if (!diff)
107
+ return "noop";
108
+ const fragment = changedFragment(target, diff);
109
+ const tr = editor.state.tr;
110
+ tr.replaceWith(diff.fromPos, diff.toPos, fragment);
111
+ tr.setMeta("addToHistory", false);
112
+ tr.setMeta(RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION, true);
113
+ editor.view.dispatch(tr);
114
+ return "applied";
115
+ }
116
+ catch {
117
+ return "failed";
118
+ }
119
+ }
120
+ /**
121
+ * Best-effort default parser for the surgical path: use the tiptap-markdown
122
+ * storage parser (present when the shared editor's `features.markdown` is on)
123
+ * to turn the authoritative markdown into a ProseMirror document. Returns null
124
+ * when unavailable or when parsing fails — the caller falls back to the full
125
+ * `setContent` path.
126
+ *
127
+ * Apps with their own serializers (Content's NFM, Plan's blocks[] doc) should
128
+ * pass an explicit `parseValue` producing the exact doc their `setContent`
129
+ * would have written.
130
+ */
131
+ export function defaultParseValue(editor, value) {
132
+ try {
133
+ const storage = editor.storage.markdown;
134
+ const parsed = storage?.parser?.parse?.(value, { inline: false });
135
+ if (typeof parsed !== "string" || !parsed)
136
+ return null;
137
+ const node = createNodeFromContent(parsed, editor.schema, {
138
+ slice: false,
139
+ });
140
+ // createNodeFromContent with slice:false returns a Node (the doc).
141
+ return node ?? null;
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+ //# sourceMappingURL=surgical-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surgical-apply.js","sourceRoot":"","sources":["../../src/editor/surgical-apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=surgical-apply.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surgical-apply.spec.d.ts","sourceRoot":"","sources":["../../src/editor/surgical-apply.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,257 @@
1
+ // @vitest-environment happy-dom
2
+ import { Editor } from "@tiptap/core";
3
+ import { describe, expect, it } from "vitest";
4
+ import { createRichMarkdownExtensions } from "./RichMarkdownEditor.js";
5
+ import { applyDocSurgically, defaultParseValue, diffTopLevel, } from "./surgical-apply.js";
6
+ /**
7
+ * The surgical reconcile must replace ONLY the changed top-level run —
8
+ * unchanged siblings keep their identity (no NodeView teardown, minimal Yjs
9
+ * ops under Collaboration) — and must converge the editor to exactly the
10
+ * document a full setContent would have produced.
11
+ *
12
+ * NOTE: ProseMirror `Node.eq` relies on NodeType identity, which is
13
+ * per-Schema-instance — so target docs in these tests are parsed with the SAME
14
+ * editor's schema via `defaultParseValue`, mirroring production (where
15
+ * `parseValue` always uses the live editor).
16
+ */
17
+ function makeEditor(markdown) {
18
+ const editor = new Editor({
19
+ extensions: createRichMarkdownExtensions(),
20
+ content: "",
21
+ });
22
+ if (markdown)
23
+ editor.commands.setContent(markdown);
24
+ return editor;
25
+ }
26
+ function md(editor) {
27
+ return (editor.storage.markdown?.getMarkdown?.() ?? "");
28
+ }
29
+ /** Parse markdown into a doc bound to THIS editor's schema. */
30
+ function parse(editor, markdown) {
31
+ const doc = defaultParseValue(editor, markdown);
32
+ if (!doc)
33
+ throw new Error("defaultParseValue returned null in test setup");
34
+ return doc;
35
+ }
36
+ describe("diffTopLevel", () => {
37
+ it("returns null for identical documents", () => {
38
+ const editor = makeEditor("# Title\n\nAlpha\n\nBravo");
39
+ try {
40
+ const same = parse(editor, "# Title\n\nAlpha\n\nBravo");
41
+ expect(diffTopLevel(editor.state.doc, same)).toBeNull();
42
+ }
43
+ finally {
44
+ editor.destroy();
45
+ }
46
+ });
47
+ it("isolates a single changed middle node", () => {
48
+ const editor = makeEditor("# Title\n\nAlpha\n\nBravo\n\nCharlie");
49
+ try {
50
+ const target = parse(editor, "# Title\n\nAlpha CHANGED\n\nBravo\n\nCharlie");
51
+ const diff = diffTopLevel(editor.state.doc, target);
52
+ expect(diff).not.toBeNull();
53
+ expect(diff.fromIndex).toBe(1);
54
+ expect(diff.oldToIndex).toBe(2);
55
+ expect(diff.newToIndex).toBe(2);
56
+ }
57
+ finally {
58
+ editor.destroy();
59
+ }
60
+ });
61
+ it("handles insertion (empty old run)", () => {
62
+ const editor = makeEditor("Alpha\n\nCharlie");
63
+ try {
64
+ const target = parse(editor, "Alpha\n\nBravo\n\nCharlie");
65
+ const diff = diffTopLevel(editor.state.doc, target);
66
+ expect(diff).not.toBeNull();
67
+ expect(diff.fromIndex).toBe(1);
68
+ expect(diff.oldToIndex).toBe(1); // nothing removed
69
+ expect(diff.newToIndex).toBe(2); // one node inserted
70
+ }
71
+ finally {
72
+ editor.destroy();
73
+ }
74
+ });
75
+ it("handles deletion (empty new run)", () => {
76
+ const editor = makeEditor("Alpha\n\nBravo\n\nCharlie");
77
+ try {
78
+ const target = parse(editor, "Alpha\n\nCharlie");
79
+ const diff = diffTopLevel(editor.state.doc, target);
80
+ expect(diff).not.toBeNull();
81
+ expect(diff.fromIndex).toBe(1);
82
+ expect(diff.oldToIndex).toBe(2);
83
+ expect(diff.newToIndex).toBe(1);
84
+ }
85
+ finally {
86
+ editor.destroy();
87
+ }
88
+ });
89
+ });
90
+ describe("applyDocSurgically", () => {
91
+ it("converges the live doc to the target and leaves unchanged nodes intact", () => {
92
+ const editor = makeEditor("# Title\n\nAlpha\n\nBravo\n\nCharlie");
93
+ try {
94
+ const target = parse(editor, "# Title\n\nAlpha CHANGED\n\nBravo\n\nCharlie");
95
+ const before = editor.state.doc;
96
+ const untouched = [before.child(0), before.child(2), before.child(3)];
97
+ const result = applyDocSurgically(editor, target);
98
+ expect(result).toBe("applied");
99
+ expect(editor.state.doc.eq(target)).toBe(true);
100
+ // Structure-preserving: the untouched siblings are still node-equal
101
+ // (same content at the same top-level slots).
102
+ const after = editor.state.doc;
103
+ expect(after.child(0).eq(untouched[0])).toBe(true);
104
+ expect(after.child(2).eq(untouched[1])).toBe(true);
105
+ expect(after.child(3).eq(untouched[2])).toBe(true);
106
+ }
107
+ finally {
108
+ editor.destroy();
109
+ }
110
+ });
111
+ it("returns noop for identical documents without dispatching", () => {
112
+ const editor = makeEditor("Alpha\n\nBravo");
113
+ try {
114
+ const same = parse(editor, "Alpha\n\nBravo");
115
+ const docBefore = editor.state.doc;
116
+ expect(applyDocSurgically(editor, same)).toBe("noop");
117
+ // Same state object — no transaction was dispatched.
118
+ expect(editor.state.doc).toBe(docBefore);
119
+ }
120
+ finally {
121
+ editor.destroy();
122
+ }
123
+ });
124
+ it("handles full-document divergence (worst case degrades to full replace)", () => {
125
+ const editor = makeEditor("One\n\nTwo");
126
+ try {
127
+ const target = parse(editor, "# Totally\n\nDifferent\n\n- list");
128
+ expect(applyDocSurgically(editor, target)).toBe("applied");
129
+ // Serialization converges to what a full setContent would produce…
130
+ const reference = makeEditor("# Totally\n\nDifferent\n\n- list");
131
+ try {
132
+ expect(md(editor)).toBe(md(reference));
133
+ }
134
+ finally {
135
+ reference.destroy();
136
+ }
137
+ // …and re-applying the same parsed value is a no-op (stable after one
138
+ // apply — trailing-cursor-paragraph preservation doesn't oscillate).
139
+ const again = parse(editor, "# Totally\n\nDifferent\n\n- list");
140
+ expect(applyDocSurgically(editor, again)).toBe("noop");
141
+ }
142
+ finally {
143
+ editor.destroy();
144
+ }
145
+ });
146
+ it("preserves the user's trailing empty paragraph across reconciles", () => {
147
+ const editor = makeEditor("Alpha");
148
+ try {
149
+ // Give the user a trailing cursor line below the content.
150
+ editor.commands.focus("end");
151
+ editor.commands.insertContentAt(editor.state.doc.content.size, {
152
+ type: "paragraph",
153
+ });
154
+ const childCountBefore = editor.state.doc.childCount;
155
+ // Agent rewrites the first paragraph; markdown can't express the
156
+ // trailing empty paragraph, so the parsed doc lacks it.
157
+ const target = parse(editor, "Alpha CHANGED");
158
+ expect(applyDocSurgically(editor, target)).toBe("applied");
159
+ const doc = editor.state.doc;
160
+ expect(doc.childCount).toBe(childCountBefore);
161
+ const last = doc.child(doc.childCount - 1);
162
+ expect(last.type.name).toBe("paragraph");
163
+ expect(last.content.size).toBe(0);
164
+ expect(md(editor)).toContain("Alpha CHANGED");
165
+ }
166
+ finally {
167
+ editor.destroy();
168
+ }
169
+ });
170
+ it("converges across a sequence of inserts, deletes, and rewrites", () => {
171
+ const editor = makeEditor("Alpha\n\nBravo\n\nCharlie");
172
+ const steps = [
173
+ "Alpha\n\nBravo\n\nInserted\n\nCharlie",
174
+ "Alpha\n\nCharlie",
175
+ "Prefix\n\nAlpha\n\nCharlie",
176
+ ];
177
+ try {
178
+ for (const step of steps) {
179
+ const target = parse(editor, step);
180
+ const result = applyDocSurgically(editor, target);
181
+ expect(result === "applied" || result === "noop").toBe(true);
182
+ expect(editor.state.doc.eq(target)).toBe(true);
183
+ // The serialized output matches what a full setContent would produce.
184
+ const reference = makeEditor(step);
185
+ try {
186
+ expect(md(editor)).toBe(md(reference));
187
+ }
188
+ finally {
189
+ reference.destroy();
190
+ }
191
+ }
192
+ }
193
+ finally {
194
+ editor.destroy();
195
+ }
196
+ });
197
+ it("fails (for setContent fallback) when the doc comes from a foreign schema", () => {
198
+ const editor = makeEditor("Alpha");
199
+ const foreign = makeEditor("Alpha CHANGED"); // separate Editor → separate Schema
200
+ try {
201
+ expect(applyDocSurgically(editor, foreign.state.doc)).toBe("failed");
202
+ expect(md(editor)).toBe("Alpha");
203
+ }
204
+ finally {
205
+ editor.destroy();
206
+ foreign.destroy();
207
+ }
208
+ });
209
+ it("marks the transaction programmatic and history-free", () => {
210
+ const editor = makeEditor("Alpha");
211
+ try {
212
+ const target = parse(editor, "Alpha CHANGED");
213
+ let sawMeta = false;
214
+ let sawHistoryOff = false;
215
+ const origDispatch = editor.view.dispatch.bind(editor.view);
216
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
+ editor.view.dispatch = (tr) => {
218
+ if (tr.getMeta("an-rich-md-programmatic-transaction"))
219
+ sawMeta = true;
220
+ if (tr.getMeta("addToHistory") === false)
221
+ sawHistoryOff = true;
222
+ origDispatch(tr);
223
+ };
224
+ applyDocSurgically(editor, target);
225
+ expect(sawMeta).toBe(true);
226
+ expect(sawHistoryOff).toBe(true);
227
+ }
228
+ finally {
229
+ editor.destroy();
230
+ }
231
+ });
232
+ });
233
+ describe("defaultParseValue", () => {
234
+ it("parses markdown that applies to the same serialization as setContent", () => {
235
+ const editor = makeEditor("Alpha");
236
+ try {
237
+ const parsed = defaultParseValue(editor, "# Heading\n\nBody text\n\n- item");
238
+ expect(parsed).not.toBeNull();
239
+ expect(applyDocSurgically(editor, parsed)).toBe("applied");
240
+ const reference = makeEditor("# Heading\n\nBody text\n\n- item");
241
+ try {
242
+ expect(md(editor)).toBe(md(reference));
243
+ }
244
+ finally {
245
+ reference.destroy();
246
+ }
247
+ }
248
+ finally {
249
+ editor.destroy();
250
+ }
251
+ });
252
+ it("returns null when the markdown storage is unavailable", () => {
253
+ const stub = { storage: {}, schema: null };
254
+ expect(defaultParseValue(stub, "# x")).toBeNull();
255
+ });
256
+ });
257
+ //# sourceMappingURL=surgical-apply.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surgical-apply.spec.js","sourceRoot":"","sources":["../../src/editor/surgical-apply.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useCollabReconcile.concurrent.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollabReconcile.concurrent.spec.d.ts","sourceRoot":"","sources":["../../src/editor/useCollabReconcile.concurrent.spec.ts"],"names":[],"mappings":""}