@agent-native/core 0.109.2 → 0.109.4

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 (334) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +16 -0
  3. package/corpus/core/docs/content/agent-native-toolkit.mdx +46 -13
  4. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +79 -55
  5. package/corpus/core/docs/content/locales/ar-SA/toolkit-capability-packages.mdx +21 -0
  6. package/corpus/core/docs/content/locales/ar-SA/toolkit-context-knowledge.mdx +12 -0
  7. package/corpus/core/docs/content/locales/ar-SA/toolkit-editors-canvases.mdx +17 -0
  8. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +82 -54
  9. package/corpus/core/docs/content/locales/de-DE/toolkit-capability-packages.mdx +21 -0
  10. package/corpus/core/docs/content/locales/de-DE/toolkit-context-knowledge.mdx +12 -0
  11. package/corpus/core/docs/content/locales/de-DE/toolkit-editors-canvases.mdx +17 -0
  12. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +81 -52
  13. package/corpus/core/docs/content/locales/es-ES/toolkit-capability-packages.mdx +21 -0
  14. package/corpus/core/docs/content/locales/es-ES/toolkit-context-knowledge.mdx +12 -0
  15. package/corpus/core/docs/content/locales/es-ES/toolkit-editors-canvases.mdx +21 -0
  16. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +84 -54
  17. package/corpus/core/docs/content/locales/fr-FR/toolkit-capability-packages.mdx +21 -0
  18. package/corpus/core/docs/content/locales/fr-FR/toolkit-context-knowledge.mdx +12 -0
  19. package/corpus/core/docs/content/locales/fr-FR/toolkit-editors-canvases.mdx +21 -0
  20. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +69 -62
  21. package/corpus/core/docs/content/locales/hi-IN/toolkit-capability-packages.mdx +21 -0
  22. package/corpus/core/docs/content/locales/hi-IN/toolkit-context-knowledge.mdx +12 -0
  23. package/corpus/core/docs/content/locales/hi-IN/toolkit-editors-canvases.mdx +17 -0
  24. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +69 -62
  25. package/corpus/core/docs/content/locales/ja-JP/toolkit-capability-packages.mdx +21 -0
  26. package/corpus/core/docs/content/locales/ja-JP/toolkit-context-knowledge.mdx +12 -0
  27. package/corpus/core/docs/content/locales/ja-JP/toolkit-editors-canvases.mdx +17 -0
  28. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +69 -62
  29. package/corpus/core/docs/content/locales/ko-KR/toolkit-capability-packages.mdx +21 -0
  30. package/corpus/core/docs/content/locales/ko-KR/toolkit-context-knowledge.mdx +12 -0
  31. package/corpus/core/docs/content/locales/ko-KR/toolkit-editors-canvases.mdx +17 -0
  32. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +82 -54
  33. package/corpus/core/docs/content/locales/pt-BR/toolkit-capability-packages.mdx +21 -0
  34. package/corpus/core/docs/content/locales/pt-BR/toolkit-context-knowledge.mdx +12 -0
  35. package/corpus/core/docs/content/locales/pt-BR/toolkit-editors-canvases.mdx +17 -0
  36. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +69 -62
  37. package/corpus/core/docs/content/locales/zh-CN/toolkit-capability-packages.mdx +21 -0
  38. package/corpus/core/docs/content/locales/zh-CN/toolkit-context-knowledge.mdx +12 -0
  39. package/corpus/core/docs/content/locales/zh-CN/toolkit-editors-canvases.mdx +17 -0
  40. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +69 -62
  41. package/corpus/core/docs/content/locales/zh-TW/toolkit-capability-packages.mdx +21 -0
  42. package/corpus/core/docs/content/locales/zh-TW/toolkit-context-knowledge.mdx +12 -0
  43. package/corpus/core/docs/content/locales/zh-TW/toolkit-editors-canvases.mdx +17 -0
  44. package/corpus/core/docs/content/toolkit-capability-packages.mdx +52 -0
  45. package/corpus/core/docs/content/toolkit-context-knowledge.mdx +46 -0
  46. package/corpus/core/docs/content/toolkit-editors-canvases.mdx +55 -0
  47. package/corpus/core/package.json +35 -34
  48. package/corpus/core/src/cli/create.ts +57 -15
  49. package/corpus/core/src/cli/package-lifecycle.ts +2 -0
  50. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +2 -0
  51. package/corpus/core/src/client/context-xray/ContextMeter.tsx +31 -111
  52. package/corpus/core/src/client/context-xray/ContextSegmentRow.tsx +8 -111
  53. package/corpus/core/src/client/context-xray/ContextTreemap.tsx +6 -111
  54. package/corpus/core/src/client/context-xray/ContextXRayPanel.tsx +31 -391
  55. package/corpus/core/src/client/context-xray/SegmentProvenancePopover.tsx +4 -52
  56. package/corpus/core/src/client/context-xray/format.ts +0 -33
  57. package/corpus/core/src/client/require-session.tsx +19 -3
  58. package/corpus/core/src/client/rich-markdown-editor/index.ts +42 -57
  59. package/corpus/core/src/client/rich-markdown-editor/uploadEditorImage.ts +2 -1
  60. package/corpus/core/src/client/use-action.ts +145 -2
  61. package/corpus/core/src/client/use-session.ts +79 -48
  62. package/corpus/core/src/client/visual-style-controls.tsx +1 -1088
  63. package/corpus/core/src/collab/agent-identity.ts +5 -22
  64. package/corpus/core/src/collab/client.ts +1 -53
  65. package/corpus/core/src/db/client.ts +13 -7
  66. package/corpus/core/src/db/create-get-db.ts +20 -13
  67. package/corpus/core/src/db/request-telemetry.ts +154 -0
  68. package/corpus/core/src/integrations/index.ts +1 -0
  69. package/corpus/core/src/integrations/plugin.ts +9 -3
  70. package/corpus/core/src/integrations/remote-push-delivery-job.ts +48 -0
  71. package/corpus/core/src/integrations/remote-push-delivery.ts +370 -0
  72. package/corpus/core/src/integrations/remote-push-store.ts +275 -26
  73. package/corpus/core/src/server/better-auth-instance.ts +11 -3
  74. package/corpus/core/src/server/core-routes-plugin.ts +36 -14
  75. package/corpus/core/src/server/framework-request-handler.ts +11 -1
  76. package/corpus/core/src/server/http-response-telemetry.ts +233 -31
  77. package/corpus/core/src/styles/rich-markdown-editor.css +1 -510
  78. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +19 -0
  79. package/corpus/core/src/testing.ts +1 -1
  80. package/corpus/core/src/vite/client.ts +3 -0
  81. package/corpus/templates/clips/actions/finalize-recording.ts +3 -1
  82. package/corpus/templates/clips/actions/set-mobile-capture-state.ts +4 -1
  83. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -6
  84. package/corpus/templates/clips/changelog/2026-07-18-new-recording-is-now-emphasized-as-the-primary-action-in-the.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-07-18-recordings-now-remain-safely-recoverable-until-the-stored-me.md +6 -0
  86. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +5 -3
  87. package/corpus/templates/content/app/components/editor/extensions/DragHandle.tsx +4 -4
  88. package/corpus/templates/content/package.json +25 -25
  89. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  90. package/corpus/templates/design/package.json +1 -1
  91. package/corpus/templates/mail/package.json +9 -9
  92. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +2 -0
  93. package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +8 -8
  94. package/corpus/templates/plan/app/components/editor/planSlashCommands.ts +6 -6
  95. package/corpus/templates/plan/app/components/plan/PlanImageNode.tsx +4 -7
  96. package/corpus/templates/plan/app/components/plan/PlanMarkdownEditor.tsx +6 -4
  97. package/corpus/templates/plan/app/components/plan/PlanVisualSurface.tsx +1 -1
  98. package/corpus/templates/plan/changelog/2026-07-18-visual-plans-now-open-on-wireframes-by-default-when-a-protot.md +6 -0
  99. package/corpus/templates/plan/package.json +3 -3
  100. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +2 -2
  101. package/corpus/templates/slides/app/components/editor/TweaksPanel.tsx +2 -2
  102. package/corpus/templates/slides/package.json +13 -13
  103. package/corpus/templates/tasks/AGENTS.md +3 -0
  104. package/corpus/templates/tasks/actions/render-task-list-inline.ts +202 -0
  105. package/corpus/templates/tasks/changelog/2026-07-18-task-lists-can-now-appear-as-interactive-widgets-inline-in-c.md +6 -0
  106. package/corpus/templates/tasks/docs/features/f8-chat.mdx +2 -0
  107. package/corpus/templates/tasks/server/plugins/agent-chat.ts +2 -0
  108. package/dist/catalog.json +39 -1
  109. package/dist/cli/create.d.ts +10 -1
  110. package/dist/cli/create.d.ts.map +1 -1
  111. package/dist/cli/create.js +49 -16
  112. package/dist/cli/create.js.map +1 -1
  113. package/dist/cli/package-lifecycle.d.ts.map +1 -1
  114. package/dist/cli/package-lifecycle.js +2 -0
  115. package/dist/cli/package-lifecycle.js.map +1 -1
  116. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  117. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
  118. package/dist/cli/skills-content/visual-plan-skill.js +2 -0
  119. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
  120. package/dist/client/context-xray/ContextMeter.d.ts.map +1 -1
  121. package/dist/client/context-xray/ContextMeter.js +8 -23
  122. package/dist/client/context-xray/ContextMeter.js.map +1 -1
  123. package/dist/client/context-xray/ContextSegmentRow.d.ts.map +1 -1
  124. package/dist/client/context-xray/ContextSegmentRow.js +3 -19
  125. package/dist/client/context-xray/ContextSegmentRow.js.map +1 -1
  126. package/dist/client/context-xray/ContextTreemap.d.ts.map +1 -1
  127. package/dist/client/context-xray/ContextTreemap.js +3 -54
  128. package/dist/client/context-xray/ContextTreemap.js.map +1 -1
  129. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  130. package/dist/client/context-xray/ContextXRayPanel.js +21 -163
  131. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  132. package/dist/client/context-xray/SegmentProvenancePopover.d.ts.map +1 -1
  133. package/dist/client/context-xray/SegmentProvenancePopover.js +3 -4
  134. package/dist/client/context-xray/SegmentProvenancePopover.js.map +1 -1
  135. package/dist/client/context-xray/format.d.ts +0 -4
  136. package/dist/client/context-xray/format.d.ts.map +1 -1
  137. package/dist/client/context-xray/format.js +0 -49
  138. package/dist/client/context-xray/format.js.map +1 -1
  139. package/dist/client/require-session.d.ts.map +1 -1
  140. package/dist/client/require-session.js +6 -3
  141. package/dist/client/require-session.js.map +1 -1
  142. package/dist/client/rich-markdown-editor/index.d.ts +1 -12
  143. package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
  144. package/dist/client/rich-markdown-editor/index.js +1 -12
  145. package/dist/client/rich-markdown-editor/index.js.map +1 -1
  146. package/dist/client/rich-markdown-editor/uploadEditorImage.d.ts +1 -1
  147. package/dist/client/rich-markdown-editor/uploadEditorImage.d.ts.map +1 -1
  148. package/dist/client/rich-markdown-editor/uploadEditorImage.js.map +1 -1
  149. package/dist/client/use-action.d.ts.map +1 -1
  150. package/dist/client/use-action.js +117 -1
  151. package/dist/client/use-action.js.map +1 -1
  152. package/dist/client/use-session.d.ts.map +1 -1
  153. package/dist/client/use-session.js +72 -50
  154. package/dist/client/use-session.js.map +1 -1
  155. package/dist/client/visual-style-controls.d.ts +1 -89
  156. package/dist/client/visual-style-controls.d.ts.map +1 -1
  157. package/dist/client/visual-style-controls.js +1 -498
  158. package/dist/client/visual-style-controls.js.map +1 -1
  159. package/dist/collab/agent-identity.d.ts +1 -14
  160. package/dist/collab/agent-identity.d.ts.map +1 -1
  161. package/dist/collab/agent-identity.js +1 -13
  162. package/dist/collab/agent-identity.js.map +1 -1
  163. package/dist/collab/awareness.d.ts +2 -2
  164. package/dist/collab/awareness.d.ts.map +1 -1
  165. package/dist/collab/client.d.ts +1 -19
  166. package/dist/collab/client.d.ts.map +1 -1
  167. package/dist/collab/client.js +1 -53
  168. package/dist/collab/client.js.map +1 -1
  169. package/dist/collab/struct-routes.d.ts +1 -1
  170. package/dist/db/client.d.ts.map +1 -1
  171. package/dist/db/client.js +7 -1
  172. package/dist/db/client.js.map +1 -1
  173. package/dist/db/create-get-db.d.ts +3 -6
  174. package/dist/db/create-get-db.d.ts.map +1 -1
  175. package/dist/db/create-get-db.js +9 -2
  176. package/dist/db/create-get-db.js.map +1 -1
  177. package/dist/db/request-telemetry.d.ts +23 -0
  178. package/dist/db/request-telemetry.d.ts.map +1 -0
  179. package/dist/db/request-telemetry.js +95 -0
  180. package/dist/db/request-telemetry.js.map +1 -0
  181. package/dist/integrations/index.d.ts +1 -0
  182. package/dist/integrations/index.d.ts.map +1 -1
  183. package/dist/integrations/index.js +1 -0
  184. package/dist/integrations/index.js.map +1 -1
  185. package/dist/integrations/plugin.d.ts.map +1 -1
  186. package/dist/integrations/plugin.js +8 -3
  187. package/dist/integrations/plugin.js.map +1 -1
  188. package/dist/integrations/remote-push-delivery-job.d.ts +4 -0
  189. package/dist/integrations/remote-push-delivery-job.d.ts.map +1 -0
  190. package/dist/integrations/remote-push-delivery-job.js +44 -0
  191. package/dist/integrations/remote-push-delivery-job.js.map +1 -0
  192. package/dist/integrations/remote-push-delivery.d.ts +11 -0
  193. package/dist/integrations/remote-push-delivery.d.ts.map +1 -0
  194. package/dist/integrations/remote-push-delivery.js +265 -0
  195. package/dist/integrations/remote-push-delivery.js.map +1 -0
  196. package/dist/integrations/remote-push-store.d.ts +33 -0
  197. package/dist/integrations/remote-push-store.d.ts.map +1 -1
  198. package/dist/integrations/remote-push-store.js +195 -26
  199. package/dist/integrations/remote-push-store.js.map +1 -1
  200. package/dist/notifications/routes.d.ts +3 -3
  201. package/dist/progress/routes.d.ts +1 -1
  202. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  203. package/dist/resources/handlers.d.ts +3 -3
  204. package/dist/secrets/routes.d.ts +9 -9
  205. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  206. package/dist/server/better-auth-instance.js +7 -3
  207. package/dist/server/better-auth-instance.js.map +1 -1
  208. package/dist/server/core-routes-plugin.d.ts +8 -0
  209. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  210. package/dist/server/core-routes-plugin.js +23 -8
  211. package/dist/server/core-routes-plugin.js.map +1 -1
  212. package/dist/server/framework-request-handler.d.ts.map +1 -1
  213. package/dist/server/framework-request-handler.js +9 -1
  214. package/dist/server/framework-request-handler.js.map +1 -1
  215. package/dist/server/http-response-telemetry.d.ts +3 -2
  216. package/dist/server/http-response-telemetry.d.ts.map +1 -1
  217. package/dist/server/http-response-telemetry.js +160 -27
  218. package/dist/server/http-response-telemetry.js.map +1 -1
  219. package/dist/server/transcribe-voice.d.ts +1 -1
  220. package/dist/styles/rich-markdown-editor.css +1 -510
  221. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +19 -0
  222. package/dist/testing.d.ts +1 -1
  223. package/dist/testing.d.ts.map +1 -1
  224. package/dist/testing.js +1 -1
  225. package/dist/testing.js.map +1 -1
  226. package/dist/vite/client.d.ts.map +1 -1
  227. package/dist/vite/client.js +3 -0
  228. package/dist/vite/client.js.map +1 -1
  229. package/docs/content/agent-native-toolkit.mdx +46 -13
  230. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +79 -55
  231. package/docs/content/locales/ar-SA/toolkit-capability-packages.mdx +21 -0
  232. package/docs/content/locales/ar-SA/toolkit-context-knowledge.mdx +12 -0
  233. package/docs/content/locales/ar-SA/toolkit-editors-canvases.mdx +17 -0
  234. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +82 -54
  235. package/docs/content/locales/de-DE/toolkit-capability-packages.mdx +21 -0
  236. package/docs/content/locales/de-DE/toolkit-context-knowledge.mdx +12 -0
  237. package/docs/content/locales/de-DE/toolkit-editors-canvases.mdx +17 -0
  238. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +81 -52
  239. package/docs/content/locales/es-ES/toolkit-capability-packages.mdx +21 -0
  240. package/docs/content/locales/es-ES/toolkit-context-knowledge.mdx +12 -0
  241. package/docs/content/locales/es-ES/toolkit-editors-canvases.mdx +21 -0
  242. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +84 -54
  243. package/docs/content/locales/fr-FR/toolkit-capability-packages.mdx +21 -0
  244. package/docs/content/locales/fr-FR/toolkit-context-knowledge.mdx +12 -0
  245. package/docs/content/locales/fr-FR/toolkit-editors-canvases.mdx +21 -0
  246. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +69 -62
  247. package/docs/content/locales/hi-IN/toolkit-capability-packages.mdx +21 -0
  248. package/docs/content/locales/hi-IN/toolkit-context-knowledge.mdx +12 -0
  249. package/docs/content/locales/hi-IN/toolkit-editors-canvases.mdx +17 -0
  250. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +69 -62
  251. package/docs/content/locales/ja-JP/toolkit-capability-packages.mdx +21 -0
  252. package/docs/content/locales/ja-JP/toolkit-context-knowledge.mdx +12 -0
  253. package/docs/content/locales/ja-JP/toolkit-editors-canvases.mdx +17 -0
  254. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +69 -62
  255. package/docs/content/locales/ko-KR/toolkit-capability-packages.mdx +21 -0
  256. package/docs/content/locales/ko-KR/toolkit-context-knowledge.mdx +12 -0
  257. package/docs/content/locales/ko-KR/toolkit-editors-canvases.mdx +17 -0
  258. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +82 -54
  259. package/docs/content/locales/pt-BR/toolkit-capability-packages.mdx +21 -0
  260. package/docs/content/locales/pt-BR/toolkit-context-knowledge.mdx +12 -0
  261. package/docs/content/locales/pt-BR/toolkit-editors-canvases.mdx +17 -0
  262. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +69 -62
  263. package/docs/content/locales/zh-CN/toolkit-capability-packages.mdx +21 -0
  264. package/docs/content/locales/zh-CN/toolkit-context-knowledge.mdx +12 -0
  265. package/docs/content/locales/zh-CN/toolkit-editors-canvases.mdx +17 -0
  266. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +69 -62
  267. package/docs/content/locales/zh-TW/toolkit-capability-packages.mdx +21 -0
  268. package/docs/content/locales/zh-TW/toolkit-context-knowledge.mdx +12 -0
  269. package/docs/content/locales/zh-TW/toolkit-editors-canvases.mdx +17 -0
  270. package/docs/content/toolkit-capability-packages.mdx +52 -0
  271. package/docs/content/toolkit-context-knowledge.mdx +46 -0
  272. package/docs/content/toolkit-editors-canvases.mdx +55 -0
  273. package/package.json +27 -26
  274. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +19 -0
  275. package/corpus/core/src/client/rich-markdown-editor/BubbleToolbar.tsx +0 -253
  276. package/corpus/core/src/client/rich-markdown-editor/CodeBlockNode.tsx +0 -258
  277. package/corpus/core/src/client/rich-markdown-editor/DragHandle.ts +0 -1437
  278. package/corpus/core/src/client/rich-markdown-editor/ImageExtension.ts +0 -306
  279. package/corpus/core/src/client/rich-markdown-editor/RichMarkdownEditor.tsx +0 -80
  280. package/corpus/core/src/client/rich-markdown-editor/RunId.ts +0 -61
  281. package/corpus/core/src/client/rich-markdown-editor/SharedRichEditor.tsx +0 -321
  282. package/corpus/core/src/client/rich-markdown-editor/SlashCommandMenu.tsx +0 -310
  283. package/corpus/core/src/client/rich-markdown-editor/extensions.ts +0 -402
  284. package/corpus/core/src/client/rich-markdown-editor/gfmDoc.ts +0 -92
  285. package/corpus/core/src/client/rich-markdown-editor/surgical-apply.ts +0 -192
  286. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +0 -590
  287. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts +0 -37
  288. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts.map +0 -1
  289. package/dist/client/rich-markdown-editor/BubbleToolbar.js +0 -171
  290. package/dist/client/rich-markdown-editor/BubbleToolbar.js.map +0 -1
  291. package/dist/client/rich-markdown-editor/CodeBlockNode.d.ts +0 -49
  292. package/dist/client/rich-markdown-editor/CodeBlockNode.d.ts.map +0 -1
  293. package/dist/client/rich-markdown-editor/CodeBlockNode.js +0 -127
  294. package/dist/client/rich-markdown-editor/CodeBlockNode.js.map +0 -1
  295. package/dist/client/rich-markdown-editor/DragHandle.d.ts +0 -97
  296. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +0 -1
  297. package/dist/client/rich-markdown-editor/DragHandle.js +0 -1066
  298. package/dist/client/rich-markdown-editor/DragHandle.js.map +0 -1
  299. package/dist/client/rich-markdown-editor/ImageExtension.d.ts +0 -63
  300. package/dist/client/rich-markdown-editor/ImageExtension.d.ts.map +0 -1
  301. package/dist/client/rich-markdown-editor/ImageExtension.js +0 -243
  302. package/dist/client/rich-markdown-editor/ImageExtension.js.map +0 -1
  303. package/dist/client/rich-markdown-editor/RichMarkdownEditor.d.ts +0 -51
  304. package/dist/client/rich-markdown-editor/RichMarkdownEditor.d.ts.map +0 -1
  305. package/dist/client/rich-markdown-editor/RichMarkdownEditor.js +0 -37
  306. package/dist/client/rich-markdown-editor/RichMarkdownEditor.js.map +0 -1
  307. package/dist/client/rich-markdown-editor/RunId.d.ts +0 -28
  308. package/dist/client/rich-markdown-editor/RunId.d.ts.map +0 -1
  309. package/dist/client/rich-markdown-editor/RunId.js +0 -60
  310. package/dist/client/rich-markdown-editor/RunId.js.map +0 -1
  311. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +0 -110
  312. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +0 -1
  313. package/dist/client/rich-markdown-editor/SharedRichEditor.js +0 -144
  314. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +0 -1
  315. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts +0 -41
  316. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts.map +0 -1
  317. package/dist/client/rich-markdown-editor/SlashCommandMenu.js +0 -221
  318. package/dist/client/rich-markdown-editor/SlashCommandMenu.js.map +0 -1
  319. package/dist/client/rich-markdown-editor/extensions.d.ts +0 -178
  320. package/dist/client/rich-markdown-editor/extensions.d.ts.map +0 -1
  321. package/dist/client/rich-markdown-editor/extensions.js +0 -224
  322. package/dist/client/rich-markdown-editor/extensions.js.map +0 -1
  323. package/dist/client/rich-markdown-editor/gfmDoc.d.ts +0 -24
  324. package/dist/client/rich-markdown-editor/gfmDoc.d.ts.map +0 -1
  325. package/dist/client/rich-markdown-editor/gfmDoc.js +0 -83
  326. package/dist/client/rich-markdown-editor/gfmDoc.js.map +0 -1
  327. package/dist/client/rich-markdown-editor/surgical-apply.d.ts +0 -66
  328. package/dist/client/rich-markdown-editor/surgical-apply.d.ts.map +0 -1
  329. package/dist/client/rich-markdown-editor/surgical-apply.js +0 -147
  330. package/dist/client/rich-markdown-editor/surgical-apply.js.map +0 -1
  331. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +0 -110
  332. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +0 -1
  333. package/dist/client/rich-markdown-editor/useCollabReconcile.js +0 -441
  334. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +0 -1
@@ -1,224 +0,0 @@
1
- import Collaboration from "@tiptap/extension-collaboration";
2
- import CollaborationCaret from "@tiptap/extension-collaboration-caret";
3
- import Link from "@tiptap/extension-link";
4
- import Placeholder from "@tiptap/extension-placeholder";
5
- import { Table } from "@tiptap/extension-table";
6
- import { TableCell } from "@tiptap/extension-table-cell";
7
- import { TableHeader } from "@tiptap/extension-table-header";
8
- import { TableRow } from "@tiptap/extension-table-row";
9
- import TaskItem from "@tiptap/extension-task-item";
10
- import TaskList from "@tiptap/extension-task-list";
11
- import StarterKit from "@tiptap/starter-kit";
12
- import bash from "highlight.js/lib/languages/bash";
13
- import css from "highlight.js/lib/languages/css";
14
- import javascript from "highlight.js/lib/languages/javascript";
15
- import json from "highlight.js/lib/languages/json";
16
- import markdown from "highlight.js/lib/languages/markdown";
17
- import python from "highlight.js/lib/languages/python";
18
- import sql from "highlight.js/lib/languages/sql";
19
- import typescript from "highlight.js/lib/languages/typescript";
20
- import xml from "highlight.js/lib/languages/xml";
21
- import yaml from "highlight.js/lib/languages/yaml";
22
- import { createLowlight } from "lowlight";
23
- import { Markdown } from "tiptap-markdown";
24
- /**
25
- * Shared lowlight instance for the editor's syntax-highlighted code blocks. A
26
- * curated grammar set (aliases like ts/tsx, js/jsx, html, sh, py, yml, md come
27
- * for free from each grammar) keeps the editor bundle lean while matching the
28
- * languages the read-side Shiki surfaces (`code-tabs`) support. highlight.js is
29
- * synchronous, which is what a live ProseMirror editor needs — Shiki is async
30
- * and only used for read-only render paths.
31
- */
32
- const codeLowlight = createLowlight({
33
- bash,
34
- css,
35
- javascript,
36
- json,
37
- markdown,
38
- python,
39
- sql,
40
- typescript,
41
- xml,
42
- yaml,
43
- });
44
- import { createCodeBlockNode } from "./CodeBlockNode.js";
45
- import { createImageExtension } from "./ImageExtension.js";
46
- /**
47
- * tiptap-markdown configuration, keyed by dialect. This is the single source of
48
- * truth for how each dialect parses/serializes markdown so the editor component
49
- * and the round-trip fidelity test can never drift apart.
50
- *
51
- * tiptap-markdown re-serializes the whole document on every edit, so the goal
52
- * for GFM is `serialize(parse(markdown)) === markdown` for the markdown plans
53
- * actually contain. We deliberately keep tiptap-markdown's own defaults
54
- * (`bulletListMarker: "-"`, `tightLists: true`, `linkify: false`,
55
- * `breaks: false`) because those produce the most byte-stable GFM. See
56
- * RichMarkdownEditor.roundtrip.spec.ts for the pinned corpus.
57
- *
58
- * NFM (Content) opts into inline HTML passthrough (`html: true`) so
59
- * Notion-specific blocks survive a markdown round-trip; the rest mirrors the
60
- * Content editor's existing `Markdown.configure` call.
61
- */
62
- export const MARKDOWN_DIALECT_CONFIG = {
63
- gfm: {
64
- // GFM plans are the common case and must never gain raw HTML as a second
65
- // representation.
66
- html: false,
67
- // Keep tiptap-markdown's defaults that minimise first-edit normalisation
68
- // churn (see roundtrip spec). Listed explicitly so the contract is
69
- // self-documenting rather than relying on the package defaults.
70
- bulletListMarker: "-",
71
- tightLists: true,
72
- linkify: false,
73
- breaks: false,
74
- transformPastedText: true,
75
- transformCopiedText: true,
76
- },
77
- nfm: {
78
- // NFM is a superset that allows inline HTML so Notion blocks round-trip.
79
- html: true,
80
- transformPastedText: true,
81
- transformCopiedText: true,
82
- },
83
- };
84
- const DEFAULT_FEATURES = {
85
- tables: true,
86
- tasks: true,
87
- link: true,
88
- codeBlock: true,
89
- placeholder: true,
90
- markdown: true,
91
- // Off by default: only Plans opt in today. Content injects its own richer
92
- // image node via `extraExtensions` and must not get a second `image` node.
93
- image: false,
94
- };
95
- /**
96
- * The ONE editor extension factory shared by every embedder (Plans today,
97
- * Content next). It assembles the base Tiptap schema (StarterKit + Placeholder
98
- * + Link + tasks + tables + code block), the dialect-keyed {@link Markdown}
99
- * serializer, the optional Collaboration stack, and finally any app-specific
100
- * `extraExtensions`.
101
- *
102
- * Ordering matters:
103
- * 1. Base schema (StarterKit first so its nodes/marks register; `starterKit`
104
- * overrides let an app disable replaced nodes / swap the dropcursor).
105
- * 2. dialect-keyed Markdown serializer (suppressible via `features.markdown`
106
- * for apps that own the whole serialize/parse pipeline, e.g. Content's NFM).
107
- * 3. `extraExtensions` (Notion/media/etc.) — appended before Collaboration so
108
- * apps can extend the schema and Collaboration still binds over the full
109
- * schema.
110
- * 4. Collaboration (+ CollaborationCaret) LAST so they bind over everything.
111
- *
112
- * Content (the NFM editor) drives this factory with `features.placeholder` and
113
- * `features.markdown` off, `features.tasks/tables/link` off where it ships its
114
- * own, a `starterKit` override disabling paragraph/blockquote/codeBlock, and all
115
- * Notion/media/fidelity nodes + its own Markdown(NFM)/Placeholder via
116
- * `extraExtensions` — so it shares the StarterKit base + the collab wiring while
117
- * owning its byte-identical NFM serializer.
118
- */
119
- export function createSharedEditorExtensions({ dialect = "gfm",
120
- // `preset` is accepted and forwarded for future preset-specific schema
121
- // branches; it is currently schema-neutral.
122
- preset: _preset = "plan", placeholder = "Type '/' for commands...", features, starterKit, markdown, extraExtensions = [], collab = null, onImageUpload = null, disableHistory = false, } = {}) {
123
- const feat = { ...DEFAULT_FEATURES, ...(features ?? {}) };
124
- const ydoc = collab?.ydoc ?? null;
125
- const awareness = collab?.awareness ?? null;
126
- const user = collab?.user ?? null;
127
- const exts = [
128
- StarterKit.configure({
129
- heading: { levels: [1, 2, 3, 4] },
130
- link: false,
131
- // StarterKit's plain code block is always disabled; when enabled we add the
132
- // syntax-highlighting `CodeBlockLowlight` (same `codeBlock` node) below.
133
- codeBlock: false,
134
- dropcursor: { color: "hsl(var(--ring))", width: 2 },
135
- // Yjs owns undo/redo when Collaboration is active; the StarterKit history
136
- // plugin and the CRDT cannot both track undo without corrupting state.
137
- // `disableHistory` is the non-collab equivalent: a controlled editor whose
138
- // host (e.g. the plan editor) owns a single app-level undo authority.
139
- ...(ydoc || disableHistory ? { undoRedo: false } : {}),
140
- // App overrides last so embedders can disable replaced nodes (paragraph,
141
- // blockquote, code block) or swap the dropcursor while keeping the shared
142
- // base + the collab undo/redo gating above.
143
- ...(starterKit ?? {}),
144
- }),
145
- ];
146
- // Notion-style syntax-highlighted code block (replaces StarterKit's plain one)
147
- // only when the embedder opts in via `features.codeBlock`. The shared node adds
148
- // a language picker header (Auto-detects by default) over `CodeBlockLowlight`,
149
- // so fenced markdown still round-trips byte-identically. Content disables this
150
- // and ships its own code node, so this affects Plans (and future opt-in apps)
151
- // alone.
152
- if (feat.codeBlock) {
153
- exts.push(createCodeBlockNode({ lowlight: codeLowlight }));
154
- }
155
- if (feat.placeholder) {
156
- exts.push(Placeholder.configure({
157
- placeholder: ({ node }) => {
158
- if (node.type.name === "heading") {
159
- const level = node.attrs.level;
160
- if (level === 1)
161
- return "Heading 1";
162
- if (level === 2)
163
- return "Heading 2";
164
- if (level === 3)
165
- return "Heading 3";
166
- return "Heading 4";
167
- }
168
- return placeholder;
169
- },
170
- showOnlyWhenEditable: true,
171
- showOnlyCurrent: true,
172
- }));
173
- }
174
- if (feat.link) {
175
- exts.push(Link.configure({
176
- openOnClick: false,
177
- HTMLAttributes: { class: "an-rich-md-link" },
178
- }));
179
- }
180
- if (feat.tasks) {
181
- exts.push(TaskList.configure({
182
- HTMLAttributes: { class: "an-rich-md-task-list" },
183
- }), TaskItem.configure({ nested: true }));
184
- }
185
- if (feat.tables) {
186
- exts.push(Table.configure({
187
- resizable: false,
188
- HTMLAttributes: { class: "an-rich-md-table" },
189
- }), TableRow, TableHeader, TableCell);
190
- }
191
- if (feat.markdown) {
192
- exts.push(Markdown.configure(markdown ?? MARKDOWN_DIALECT_CONFIG[dialect]));
193
- }
194
- // Shared block-level image node. The node is named `image`, so when
195
- // `features.markdown` is on, tiptap-markdown serializes it through its
196
- // built-in `defaultMarkdownSerializer.nodes.image` fallback → `![alt](src)`
197
- // (no width-as-HTML override here, so GFM stays byte-stable and
198
- // source-syncable). With an `onImageUpload` it accepts paste/drop uploads.
199
- if (feat.image) {
200
- exts.push(createImageExtension({ onImageUpload }));
201
- }
202
- // App-specific extensions (Notion/media/drag handles/comments). Appended
203
- // before Collaboration so they can extend the schema and Collaboration binds
204
- // over the full set.
205
- if (extraExtensions.length > 0) {
206
- exts.push(...extraExtensions);
207
- }
208
- // Collaborative editing via the shared Y.Doc. Markdown stays the canonical
209
- // saved representation (onChange serializes it); the Y.Doc is transient live
210
- // state only. Appended last so it binds over the configured schema above.
211
- if (ydoc) {
212
- exts.push(Collaboration.configure({ document: ydoc }));
213
- // Live multi-user cursors. Only mounted alongside a Y.Doc so the standalone
214
- // controlled editor (today's plan/content behavior) is untouched.
215
- if (awareness) {
216
- exts.push(CollaborationCaret.configure({
217
- provider: { awareness },
218
- user: user ?? { name: "Anonymous", color: "#999" },
219
- }));
220
- }
221
- }
222
- return exts;
223
- }
224
- //# sourceMappingURL=extensions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/extensions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Extension, Node, Mark } from \"@tiptap/core\";\nimport Collaboration from \"@tiptap/extension-collaboration\";\nimport CollaborationCaret from \"@tiptap/extension-collaboration-caret\";\nimport Link from \"@tiptap/extension-link\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport { Table } from \"@tiptap/extension-table\";\nimport { TableCell } from \"@tiptap/extension-table-cell\";\nimport { TableHeader } from \"@tiptap/extension-table-header\";\nimport { TableRow } from \"@tiptap/extension-table-row\";\nimport TaskItem from \"@tiptap/extension-task-item\";\nimport TaskList from \"@tiptap/extension-task-list\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport type { StarterKitOptions } from \"@tiptap/starter-kit\";\nimport bash from \"highlight.js/lib/languages/bash\";\nimport css from \"highlight.js/lib/languages/css\";\nimport javascript from \"highlight.js/lib/languages/javascript\";\nimport json from \"highlight.js/lib/languages/json\";\nimport markdown from \"highlight.js/lib/languages/markdown\";\nimport python from \"highlight.js/lib/languages/python\";\nimport sql from \"highlight.js/lib/languages/sql\";\nimport typescript from \"highlight.js/lib/languages/typescript\";\nimport xml from \"highlight.js/lib/languages/xml\";\nimport yaml from \"highlight.js/lib/languages/yaml\";\nimport { createLowlight } from \"lowlight\";\nimport { Markdown } from \"tiptap-markdown\";\n\n/**\n * Shared lowlight instance for the editor's syntax-highlighted code blocks. A\n * curated grammar set (aliases like ts/tsx, js/jsx, html, sh, py, yml, md come\n * for free from each grammar) keeps the editor bundle lean while matching the\n * languages the read-side Shiki surfaces (`code-tabs`) support. highlight.js is\n * synchronous, which is what a live ProseMirror editor needs — Shiki is async\n * and only used for read-only render paths.\n */\nconst codeLowlight = createLowlight({\n bash,\n css,\n javascript,\n json,\n markdown,\n python,\n sql,\n typescript,\n xml,\n yaml,\n});\nimport type { Awareness } from \"y-protocols/awareness\";\nimport type { Doc as YDoc } from \"yjs\";\n\nimport { createCodeBlockNode } from \"./CodeBlockNode.js\";\nimport { createImageExtension, type ImageUploadFn } from \"./ImageExtension.js\";\n\n/**\n * Markdown dialect the editor parses/serializes.\n *\n * - `gfm` — GitHub-Flavored Markdown. No raw HTML passthrough. The byte-stable\n * serialization used by Plans (see RichMarkdownEditor.roundtrip.spec.ts).\n * - `nfm` — the Notion-Flavored Markdown superset used by the Content editor,\n * which opts into inline HTML so Notion-specific blocks round-trip.\n */\nexport type RichMarkdownDialect = \"gfm\" | \"nfm\";\n\n/**\n * Editor preset. Schema-neutral today (both presets share the base schema),\n * but threaded through so an app can branch schema/behavior per preset without\n * a new factory. The collab/markdown wiring is preset-independent.\n */\nexport type RichMarkdownEditorPreset = \"plan\" | \"content\";\n\n/** User info used to label this client's collaborative cursor. */\nexport interface RichMarkdownCollabUser {\n name: string;\n color: string;\n email?: string;\n}\n\n/** Optional collaborative-editing inputs for the shared editor. */\nexport interface SharedEditorCollab {\n /**\n * Yjs document for collaborative editing. When present the editor binds the\n * shared {@link Collaboration} (+ {@link CollaborationCaret} when awareness\n * is set) extensions and StarterKit's built-in undo/redo is disabled (Yjs\n * owns history). When absent the editor is a controlled `value`/`onChange`\n * editor.\n */\n ydoc?: YDoc | null;\n /** Shared awareness instance for live multi-user cursors. */\n awareness?: Awareness | null;\n /** Current user info for the collaborative cursor label. */\n user?: RichMarkdownCollabUser | null;\n}\n\n/** Toggle the optional base extensions on/off per app. All default to `true`. */\nexport interface SharedEditorFeatures {\n /** GFM pipe tables (Table + TableRow + TableHeader + TableCell). */\n tables?: boolean;\n /** Task / checklist lists (TaskList + TaskItem). */\n tasks?: boolean;\n /** Inline links (the `Link` mark). When off, links fall back to plain text. */\n link?: boolean;\n /** Fenced code blocks. Disabling lets an app inject its own code-block node. */\n codeBlock?: boolean;\n /**\n * The built-in {@link Placeholder} extension. Default `true`. Apps that need a\n * bespoke placeholder resolver (per-node-type labels, ancestor-aware text)\n * disable this and supply their own Placeholder via `extraExtensions`.\n */\n placeholder?: boolean;\n /**\n * The built-in dialect-keyed {@link Markdown} serializer. Default `true`.\n * Apps with a custom serializer (e.g. Content's NFM converter, which does NOT\n * round-trip through tiptap-markdown's storage) disable this and own the\n * serialize/parse pipeline themselves. The Markdown extension is still added\n * so paste/clipboard transforms work — disable it only when supplying your own\n * Markdown configuration via the {@link CreateSharedEditorExtensionsOptions.markdown}\n * option instead.\n */\n markdown?: boolean;\n /**\n * The shared block-level image node (`@tiptap/extension-image`). Default\n * `false` so existing embedders are unchanged. When `true`, images\n * serialize to GFM `![alt](src)` (source-syncable) and — when an\n * {@link CreateSharedEditorExtensionsOptions.onImageUpload} function is\n * supplied — paste / drop of local image files uploads through it. Content\n * leaves this off and injects its own richer image node via\n * `extraExtensions`, so the two never collide.\n */\n image?: boolean;\n}\n\nexport interface CreateSharedEditorExtensionsOptions {\n /** Markdown dialect; selects the keyed {@link Markdown} config. */\n dialect?: RichMarkdownDialect;\n /** Preset hook (schema-neutral today). */\n preset?: RichMarkdownEditorPreset;\n /** Empty-block placeholder text (headings get their own labels). */\n placeholder?: string;\n /** Toggle individual base extensions. */\n features?: SharedEditorFeatures;\n /**\n * Extra StarterKit options merged over the shared defaults. Lets an app turn\n * off StarterKit nodes it replaces (Content swaps in its own paragraph /\n * blockquote / code block) or pass a custom dropcursor, while still sharing\n * the rest of the StarterKit base + the collab undo/redo gating. The shared\n * defaults (`heading` levels 1-4, `link: false`, the default dropcursor, and\n * `undoRedo: false` in collab mode) are applied first and can be overridden\n * key-by-key here.\n */\n starterKit?: Partial<StarterKitOptions>;\n /**\n * Custom {@link Markdown} configuration. Replaces the dialect-keyed config from\n * {@link MARKDOWN_DIALECT_CONFIG} when provided. Only used when\n * `features.markdown !== false`; apps that own the whole markdown pipeline (no\n * tiptap-markdown serialization at all) should set `features.markdown: false`\n * and add their own configured Markdown extension via `extraExtensions`.\n */\n markdown?: Parameters<typeof Markdown.configure>[0];\n /**\n * App-specific extensions (Notion nodes, media, drag handles, comment\n * anchors, etc.) appended LAST so they bind over the shared base schema and\n * the optional Collaboration extensions still mount after them.\n */\n extraExtensions?: Array<Extension | Node | Mark>;\n /** Optional collaborative-editing wiring. */\n collab?: SharedEditorCollab | null;\n /**\n * Disable StarterKit's built-in undo/redo (prosemirror-history) for a\n * controlled (non-collab) editor whose host owns its own undo authority.\n * Default `false`. When a `collab.ydoc` is present, undo/redo is ALWAYS\n * disabled regardless of this flag (Yjs owns history); this flag is the\n * non-collab equivalent. The plan editor sets it so a single app-level undo\n * stack (over the authoritative `blocks[]` tree, which includes block data\n * the ProseMirror doc never stores) is the sole cmd+z authority — otherwise\n * PM history and the app stack would both fire, and PM history can't see\n * block-option edits at all.\n */\n disableHistory?: boolean;\n /**\n * Injectable image uploader for the shared image block. Only used when\n * `features.image` is on. Turns a picked / pasted / dropped image File into a\n * hosted `{ src, alt? }`. Plans pass `uploadEditorImage` (the framework\n * `upload-image` action). When omitted, the image block still renders and\n * round-trips `![alt](src)` markdown but cannot ingest local files.\n */\n onImageUpload?: ImageUploadFn | null;\n}\n\n/**\n * tiptap-markdown configuration, keyed by dialect. This is the single source of\n * truth for how each dialect parses/serializes markdown so the editor component\n * and the round-trip fidelity test can never drift apart.\n *\n * tiptap-markdown re-serializes the whole document on every edit, so the goal\n * for GFM is `serialize(parse(markdown)) === markdown` for the markdown plans\n * actually contain. We deliberately keep tiptap-markdown's own defaults\n * (`bulletListMarker: \"-\"`, `tightLists: true`, `linkify: false`,\n * `breaks: false`) because those produce the most byte-stable GFM. See\n * RichMarkdownEditor.roundtrip.spec.ts for the pinned corpus.\n *\n * NFM (Content) opts into inline HTML passthrough (`html: true`) so\n * Notion-specific blocks survive a markdown round-trip; the rest mirrors the\n * Content editor's existing `Markdown.configure` call.\n */\nexport const MARKDOWN_DIALECT_CONFIG: Record<\n RichMarkdownDialect,\n Parameters<typeof Markdown.configure>[0]\n> = {\n gfm: {\n // GFM plans are the common case and must never gain raw HTML as a second\n // representation.\n html: false,\n // Keep tiptap-markdown's defaults that minimise first-edit normalisation\n // churn (see roundtrip spec). Listed explicitly so the contract is\n // self-documenting rather than relying on the package defaults.\n bulletListMarker: \"-\",\n tightLists: true,\n linkify: false,\n breaks: false,\n transformPastedText: true,\n transformCopiedText: true,\n },\n nfm: {\n // NFM is a superset that allows inline HTML so Notion blocks round-trip.\n html: true,\n transformPastedText: true,\n transformCopiedText: true,\n },\n};\n\nconst DEFAULT_FEATURES: Required<SharedEditorFeatures> = {\n tables: true,\n tasks: true,\n link: true,\n codeBlock: true,\n placeholder: true,\n markdown: true,\n // Off by default: only Plans opt in today. Content injects its own richer\n // image node via `extraExtensions` and must not get a second `image` node.\n image: false,\n};\n\n/**\n * The ONE editor extension factory shared by every embedder (Plans today,\n * Content next). It assembles the base Tiptap schema (StarterKit + Placeholder\n * + Link + tasks + tables + code block), the dialect-keyed {@link Markdown}\n * serializer, the optional Collaboration stack, and finally any app-specific\n * `extraExtensions`.\n *\n * Ordering matters:\n * 1. Base schema (StarterKit first so its nodes/marks register; `starterKit`\n * overrides let an app disable replaced nodes / swap the dropcursor).\n * 2. dialect-keyed Markdown serializer (suppressible via `features.markdown`\n * for apps that own the whole serialize/parse pipeline, e.g. Content's NFM).\n * 3. `extraExtensions` (Notion/media/etc.) — appended before Collaboration so\n * apps can extend the schema and Collaboration still binds over the full\n * schema.\n * 4. Collaboration (+ CollaborationCaret) LAST so they bind over everything.\n *\n * Content (the NFM editor) drives this factory with `features.placeholder` and\n * `features.markdown` off, `features.tasks/tables/link` off where it ships its\n * own, a `starterKit` override disabling paragraph/blockquote/codeBlock, and all\n * Notion/media/fidelity nodes + its own Markdown(NFM)/Placeholder via\n * `extraExtensions` — so it shares the StarterKit base + the collab wiring while\n * owning its byte-identical NFM serializer.\n */\nexport function createSharedEditorExtensions({\n dialect = \"gfm\",\n // `preset` is accepted and forwarded for future preset-specific schema\n // branches; it is currently schema-neutral.\n preset: _preset = \"plan\",\n placeholder = \"Type '/' for commands...\",\n features,\n starterKit,\n markdown,\n extraExtensions = [],\n collab = null,\n onImageUpload = null,\n disableHistory = false,\n}: CreateSharedEditorExtensionsOptions = {}): Array<Extension | Node | Mark> {\n const feat = { ...DEFAULT_FEATURES, ...(features ?? {}) };\n const ydoc = collab?.ydoc ?? null;\n const awareness = collab?.awareness ?? null;\n const user = collab?.user ?? null;\n\n const exts: Array<Extension | Node | Mark> = [\n StarterKit.configure({\n heading: { levels: [1, 2, 3, 4] },\n link: false,\n // StarterKit's plain code block is always disabled; when enabled we add the\n // syntax-highlighting `CodeBlockLowlight` (same `codeBlock` node) below.\n codeBlock: false,\n dropcursor: { color: \"hsl(var(--ring))\", width: 2 },\n // Yjs owns undo/redo when Collaboration is active; the StarterKit history\n // plugin and the CRDT cannot both track undo without corrupting state.\n // `disableHistory` is the non-collab equivalent: a controlled editor whose\n // host (e.g. the plan editor) owns a single app-level undo authority.\n ...(ydoc || disableHistory ? { undoRedo: false } : {}),\n // App overrides last so embedders can disable replaced nodes (paragraph,\n // blockquote, code block) or swap the dropcursor while keeping the shared\n // base + the collab undo/redo gating above.\n ...(starterKit ?? {}),\n }),\n ];\n\n // Notion-style syntax-highlighted code block (replaces StarterKit's plain one)\n // only when the embedder opts in via `features.codeBlock`. The shared node adds\n // a language picker header (Auto-detects by default) over `CodeBlockLowlight`,\n // so fenced markdown still round-trips byte-identically. Content disables this\n // and ships its own code node, so this affects Plans (and future opt-in apps)\n // alone.\n if (feat.codeBlock) {\n exts.push(createCodeBlockNode({ lowlight: codeLowlight }));\n }\n\n if (feat.placeholder) {\n exts.push(\n Placeholder.configure({\n placeholder: ({ node }) => {\n if (node.type.name === \"heading\") {\n const level = node.attrs.level;\n if (level === 1) return \"Heading 1\";\n if (level === 2) return \"Heading 2\";\n if (level === 3) return \"Heading 3\";\n return \"Heading 4\";\n }\n return placeholder;\n },\n showOnlyWhenEditable: true,\n showOnlyCurrent: true,\n }),\n );\n }\n\n if (feat.link) {\n exts.push(\n Link.configure({\n openOnClick: false,\n HTMLAttributes: { class: \"an-rich-md-link\" },\n }),\n );\n }\n\n if (feat.tasks) {\n exts.push(\n TaskList.configure({\n HTMLAttributes: { class: \"an-rich-md-task-list\" },\n }),\n TaskItem.configure({ nested: true }),\n );\n }\n\n if (feat.tables) {\n exts.push(\n Table.configure({\n resizable: false,\n HTMLAttributes: { class: \"an-rich-md-table\" },\n }),\n TableRow,\n TableHeader,\n TableCell,\n );\n }\n\n if (feat.markdown) {\n exts.push(Markdown.configure(markdown ?? MARKDOWN_DIALECT_CONFIG[dialect]));\n }\n\n // Shared block-level image node. The node is named `image`, so when\n // `features.markdown` is on, tiptap-markdown serializes it through its\n // built-in `defaultMarkdownSerializer.nodes.image` fallback → `![alt](src)`\n // (no width-as-HTML override here, so GFM stays byte-stable and\n // source-syncable). With an `onImageUpload` it accepts paste/drop uploads.\n if (feat.image) {\n exts.push(createImageExtension({ onImageUpload }));\n }\n\n // App-specific extensions (Notion/media/drag handles/comments). Appended\n // before Collaboration so they can extend the schema and Collaboration binds\n // over the full set.\n if (extraExtensions.length > 0) {\n exts.push(...extraExtensions);\n }\n\n // Collaborative editing via the shared Y.Doc. Markdown stays the canonical\n // saved representation (onChange serializes it); the Y.Doc is transient live\n // state only. Appended last so it binds over the configured schema above.\n if (ydoc) {\n exts.push(Collaboration.configure({ document: ydoc }));\n // Live multi-user cursors. Only mounted alongside a Y.Doc so the standalone\n // controlled editor (today's plan/content behavior) is untouched.\n if (awareness) {\n exts.push(\n CollaborationCaret.configure({\n provider: { awareness },\n user: user ?? { name: \"Anonymous\", color: \"#999\" },\n }),\n );\n }\n }\n\n return exts;\n}\n"]}
@@ -1,24 +0,0 @@
1
- import { type JSONContent } from "@tiptap/core";
2
- /**
3
- * Parse a GFM markdown string into an array of top-level ProseMirror node JSON
4
- * (paragraph / heading / list / table / code block / etc.), matching the live
5
- * plan editor schema (`createSharedEditorExtensions({ dialect: "gfm",
6
- * features: { image: true } })`) plus the {@link RunId} attribute.
7
- *
8
- * `tiptap-markdown` registers the markdown parser, so handing the raw markdown
9
- * string to `setContent` deserializes it (the same path the live editor uses
10
- * when it seeds `content: markdown`). Returns the doc's child nodes; an empty
11
- * string yields a single empty paragraph.
12
- */
13
- export declare function gfmToProseJSON(markdown: string): JSONContent[];
14
- /**
15
- * Serialize an array of top-level ProseMirror node JSON into GFM markdown. The
16
- * `runId` attribute is omitted by GFM (the {@link RunId} extension registers no
17
- * markdown serializer), so it never leaks into the saved markdown.
18
- *
19
- * The nodes are wrapped in a `doc` and set on the shared editor, then the GFM
20
- * markdown is read from the tiptap-markdown storage — the exact serializer the
21
- * live editor persists with, so output is byte-stable with the live save path.
22
- */
23
- export declare function proseJSONToGfm(nodes: JSONContent[]): string;
24
- //# sourceMappingURL=gfmDoc.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gfmDoc.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/gfmDoc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AA0DxD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAM9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAK3D"}
@@ -1,83 +0,0 @@
1
- import { Editor } from "@tiptap/core";
2
- import { createSharedEditorExtensions } from "./extensions.js";
3
- import { RunId } from "./RunId.js";
4
- /**
5
- * The GFM ↔ ProseMirror primitive for the plan single-doc editor.
6
- *
7
- * Plans keep `PlanContent.blocks[]` as the source of truth, but the editor is
8
- * ONE ProseMirror/Tiptap document. The `doc ↔ blocks[]` serializer
9
- * (`templates/plan/shared/plan-doc.ts`) needs to turn a `rich-text` block's GFM
10
- * markdown into prose nodes and back. This module is that primitive.
11
- *
12
- * Both directions go through a SINGLE headless Tiptap {@link Editor} built from
13
- * the exact same `createSharedEditorExtensions` config the live plan editor
14
- * uses (`dialect: "gfm"`, `features.image: true`) plus the {@link RunId}
15
- * extension, so the schema and the GFM serializer can never drift from the live
16
- * editor. The instance is created lazily on first use and reused across calls.
17
- *
18
- * The headless editor needs a DOM (ProseMirror's `EditorView`). It works under
19
- * `happy-dom` in vitest (see `gfmDoc.spec.ts`) and under the real browser DOM
20
- * in production. `createElement` is used rather than mounting into the page so
21
- * nothing is ever attached to the document.
22
- */
23
- let sharedEditor = null;
24
- /**
25
- * Lazily build (and memoize) the single headless editor. Throws if no DOM is
26
- * available — this primitive is for the client / jsdom-style test envs only.
27
- */
28
- function getSharedEditor() {
29
- if (sharedEditor)
30
- return sharedEditor;
31
- if (typeof document === "undefined") {
32
- throw new Error("gfmDoc requires a DOM (document). It runs in the browser and in jsdom/happy-dom tests, not in a bare Node server context.");
33
- }
34
- sharedEditor = new Editor({
35
- element: document.createElement("div"),
36
- extensions: createSharedEditorExtensions({
37
- dialect: "gfm",
38
- features: { image: true },
39
- extraExtensions: [RunId],
40
- }),
41
- content: "",
42
- });
43
- return sharedEditor;
44
- }
45
- /** Reads the GFM markdown out of the tiptap-markdown storage. */
46
- function getMarkdown(editor) {
47
- const storage = editor.storage;
48
- return storage.markdown?.getMarkdown?.() ?? "";
49
- }
50
- /**
51
- * Parse a GFM markdown string into an array of top-level ProseMirror node JSON
52
- * (paragraph / heading / list / table / code block / etc.), matching the live
53
- * plan editor schema (`createSharedEditorExtensions({ dialect: "gfm",
54
- * features: { image: true } })`) plus the {@link RunId} attribute.
55
- *
56
- * `tiptap-markdown` registers the markdown parser, so handing the raw markdown
57
- * string to `setContent` deserializes it (the same path the live editor uses
58
- * when it seeds `content: markdown`). Returns the doc's child nodes; an empty
59
- * string yields a single empty paragraph.
60
- */
61
- export function gfmToProseJSON(markdown) {
62
- const editor = getSharedEditor();
63
- // `emitUpdate: false` keeps this a pure transform with no side effects on any
64
- // (non-existent) consumers of the headless editor's update stream.
65
- editor.commands.setContent(markdown, { emitUpdate: false });
66
- return editor.getJSON().content ?? [];
67
- }
68
- /**
69
- * Serialize an array of top-level ProseMirror node JSON into GFM markdown. The
70
- * `runId` attribute is omitted by GFM (the {@link RunId} extension registers no
71
- * markdown serializer), so it never leaks into the saved markdown.
72
- *
73
- * The nodes are wrapped in a `doc` and set on the shared editor, then the GFM
74
- * markdown is read from the tiptap-markdown storage — the exact serializer the
75
- * live editor persists with, so output is byte-stable with the live save path.
76
- */
77
- export function proseJSONToGfm(nodes) {
78
- const editor = getSharedEditor();
79
- const content = nodes.length > 0 ? nodes : [{ type: "paragraph" }];
80
- editor.commands.setContent({ type: "doc", content }, { emitUpdate: false });
81
- return getMarkdown(editor);
82
- }
83
- //# sourceMappingURL=gfmDoc.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gfmDoc.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/gfmDoc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAoB,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AAEH,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC;;;GAGG;AACH,SAAS,eAAe;IACtB,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,2HAA2H,CAC5H,CAAC;IACJ,CAAC;IACD,YAAY,GAAG,IAAI,MAAM,CAAC;QACxB,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;QACtC,UAAU,EAAE,4BAA4B,CAAC;YACvC,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;YACzB,eAAe,EAAE,CAAC,KAAK,CAAC;SACzB,CAAC;QACF,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IACH,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,iEAAiE;AACjE,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAEtB,CAAC;IACF,OAAO,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,8EAA8E;IAC9E,mEAAmE;IACnE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["import { Editor, type JSONContent } from \"@tiptap/core\";\n\nimport { createSharedEditorExtensions } from \"./extensions.js\";\nimport { RunId } from \"./RunId.js\";\n\n/**\n * The GFM ↔ ProseMirror primitive for the plan single-doc editor.\n *\n * Plans keep `PlanContent.blocks[]` as the source of truth, but the editor is\n * ONE ProseMirror/Tiptap document. The `doc ↔ blocks[]` serializer\n * (`templates/plan/shared/plan-doc.ts`) needs to turn a `rich-text` block's GFM\n * markdown into prose nodes and back. This module is that primitive.\n *\n * Both directions go through a SINGLE headless Tiptap {@link Editor} built from\n * the exact same `createSharedEditorExtensions` config the live plan editor\n * uses (`dialect: \"gfm\"`, `features.image: true`) plus the {@link RunId}\n * extension, so the schema and the GFM serializer can never drift from the live\n * editor. The instance is created lazily on first use and reused across calls.\n *\n * The headless editor needs a DOM (ProseMirror's `EditorView`). It works under\n * `happy-dom` in vitest (see `gfmDoc.spec.ts`) and under the real browser DOM\n * in production. `createElement` is used rather than mounting into the page so\n * nothing is ever attached to the document.\n */\n\nlet sharedEditor: Editor | null = null;\n\n/**\n * Lazily build (and memoize) the single headless editor. Throws if no DOM is\n * available — this primitive is for the client / jsdom-style test envs only.\n */\nfunction getSharedEditor(): Editor {\n if (sharedEditor) return sharedEditor;\n if (typeof document === \"undefined\") {\n throw new Error(\n \"gfmDoc requires a DOM (document). It runs in the browser and in jsdom/happy-dom tests, not in a bare Node server context.\",\n );\n }\n sharedEditor = new Editor({\n element: document.createElement(\"div\"),\n extensions: createSharedEditorExtensions({\n dialect: \"gfm\",\n features: { image: true },\n extraExtensions: [RunId],\n }),\n content: \"\",\n });\n return sharedEditor;\n}\n\n/** Reads the GFM markdown out of the tiptap-markdown storage. */\nfunction getMarkdown(editor: Editor): string {\n const storage = editor.storage as unknown as {\n markdown?: { getMarkdown?: () => string };\n };\n return storage.markdown?.getMarkdown?.() ?? \"\";\n}\n\n/**\n * Parse a GFM markdown string into an array of top-level ProseMirror node JSON\n * (paragraph / heading / list / table / code block / etc.), matching the live\n * plan editor schema (`createSharedEditorExtensions({ dialect: \"gfm\",\n * features: { image: true } })`) plus the {@link RunId} attribute.\n *\n * `tiptap-markdown` registers the markdown parser, so handing the raw markdown\n * string to `setContent` deserializes it (the same path the live editor uses\n * when it seeds `content: markdown`). Returns the doc's child nodes; an empty\n * string yields a single empty paragraph.\n */\nexport function gfmToProseJSON(markdown: string): JSONContent[] {\n const editor = getSharedEditor();\n // `emitUpdate: false` keeps this a pure transform with no side effects on any\n // (non-existent) consumers of the headless editor's update stream.\n editor.commands.setContent(markdown, { emitUpdate: false });\n return editor.getJSON().content ?? [];\n}\n\n/**\n * Serialize an array of top-level ProseMirror node JSON into GFM markdown. The\n * `runId` attribute is omitted by GFM (the {@link RunId} extension registers no\n * markdown serializer), so it never leaks into the saved markdown.\n *\n * The nodes are wrapped in a `doc` and set on the shared editor, then the GFM\n * markdown is read from the tiptap-markdown storage — the exact serializer the\n * live editor persists with, so output is byte-stable with the live save path.\n */\nexport function proseJSONToGfm(nodes: JSONContent[]): string {\n const editor = getSharedEditor();\n const content = nodes.length > 0 ? nodes : [{ type: \"paragraph\" }];\n editor.commands.setContent({ type: \"doc\", content }, { emitUpdate: false });\n return getMarkdown(editor);\n}\n"]}
@@ -1,66 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"surgical-apply.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-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"}
@@ -1,147 +0,0 @@
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