@ecsplico/editor 3.6.0 → 4.0.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 (578) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/adapters/direct-ai.d.ts +4 -4
  3. package/dist/adapters/direct-ai.js +2 -2
  4. package/dist/adapters/direct-ai.js.map +1 -1
  5. package/dist/adapters/document-state.d.ts +1 -1
  6. package/dist/adapters/document-state.js.map +1 -1
  7. package/dist/adapters/forge.d.ts +2 -2
  8. package/dist/adapters/forge.js.map +1 -1
  9. package/dist/adapters/nitro.d.ts +11 -3
  10. package/dist/adapters/nitro.js +3 -1
  11. package/dist/adapters/nitro.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +6 -6
  13. package/dist/adapters/shared.js.map +1 -1
  14. package/dist/config/index.d.ts +14 -14
  15. package/dist/config/index.js +8 -8
  16. package/dist/config/index.js.map +1 -1
  17. package/dist/core/backend-types.d.ts +3 -3
  18. package/dist/core/backend-types.js.map +1 -1
  19. package/dist/core/backend.d.ts +4 -4
  20. package/dist/core/backend.js.map +1 -1
  21. package/dist/core/block-convert.d.ts +1 -1
  22. package/dist/core/block-convert.js +5 -5
  23. package/dist/core/block-convert.js.map +1 -1
  24. package/dist/core/block-transfer.d.ts +8 -4
  25. package/dist/core/block-transfer.js +23 -14
  26. package/dist/core/block-transfer.js.map +1 -1
  27. package/dist/core/capabilities.d.ts +113 -0
  28. package/dist/core/capabilities.js +155 -0
  29. package/dist/core/capabilities.js.map +1 -0
  30. package/dist/core/command-types.d.ts +1 -1
  31. package/dist/core/context.js.map +1 -1
  32. package/dist/core/convert.d.ts +5 -5
  33. package/dist/core/convert.js +5 -5
  34. package/dist/core/convert.js.map +1 -1
  35. package/dist/core/core-feature.js +1 -1
  36. package/dist/core/define-editor.d.ts +2 -2
  37. package/dist/core/define-editor.js +34 -6
  38. package/dist/core/define-editor.js.map +1 -1
  39. package/dist/core/derivation.d.ts +119 -0
  40. package/dist/core/derivation.js +187 -0
  41. package/dist/core/derivation.js.map +1 -0
  42. package/dist/core/derive.d.ts +61 -0
  43. package/dist/core/derive.js +69 -0
  44. package/dist/core/derive.js.map +1 -0
  45. package/dist/core/extension-points.d.ts +16 -0
  46. package/dist/core/feature-context.d.ts +5 -1
  47. package/dist/core/feature-context.js +10 -3
  48. package/dist/core/feature-context.js.map +1 -1
  49. package/dist/core/feature.d.ts +41 -19
  50. package/dist/core/feature.js.map +1 -1
  51. package/dist/core/fences.js +1 -1
  52. package/dist/core/fences.js.map +1 -1
  53. package/dist/core/index.d.ts +6 -2
  54. package/dist/core/index.js +5 -1
  55. package/dist/core/pipeline.d.ts +14 -5
  56. package/dist/core/pipeline.js +19 -7
  57. package/dist/core/pipeline.js.map +1 -1
  58. package/dist/core/properties.d.ts +22 -0
  59. package/dist/core/properties.js +17 -0
  60. package/dist/core/properties.js.map +1 -0
  61. package/dist/core/schema/block-ids.js +5 -5
  62. package/dist/core/schema/block-ids.js.map +1 -1
  63. package/dist/core/schema/index.d.ts +2 -1
  64. package/dist/core/schema/index.js +2 -1
  65. package/dist/core/schema/index.js.map +1 -1
  66. package/dist/core/schema/opaque-fence.d.ts +4 -4
  67. package/dist/core/schema/opaque-fence.js +7 -7
  68. package/dist/core/schema/opaque-fence.js.map +1 -1
  69. package/dist/core/schema/persisted-names.d.ts +58 -0
  70. package/dist/core/schema/persisted-names.js +96 -0
  71. package/dist/core/schema/persisted-names.js.map +1 -0
  72. package/dist/core/toolbar-items.js +1 -1
  73. package/dist/core/toolbar-items.js.map +1 -1
  74. package/dist/core/util.js +5 -1
  75. package/dist/core/util.js.map +1 -1
  76. package/dist/features/ai/agent-ops.js +1 -1
  77. package/dist/features/ai/ai-review.js +1 -1
  78. package/dist/features/ai/assistant.d.ts +4 -4
  79. package/dist/features/ai/assistant.js +1 -1
  80. package/dist/features/ai/assistant.js.map +1 -1
  81. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  82. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  83. package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
  84. package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
  85. package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
  86. package/dist/features/ai/components/SettingsAiTab.js +8 -8
  87. package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
  88. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  89. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  90. package/dist/features/ai/document-chat-model.d.ts +2 -2
  91. package/dist/features/ai/document-chat-model.js +5 -5
  92. package/dist/features/ai/document-chat-model.js.map +1 -1
  93. package/dist/features/ai/document-chat.js +2 -2
  94. package/dist/features/ai/document-chat.js.map +1 -1
  95. package/dist/features/ai/feature.d.ts +2 -2
  96. package/dist/features/ai/feature.js +2 -2
  97. package/dist/features/ai/feature.js.map +1 -1
  98. package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
  99. package/dist/features/ai/ghost-autocomplete.js +1 -1
  100. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  101. package/dist/features/ai/index.d.ts +3 -3
  102. package/dist/features/ai/index.js +2 -2
  103. package/dist/features/ai/model-profiles.d.ts +9 -9
  104. package/dist/features/ai/model-profiles.js +13 -13
  105. package/dist/features/ai/model-profiles.js.map +1 -1
  106. package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
  107. package/dist/features/ai/protocol/agent-ops.js +1 -1
  108. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  109. package/dist/features/ai/protocol/block-lines.d.ts +7 -7
  110. package/dist/features/ai/protocol/block-lines.js +10 -10
  111. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  112. package/dist/features/ai/protocol/chat.d.ts +5 -5
  113. package/dist/features/ai/protocol/chat.js +12 -12
  114. package/dist/features/ai/protocol/chat.js.map +1 -1
  115. package/dist/features/ai/protocol/generate.d.ts +1 -1
  116. package/dist/features/ai/protocol/generate.js +1 -1
  117. package/dist/features/ai/protocol/generate.js.map +1 -1
  118. package/dist/features/ai/protocol/index.d.ts +3 -3
  119. package/dist/features/ai/protocol/index.js +2 -2
  120. package/dist/features/ai/protocol/models.d.ts +3 -3
  121. package/dist/features/ai/protocol/models.js +3 -3
  122. package/dist/features/ai/protocol/models.js.map +1 -1
  123. package/dist/features/ai/protocol/schemas.d.ts +1 -1
  124. package/dist/features/ai/protocol/schemas.js +1 -1
  125. package/dist/features/ai/protocol/schemas.js.map +1 -1
  126. package/dist/features/ai/protocol/tasks.d.ts +5 -5
  127. package/dist/features/ai/protocol/tasks.js +12 -12
  128. package/dist/features/ai/protocol/tasks.js.map +1 -1
  129. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  130. package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
  131. package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
  132. package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
  133. package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
  134. package/dist/features/ai/react/SettingsAiTab.js +8 -8
  135. package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
  136. package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
  137. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  138. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  139. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  140. package/dist/features/ai/react/use-ai-assistant.js +1 -1
  141. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  142. package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
  143. package/dist/features/ai/react/use-model-profiles.js +2 -2
  144. package/dist/features/ai/react/use-model-profiles.js.map +1 -1
  145. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  146. package/dist/features/ai/use-ai-assistant.js +1 -1
  147. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  148. package/dist/features/ai/use-model-profiles.d.ts +4 -4
  149. package/dist/features/ai/use-model-profiles.js +2 -2
  150. package/dist/features/ai/use-model-profiles.js.map +1 -1
  151. package/dist/features/block-ui/block-actions.d.ts +8 -4
  152. package/dist/features/block-ui/block-actions.js +38 -22
  153. package/dist/features/block-ui/block-actions.js.map +1 -1
  154. package/dist/features/block-ui/block-target.d.ts +29 -0
  155. package/dist/features/block-ui/block-target.js +63 -0
  156. package/dist/features/block-ui/block-target.js.map +1 -0
  157. package/dist/features/block-ui/components/BlockHandles.js +3 -3
  158. package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
  159. package/dist/features/block-ui/components/BlockUi.js +11 -23
  160. package/dist/features/block-ui/components/BlockUi.js.map +1 -1
  161. package/dist/features/block-ui/feature.d.ts +3 -2
  162. package/dist/features/block-ui/feature.js +3 -2
  163. package/dist/features/block-ui/feature.js.map +1 -1
  164. package/dist/features/block-ui/handle-geometry.js +12 -23
  165. package/dist/features/block-ui/handle-geometry.js.map +1 -1
  166. package/dist/features/block-ui/index.d.ts +2 -1
  167. package/dist/features/block-ui/index.js +2 -1
  168. package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
  169. package/dist/features/block-ui/react/BlockHandles.js +4 -4
  170. package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
  171. package/dist/features/block-ui/react/BlockUi.js +13 -25
  172. package/dist/features/block-ui/react/BlockUi.js.map +1 -1
  173. package/dist/features/comments/model.js +1 -1
  174. package/dist/features/composites/accepted-children.d.ts +5 -4
  175. package/dist/features/composites/accepted-children.js +26 -26
  176. package/dist/features/composites/accepted-children.js.map +1 -1
  177. package/dist/features/composites/ai-brief.d.ts +4 -4
  178. package/dist/features/composites/ai-brief.js +14 -12
  179. package/dist/features/composites/ai-brief.js.map +1 -1
  180. package/dist/features/composites/anchors.d.ts +1 -1
  181. package/dist/features/composites/anchors.js.map +1 -1
  182. package/dist/features/composites/baskets.d.ts +1 -1
  183. package/dist/features/composites/baskets.js.map +1 -1
  184. package/dist/features/composites/bibliography-command.d.ts +1 -1
  185. package/dist/features/composites/bibliography-form.js +1 -1
  186. package/dist/features/composites/bibliography-form.js.map +1 -1
  187. package/dist/features/composites/bibliography.js.map +1 -1
  188. package/dist/features/composites/block-types-json.d.ts +38 -0
  189. package/dist/features/composites/block-types-json.js +122 -0
  190. package/dist/features/composites/block-types-json.js.map +1 -0
  191. package/dist/features/composites/block-types.d.ts +119 -0
  192. package/dist/features/composites/block-types.js +343 -0
  193. package/dist/features/composites/block-types.js.map +1 -0
  194. package/dist/features/composites/capabilities.js +109 -0
  195. package/dist/features/composites/capabilities.js.map +1 -0
  196. package/dist/features/composites/components/BibliographyEditor.js +5 -5
  197. package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
  198. package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
  199. package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
  200. package/dist/features/composites/components/CompositeChrome.js +18 -8
  201. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  202. package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
  203. package/dist/features/composites/components/CompositeDetails.js +11 -10
  204. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  205. package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
  206. package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
  207. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  208. package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
  209. package/dist/features/composites/components/CompositeInspector.js +136 -113
  210. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  211. package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
  212. package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
  213. package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
  214. package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
  215. package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
  216. package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
  217. package/dist/features/composites/components/CompositeTable.js +2 -2
  218. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  219. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  220. package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
  221. package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
  222. package/dist/features/composites/components/CompositeView.js +19 -17
  223. package/dist/features/composites/components/CompositeView.js.map +1 -1
  224. package/dist/features/composites/components/DerivationBadge.js +15 -6
  225. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  226. package/dist/features/composites/components/FocusChip.js +1 -1
  227. package/dist/features/composites/components/FocusChip.js.map +1 -1
  228. package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
  229. package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
  230. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
  231. package/dist/features/composites/components/ReferenceView.js +1 -1
  232. package/dist/features/composites/components/ReferenceView.js.map +1 -1
  233. package/dist/features/composites/components/SettingsEditingTab.js +18 -18
  234. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  235. package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
  236. package/dist/features/composites/convert.d.ts +4 -4
  237. package/dist/features/composites/convert.js +27 -28
  238. package/dist/features/composites/convert.js.map +1 -1
  239. package/dist/features/composites/derived-chrome.js +34 -28
  240. package/dist/features/composites/derived-chrome.js.map +1 -1
  241. package/dist/features/composites/editing-settings-keys.js +6 -6
  242. package/dist/features/composites/editing-settings-keys.js.map +1 -1
  243. package/dist/features/composites/feature.d.ts +10 -10
  244. package/dist/features/composites/feature.js +58 -46
  245. package/dist/features/composites/feature.js.map +1 -1
  246. package/dist/features/composites/fences.d.ts +3 -3
  247. package/dist/features/composites/fences.js +18 -13
  248. package/dist/features/composites/fences.js.map +1 -1
  249. package/dist/features/composites/focus.d.ts +10 -10
  250. package/dist/features/composites/focus.js +11 -11
  251. package/dist/features/composites/focus.js.map +1 -1
  252. package/dist/features/composites/heading-composites.d.ts +5 -5
  253. package/dist/features/composites/heading-composites.js +13 -16
  254. package/dist/features/composites/heading-composites.js.map +1 -1
  255. package/dist/features/composites/index.d.ts +20 -18
  256. package/dist/features/composites/index.js +9 -7
  257. package/dist/features/composites/inspector-model.d.ts +45 -22
  258. package/dist/features/composites/inspector-model.js +53 -14
  259. package/dist/features/composites/inspector-model.js.map +1 -1
  260. package/dist/features/composites/legacy.d.ts +5 -4
  261. package/dist/features/composites/legacy.js +16 -23
  262. package/dist/features/composites/legacy.js.map +1 -1
  263. package/dist/features/composites/markdown-export.js +3 -3
  264. package/dist/features/composites/markdown-export.js.map +1 -1
  265. package/dist/features/composites/merge.d.ts +8 -8
  266. package/dist/features/composites/merge.js +23 -22
  267. package/dist/features/composites/merge.js.map +1 -1
  268. package/dist/features/composites/meta-display.js +5 -5
  269. package/dist/features/composites/meta-display.js.map +1 -1
  270. package/dist/features/composites/meta-keys.d.ts +5 -5
  271. package/dist/features/composites/meta-keys.js +8 -8
  272. package/dist/features/composites/meta-keys.js.map +1 -1
  273. package/dist/features/composites/node-views.d.ts +3 -3
  274. package/dist/features/composites/node-views.js +2 -2
  275. package/dist/features/composites/node-views.js.map +1 -1
  276. package/dist/features/composites/nodes.d.ts +13 -13
  277. package/dist/features/composites/nodes.js +100 -77
  278. package/dist/features/composites/nodes.js.map +1 -1
  279. package/dist/features/composites/outline.d.ts +15 -12
  280. package/dist/features/composites/outline.js +24 -21
  281. package/dist/features/composites/outline.js.map +1 -1
  282. package/dist/features/composites/properties.d.ts +51 -0
  283. package/dist/features/composites/properties.js +89 -0
  284. package/dist/features/composites/properties.js.map +1 -0
  285. package/dist/features/composites/react/BibliographyEditor.js +5 -5
  286. package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
  287. package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
  288. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
  289. package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
  290. package/dist/features/composites/react/CompositeChrome.js +15 -6
  291. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  292. package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
  293. package/dist/features/composites/react/CompositeDetails.js +11 -10
  294. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  295. package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
  296. package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
  297. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  298. package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
  299. package/dist/features/composites/react/CompositeInspector.js +142 -128
  300. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  301. package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
  302. package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
  303. package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
  304. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  305. package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
  306. package/dist/features/composites/react/CompositeTable.d.ts +1 -1
  307. package/dist/features/composites/react/CompositeTable.js +3 -3
  308. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  309. package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
  310. package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
  312. package/dist/features/composites/react/CompositeView.js +17 -15
  313. package/dist/features/composites/react/CompositeView.js.map +1 -1
  314. package/dist/features/composites/react/DerivationBadge.js +13 -4
  315. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  316. package/dist/features/composites/react/FocusChip.d.ts +1 -1
  317. package/dist/features/composites/react/FocusChip.js +1 -1
  318. package/dist/features/composites/react/FocusChip.js.map +1 -1
  319. package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
  320. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
  321. package/dist/features/composites/react/ReferenceView.d.ts +1 -1
  322. package/dist/features/composites/react/ReferenceView.js +1 -1
  323. package/dist/features/composites/react/ReferenceView.js.map +1 -1
  324. package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
  325. package/dist/features/composites/react/SettingsEditingTab.js +20 -20
  326. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  327. package/dist/features/composites/react.js +1 -1
  328. package/dist/features/composites/react.js.map +1 -1
  329. package/dist/features/composites/reference-ai.js +1 -1
  330. package/dist/features/composites/reference-ai.js.map +1 -1
  331. package/dist/features/composites/reference-label.d.ts +3 -3
  332. package/dist/features/composites/reference-label.js +6 -6
  333. package/dist/features/composites/reference-label.js.map +1 -1
  334. package/dist/features/composites/reference-suggestion.d.ts +1 -1
  335. package/dist/features/composites/reference-suggestion.js +3 -3
  336. package/dist/features/composites/reference-suggestion.js.map +1 -1
  337. package/dist/features/composites/reference-text.d.ts +2 -2
  338. package/dist/features/composites/reference-text.js +4 -4
  339. package/dist/features/composites/reference-text.js.map +1 -1
  340. package/dist/features/composites/reference.d.ts +3 -3
  341. package/dist/features/composites/reference.js +1 -1
  342. package/dist/features/composites/reference.js.map +1 -1
  343. package/dist/features/composites/reveal-source.d.ts +3 -3
  344. package/dist/features/composites/reveal-source.js +6 -6
  345. package/dist/features/composites/reveal-source.js.map +1 -1
  346. package/dist/features/composites/rows-model.d.ts +2 -2
  347. package/dist/features/composites/rows-model.js +4 -3
  348. package/dist/features/composites/rows-model.js.map +1 -1
  349. package/dist/features/composites/rows.d.ts +16 -28
  350. package/dist/features/composites/rows.js +20 -54
  351. package/dist/features/composites/rows.js.map +1 -1
  352. package/dist/features/composites/schema.d.ts +12 -11
  353. package/dist/features/composites/schema.js +10 -9
  354. package/dist/features/composites/schema.js.map +1 -1
  355. package/dist/features/composites/source.d.ts +20 -0
  356. package/dist/features/composites/source.js +40 -0
  357. package/dist/features/composites/source.js.map +1 -0
  358. package/dist/features/composites/split.d.ts +11 -11
  359. package/dist/features/composites/split.js +20 -20
  360. package/dist/features/composites/split.js.map +1 -1
  361. package/dist/features/composites/structure-mode.js +3 -3
  362. package/dist/features/composites/structure-mode.js.map +1 -1
  363. package/dist/features/composites/table-model.js +2 -2
  364. package/dist/features/composites/table-model.js.map +1 -1
  365. package/dist/features/composites/use-composite-inspector.js +3 -1
  366. package/dist/features/composites/use-composite-inspector.js.map +1 -1
  367. package/dist/features/composites/use-composite-rows.d.ts +2 -2
  368. package/dist/features/composites/use-composite-rows.js.map +1 -1
  369. package/dist/features/composites/vue.js +1 -1
  370. package/dist/features/composites/vue.js.map +1 -1
  371. package/dist/features/image-studio/components/ImageStudioDialog.js +1 -1
  372. package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
  373. package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
  374. package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
  375. package/dist/features/image-studio/feature.d.ts +1 -1
  376. package/dist/features/image-studio/feature.js +1 -1
  377. package/dist/features/image-studio/feature.js.map +1 -1
  378. package/dist/features/image-studio/node-core.d.ts +3 -3
  379. package/dist/features/image-studio/node-core.js +1 -1
  380. package/dist/features/image-studio/node-core.js.map +1 -1
  381. package/dist/features/image-studio/node-store.d.ts +1 -1
  382. package/dist/features/image-studio/node-store.js +1 -1
  383. package/dist/features/image-studio/node-store.js.map +1 -1
  384. package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
  385. package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
  386. package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
  387. package/dist/features/image-studio/react/ImageStudioView.js +1 -1
  388. package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
  389. package/dist/features/image-studio/react/store.d.ts +3 -3
  390. package/dist/features/image-studio/react/store.js.map +1 -1
  391. package/dist/features/image-studio/react.d.ts +1 -1
  392. package/dist/features/image-studio/react.js +1 -1
  393. package/dist/features/image-studio/react.js.map +1 -1
  394. package/dist/features/image-studio/schema.d.ts +1 -1
  395. package/dist/features/image-studio/schema.js +1 -1
  396. package/dist/features/image-studio/schema.js.map +1 -1
  397. package/dist/features/image-studio/state.d.ts +3 -3
  398. package/dist/features/image-studio/state.js +2 -2
  399. package/dist/features/image-studio/state.js.map +1 -1
  400. package/dist/features/image-studio/store.d.ts +3 -3
  401. package/dist/features/image-studio/vue.d.ts +1 -1
  402. package/dist/features/image-studio/vue.js +1 -1
  403. package/dist/features/image-studio/vue.js.map +1 -1
  404. package/dist/features/media/index.js +1 -1
  405. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  406. package/dist/features/media/react.js +1 -1
  407. package/dist/features/mentions/tag.js +2 -1
  408. package/dist/features/mentions/tag.js.map +1 -1
  409. package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
  410. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  411. package/dist/features/themes/feature.d.ts +1 -1
  412. package/dist/features/themes/feature.js.map +1 -1
  413. package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
  414. package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
  415. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  416. package/dist/features/themes/theme-runtime.js +1 -1
  417. package/dist/features/themes/theme-runtime.js.map +1 -1
  418. package/dist/features/transcript/TranscriptSegmentView.js +1 -1
  419. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  420. package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
  421. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  422. package/dist/features/transcript/segment-node.js.map +1 -1
  423. package/dist/features/transfer/feature.js +1 -1
  424. package/dist/features/transfer/feature.js.map +1 -1
  425. package/dist/features/transfer/transforms.d.ts +4 -4
  426. package/dist/features/transfer/transforms.js +12 -12
  427. package/dist/features/transfer/transforms.js.map +1 -1
  428. package/dist/i18n/de/ai.js +4 -4
  429. package/dist/i18n/de/ai.js.map +1 -1
  430. package/dist/i18n/de/authors.js +1 -1
  431. package/dist/i18n/de/authors.js.map +1 -1
  432. package/dist/i18n/de/comments.js +1 -1
  433. package/dist/i18n/de/comments.js.map +1 -1
  434. package/dist/i18n/de/composites.js +62 -59
  435. package/dist/i18n/de/composites.js.map +1 -1
  436. package/dist/i18n/de/image-studio.js +2 -2
  437. package/dist/i18n/de/image-studio.js.map +1 -1
  438. package/dist/i18n/de/integrations.js +20 -20
  439. package/dist/i18n/de/integrations.js.map +1 -1
  440. package/dist/i18n/de/markdown.js +1 -1
  441. package/dist/i18n/de/markdown.js.map +1 -1
  442. package/dist/i18n/de/palette.js +1 -1
  443. package/dist/i18n/de/palette.js.map +1 -1
  444. package/dist/i18n/de/themes.js +3 -3
  445. package/dist/i18n/de/themes.js.map +1 -1
  446. package/dist/i18n/de/transfer.js +2 -2
  447. package/dist/i18n/de/transfer.js.map +1 -1
  448. package/dist/i18n/de/tree.js +6 -6
  449. package/dist/i18n/de/tree.js.map +1 -1
  450. package/dist/i18n/de.d.ts +101 -98
  451. package/dist/i18n/en/ai.js +2 -2
  452. package/dist/i18n/en/ai.js.map +1 -1
  453. package/dist/i18n/en/composites.js +64 -61
  454. package/dist/i18n/en/composites.js.map +1 -1
  455. package/dist/i18n/en/integrations.js +9 -9
  456. package/dist/i18n/en/integrations.js.map +1 -1
  457. package/dist/i18n/en/markdown.js +1 -1
  458. package/dist/i18n/en/markdown.js.map +1 -1
  459. package/dist/i18n/en/palette.js +1 -1
  460. package/dist/i18n/en/palette.js.map +1 -1
  461. package/dist/i18n/en/themes.js +4 -4
  462. package/dist/i18n/en/themes.js.map +1 -1
  463. package/dist/i18n/en/tree.js +5 -5
  464. package/dist/i18n/en/tree.js.map +1 -1
  465. package/dist/index.d.ts +4 -1
  466. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
  467. package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
  468. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
  469. package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
  470. package/dist/integrations/composite-ai/composite-fill.js +5 -5
  471. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  472. package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
  473. package/dist/integrations/composite-ai/composite-summary.js +5 -5
  474. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  475. package/dist/integrations/composite-ai/derive.d.ts +17 -17
  476. package/dist/integrations/composite-ai/derive.js +27 -26
  477. package/dist/integrations/composite-ai/derive.js.map +1 -1
  478. package/dist/integrations/composite-ai/index.d.ts +14 -15
  479. package/dist/integrations/composite-ai/index.js +98 -77
  480. package/dist/integrations/composite-ai/index.js.map +1 -1
  481. package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
  482. package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
  483. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
  484. package/dist/integrations/composite-ai/rendition.d.ts +9 -9
  485. package/dist/integrations/composite-ai/rendition.js +27 -27
  486. package/dist/integrations/composite-ai/rendition.js.map +1 -1
  487. package/dist/integrations/composite-ai/split.d.ts +8 -8
  488. package/dist/integrations/composite-ai/split.js +12 -12
  489. package/dist/integrations/composite-ai/split.js.map +1 -1
  490. package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
  491. package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
  492. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
  493. package/dist/integrations/composite-media/index.d.ts +4 -3
  494. package/dist/integrations/composite-media/index.js +20 -14
  495. package/dist/integrations/composite-media/index.js.map +1 -1
  496. package/dist/markdown/document.js +1 -1
  497. package/dist/markdown/document.js.map +1 -1
  498. package/dist/nuxt/module.d.ts +30 -24
  499. package/dist/nuxt/module.js.map +1 -1
  500. package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
  501. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  502. package/dist/presets/compose.d.ts +6 -6
  503. package/dist/presets/compose.js +8 -5
  504. package/dist/presets/compose.js.map +1 -1
  505. package/dist/react/AdvancedEditor.d.ts +2 -2
  506. package/dist/react/AdvancedEditor.js +1 -1
  507. package/dist/react/AdvancedEditor.js.map +1 -1
  508. package/dist/react/compose.d.ts +1 -1
  509. package/dist/react/compose.js +2 -2
  510. package/dist/react/compose.js.map +1 -1
  511. package/dist/react/composed-surface.d.ts +5 -5
  512. package/dist/react/composed-surface.js +2 -2
  513. package/dist/react/composed-surface.js.map +1 -1
  514. package/dist/server/ai.d.ts +7 -7
  515. package/dist/server/ai.js +1 -1
  516. package/dist/server/ai.js.map +1 -1
  517. package/dist/server/auth.d.ts +1 -1
  518. package/dist/server/collab-state.d.ts +1 -1
  519. package/dist/server/collab-state.js.map +1 -1
  520. package/dist/server/collab.d.ts +4 -4
  521. package/dist/server/collab.js +22 -17
  522. package/dist/server/collab.js.map +1 -1
  523. package/dist/server/handlers/ai.d.ts +7 -4
  524. package/dist/server/handlers/ai.js +13 -17
  525. package/dist/server/handlers/ai.js.map +1 -1
  526. package/dist/server/handlers/context.d.ts +4 -0
  527. package/dist/server/handlers/context.js.map +1 -1
  528. package/dist/server/handlers/editor.d.ts +33 -32
  529. package/dist/server/handlers/editor.js +13 -8
  530. package/dist/server/handlers/editor.js.map +1 -1
  531. package/dist/server/handlers/images.d.ts +1 -1
  532. package/dist/server/handlers/images.js +1 -1
  533. package/dist/server/handlers/images.js.map +1 -1
  534. package/dist/server/host.d.ts +4 -0
  535. package/dist/server/host.js +10 -2
  536. package/dist/server/host.js.map +1 -1
  537. package/dist/server/index.d.ts +3 -3
  538. package/dist/server/ports.d.ts +8 -8
  539. package/dist/server/ports.js.map +1 -1
  540. package/dist/settings/index.d.ts +20 -19
  541. package/dist/settings/index.js +25 -24
  542. package/dist/settings/index.js.map +1 -1
  543. package/dist/settings/migrate.d.ts +18 -0
  544. package/dist/settings/migrate.js +46 -0
  545. package/dist/settings/migrate.js.map +1 -0
  546. package/dist/settings/values.d.ts +12 -12
  547. package/dist/settings/values.js +11 -11
  548. package/dist/settings/values.js.map +1 -1
  549. package/dist/styles/composites.css +10 -10
  550. package/dist/tree/DocumentTree.js +12 -5
  551. package/dist/tree/DocumentTree.js.map +1 -1
  552. package/dist/tree/drop-rules.js +5 -5
  553. package/dist/tree/drop-rules.js.map +1 -1
  554. package/dist/tree/react/DocumentTree.js +14 -5
  555. package/dist/tree/react/DocumentTree.js.map +1 -1
  556. package/dist/tree/tree-host.js +6 -6
  557. package/dist/tree/tree-host.js.map +1 -1
  558. package/dist/tree/tree-items.js +34 -28
  559. package/dist/tree/tree-items.js.map +1 -1
  560. package/dist/tree/tree-model.js +16 -16
  561. package/dist/tree/tree-model.js.map +1 -1
  562. package/dist/tree/tree-rows.js +2 -2
  563. package/dist/tree/tree-rows.js.map +1 -1
  564. package/dist/tree/tree-view-model.d.ts +2 -2
  565. package/dist/tree/tree-view-model.js.map +1 -1
  566. package/dist/vue/AdvancedEditor.js +2 -2
  567. package/dist/vue/AdvancedEditor.js.map +1 -1
  568. package/dist/vue/AdvancedEditor.vue.d.ts +6 -6
  569. package/dist/vue/compose.d.ts +1 -1
  570. package/dist/vue/compose.js +2 -2
  571. package/dist/vue/compose.js.map +1 -1
  572. package/package.json +1 -1
  573. package/dist/features/composites/derivation.d.ts +0 -62
  574. package/dist/features/composites/derivation.js +0 -102
  575. package/dist/features/composites/derivation.js.map +0 -1
  576. package/dist/features/composites/kinds.d.ts +0 -89
  577. package/dist/features/composites/kinds.js +0 -285
  578. package/dist/features/composites/kinds.js.map +0 -1
@@ -1,13 +1,14 @@
1
- import { parseBlocks, structureBlocks } from "../../core/pipeline.js";
2
1
  import { blockIdOf, findBlockById, newBlockId } from "../../core/schema/block-ids.js";
2
+ import { capabilitiesOf } from "../../core/capabilities.js";
3
+ import { parseBlocks, structureBlocks } from "../../core/pipeline.js";
4
+ import { DERIVATION_KEY, derivationOf, derivationState } from "../../core/derivation.js";
3
5
  import { captureRange, releaseRanges, resolveRange } from "../../core/doc-anchors.js";
4
6
  import { fetchErrorMessage } from "../../core/fetch-error.js";
5
7
  import { sha256Hex } from "../../core/hash.js";
6
- import { compositeKind, kindAccepts } from "../../features/composites/kinds.js";
7
- import { DERIVATION_KEY } from "../../features/composites/meta-keys.js";
8
- import { bodyMarkdown, derivationOf, derivationState, sourceOf } from "../../features/composites/derivation.js";
9
- import { compositeJSON, compositeKindsOf } from "../../features/composites/nodes.js";
8
+ import { acceptsChild, blockTypeOf } from "../../features/composites/block-types.js";
9
+ import { blockTypesOf, compositeJSON } from "../../features/composites/nodes.js";
10
10
  import { bibOf } from "../../features/composites/bibliography.js";
11
+ import { bodyMarkdown, sourceOf } from "../../features/composites/source.js";
11
12
  import { isRateLimited, notifyAiRateLimited } from "../../features/ai/rate-limit.js";
12
13
  import { Fragment } from "@tiptap/pm/model";
13
14
  //#region src/integrations/composite-ai/rendition.ts
@@ -38,7 +39,7 @@ function withPageLabels(markdown, t) {
38
39
  /**
39
40
  * The body blocks of a rendition: one `transcriptSegment` per timed segment (speaker empty, `start`/`end` in seconds)
40
41
  * when the editor has the transcript feature, else the Markdown parsed and brought into the preferred structure
41
- * (chapters become nested `section` Bausteine in composite structure; PDF page breaks become page label paragraphs).
42
+ * (chapters become nested `section` Typed blocks in composite structure; PDF page breaks become page label paragraphs).
42
43
  */
43
44
  function renditionBody(editor, response, t) {
44
45
  if (editor.schema.nodes.transcriptSegment && response.segments?.length) {
@@ -73,20 +74,20 @@ function sealed(editor, node, derivation) {
73
74
  }, node.content, node.marks);
74
75
  }
75
76
  /**
76
- * „Lesefassung erzeugen“: extracts the readable content of the source of the Baustein at `pos` (`ai.extract`, method
77
+ * the „Create readable rendition“ action: extracts the readable content of the source of the Typed block at `pos` (`ai.extract`, method
77
78
  * `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds
78
- * it as a `rendition` Baustein right after the source block, carrying `meta.derivation` (asset, method, model, hashes,
79
- * the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Baustein, and the work's
80
- * title an empty Baustein title. With `options.replace` the existing rendition is replaced in place (same block id).
81
- * The Baustein is anchored through its description when the request starts and found again after it ends, so edits
79
+ * it as a `rendition` Typed block right after the source block, carrying `meta.derivation` (asset, method, model, hashes,
80
+ * the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Typed block, and the work's
81
+ * title an empty Typed block title. With `options.replace` the existing rendition is replaced in place (same block id).
82
+ * The Typed block is anchored through its description when the request starts and found again after it ends, so edits
82
83
  * while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice
83
84
  * stays until the request ends.
84
85
  */
85
86
  async function createRendition(editor, pos, ai, modelRef, notify, t, options = {}) {
86
- const kinds = compositeKindsOf(editor);
87
+ const kinds = blockTypesOf(editor);
87
88
  const composite = editor.state.doc.nodeAt(pos);
88
89
  const source = composite && sourceOf(composite, kinds);
89
- if (composite?.type.name !== "composite" || !source) return;
90
+ if (composite?.type.name !== "typedBlock" || !source) return;
90
91
  const asset = source.asset;
91
92
  if (!asset) {
92
93
  notify({
@@ -95,7 +96,7 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
95
96
  });
96
97
  return;
97
98
  }
98
- if (!kindAccepts(kinds, String(composite.attrs.kind), "rendition")) {
99
+ if (!acceptsChild(kinds, String(composite.attrs.blockType), "rendition")) {
99
100
  notify({
100
101
  title: t("integrations.rendition.notAccepted"),
101
102
  kind: "error"
@@ -106,7 +107,7 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
106
107
  if (options.replace) {
107
108
  const target = editor.state.doc.nodeAt(options.replace.pos);
108
109
  replaceId = target && options.replace.pos > pos && options.replace.pos < pos + composite.nodeSize ? blockIdOf(target) : null;
109
- if (target?.type.name !== "composite" || !replaceId) return;
110
+ if (target?.type.name !== "typedBlock" || !replaceId) return;
110
111
  }
111
112
  const descriptionPos = pos + 1 + composite.child(0).nodeSize;
112
113
  const anchor = captureRange(editor, {
@@ -114,7 +115,7 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
114
115
  to: descriptionPos + 1 + composite.child(1).content.size
115
116
  });
116
117
  const toastId = `rendition-${blockIdOf(composite) ?? asset.name}`;
117
- const wantsBibliography = compositeKind(kinds, String(composite.attrs.kind)).fields.some((field) => field.type === "bibliography");
118
+ const wantsBibliography = capabilitiesOf(editor, composite).has("bibliography");
118
119
  const model = modelRef("generate");
119
120
  const controller = new AbortController();
120
121
  const abort = () => controller.abort();
@@ -146,7 +147,7 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
146
147
  }
147
148
  const range = resolveRange(editor.state, anchor);
148
149
  const $from = range && editor.state.doc.resolve(range.from);
149
- const parentPos = $from && $from.parent.type.name === "compositeDescription" ? $from.before($from.depth - 1) : null;
150
+ const parentPos = $from && $from.parent.type.name === "typedBlockDescription" ? $from.before($from.depth - 1) : null;
150
151
  const parent = parentPos === null ? null : editor.state.doc.nodeAt(parentPos);
151
152
  const currentSource = parent && sourceOf(parent, kinds);
152
153
  const replaced = replaceId ? findBlockById(editor.state.doc, replaceId) : null;
@@ -179,7 +180,7 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
179
180
  const titleKey = TITLED_METHODS.includes(response.method) ? `integrations.rendition.title.${response.method}` : null;
180
181
  const json = compositeJSON("rendition", body);
181
182
  const [title, ...rest] = json.content;
182
- const text = titleKey ? t(titleKey) : compositeKind(kinds, "rendition").label;
183
+ const text = titleKey ? t(titleKey) : blockTypeOf(kinds, "rendition").label;
183
184
  node = sealed(editor, schema.nodeFromJSON({
184
185
  ...json,
185
186
  attrs: {
@@ -250,34 +251,34 @@ async function createRendition(editor, pos, ai, modelRef, notify, t, options = {
250
251
  }
251
252
  }
252
253
  /**
253
- * Whether „Lesefassung erzeugen“ applies to `node`: a Baustein of a source-holding kind whose source block was
254
+ * Whether the „Create readable rendition“ action applies to `node`: a Typed block of a source-holding Block type whose source block was
254
255
  * found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else
255
256
  * is extracted by the server.
256
257
  */
257
258
  function canCreateRendition(editor, node, transcription) {
258
- const source = sourceOf(node, compositeKindsOf(editor));
259
+ const source = sourceOf(node, blockTypesOf(editor));
259
260
  if (!source) return false;
260
261
  return transcription || source.node.type.name !== "audio" && source.node.type.name !== "video";
261
262
  }
262
- /** The source-holding Baustein around the asset-derived rendition at `pos`; null for anything else. */
263
+ /** The source-holding Typed block around the asset-derived rendition at `pos`; null for anything else. */
263
264
  function renditionParentOf(editor, pos) {
264
265
  const node = editor.state.doc.nodeAt(pos);
265
266
  const derivation = node && derivationOf(node);
266
267
  if (!derivation || !("asset" in derivation.from)) return null;
267
268
  const $pos = editor.state.doc.resolve(pos);
268
- if ($pos.depth === 0 || $pos.parent.type.name !== "composite" || !sourceOf($pos.parent, compositeKindsOf(editor))) return null;
269
+ if ($pos.depth === 0 || $pos.parent.type.name !== "typedBlock" || !sourceOf($pos.parent, blockTypesOf(editor))) return null;
269
270
  return {
270
271
  node: $pos.parent,
271
272
  pos: $pos.before()
272
273
  };
273
274
  }
274
- /** Whether „Neu erzeugen (ersetzen)“ applies to the Baustein `node` at `pos`: an asset-derived rendition inside a Baustein that still has a source. */
275
+ /** Whether „Neu erzeugen (ersetzen)“ applies to the Typed block `node` at `pos`: an asset-derived rendition inside a Typed block that still has a source. */
275
276
  function canRegenerateRendition(editor, node, pos, transcription) {
276
- const parent = node.type.name === "composite" ? renditionParentOf(editor, pos) : null;
277
+ const parent = renditionParentOf(editor, pos);
277
278
  return parent !== null && canCreateRendition(editor, parent.node, transcription);
278
279
  }
279
280
  /**
280
- * „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Baustein and replaces it in place
281
+ * „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Typed block and replaces it in place
281
282
  * (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was
282
283
  * edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice
283
284
  * cancels. The rendition is found again by its id when the button is pressed.
@@ -292,8 +293,7 @@ function regenerateRendition(editor, pos, ai, modelRef, notify, t) {
292
293
  const current = found && renditionParentOf(editor, found.pos);
293
294
  if (found && current) createRendition(editor, current.pos, ai, modelRef, notify, t, { replace: { pos: found.pos } });
294
295
  };
295
- const kinds = compositeKindsOf(editor);
296
- if (derivationState(parent.node, node, () => sha256Hex(bodyMarkdown(editor, node)), kinds).edited !== true) {
296
+ if (derivationState(editor.state.doc, pos, () => sha256Hex(bodyMarkdown(editor, node)))?.edited !== true) {
297
297
  replace();
298
298
  return;
299
299
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rendition.js","names":[],"sources":["../../../src/integrations/composite-ai/rendition.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport type { ExtractResponse } from '../../core/backend-types'\nimport { captureRange, fetchErrorMessage, parseBlocks, releaseRanges, resolveRange, sha256Hex, structureBlocks } from '../../core'\nimport type { MessageKey, Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf, findBlockById, newBlockId } from '../../core/schema'\nimport { isRateLimited, type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport {\n bibOf,\n bodyMarkdown,\n COMPOSITE_CHROME_COUNT,\n compositeJSON,\n compositeKind,\n compositeKindsOf,\n DERIVATION_KEY,\n derivationOf,\n derivationState,\n type Derivation,\n kindAccepts,\n sourceOf,\n} from '../../features/composites/schema'\n\nexport interface RenditionOptions {\n /**\n * Replace the rendition at this position (a child of the source-holding Baustein) in place instead of adding a new one\n * after the source: its chrome (title, description, tags) and block id stay, body and derivation are new.\n */\n replace?: { pos: number }\n}\n\n/** Methods with their own title of a fresh rendition (`integrations.rendition.title.<method>`). */\nconst TITLED_METHODS: readonly string[] = ['transcription', 'pdf-text', 'ocr', 'description']\n\n/** What the server's `warnings` codes say; an unknown code is shown as it is. */\nconst WARNING_KEYS: Readonly<Record<string, MessageKey>> = {\n 'ocr-unavailable': 'integrations.rendition.warning.ocr-unavailable',\n 'crossref-unavailable': 'integrations.rendition.warning.crossref-unavailable',\n 'pages-truncated': 'integrations.rendition.warning.pages-truncated',\n 'ocr-truncated': 'integrations.rendition.warning.ocr-truncated',\n 'bibliography-failed': 'integrations.rendition.warning.bibliography-failed',\n}\n\n/** The `<!-- page N -->` line the server puts at the start of every PDF page after the first (`joinPages`). */\nconst PAGE_MARKER = /^<!-- page (\\d+) -->[ \\t]*$/gm\n\n/**\n * `markdown` with every page marker line replaced by an emphasised page label paragraph (`*S. 2*`): parsed as it is, a\n * marker is an HTML comment and would leave an empty paragraph without the page. The stored raw output keeps the markers.\n */\nfunction withPageLabels(markdown: string, t: Translate): string {\n return markdown.replace(PAGE_MARKER, (_marker, page: string) => `*${t('integrations.rendition.page', { n: page })}*`)\n}\n\n/**\n * The body blocks of a rendition: one `transcriptSegment` per timed segment (speaker empty, `start`/`end` in seconds)\n * when the editor has the transcript feature, else the Markdown parsed and brought into the preferred structure\n * (chapters become nested `section` Bausteine in composite structure; PDF page breaks become page label paragraphs).\n */\nfunction renditionBody(editor: Editor, response: ExtractResponse, t: Translate): JSONContent[] {\n if (editor.schema.nodes.transcriptSegment && response.segments?.length) {\n const segments = response.segments\n .filter(segment => segment.text.trim())\n .map((segment): JSONContent => ({\n type: 'transcriptSegment',\n attrs: { speaker: '', start: segment.start, end: segment.end },\n content: [{ type: 'text', text: segment.text.trim() }],\n }))\n if (segments.length) return segments\n }\n return response.markdown.trim() ? structureBlocks(editor, parseBlocks(editor, withPageLabels(response.markdown, t)).blocks) : []\n}\n\n/** `node` with `derivation` in its meta, `outputHash` being the hash of the Markdown of its body (what `derivationState` compares later). */\nfunction sealed(editor: Editor, node: PMNode, derivation: Derivation): PMNode {\n const outputHash = sha256Hex(bodyMarkdown(editor, node))\n return node.type.create({ ...node.attrs, meta: { ...node.attrs.meta, [DERIVATION_KEY]: { ...derivation, outputHash } } }, node.content, node.marks)\n}\n\n/**\n * „Lesefassung erzeugen“: extracts the readable content of the source of the Baustein at `pos` (`ai.extract`, method\n * `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds\n * it as a `rendition` Baustein right after the source block, carrying `meta.derivation` (asset, method, model, hashes,\n * the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Baustein, and the work's\n * title an empty Baustein title. With `options.replace` the existing rendition is replaced in place (same block id).\n * The Baustein is anchored through its description when the request starts and found again after it ends, so edits\n * while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice\n * stays until the request ends.\n */\nexport async function createRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: RenditionOptions = {}): Promise<void> {\n const kinds = compositeKindsOf(editor)\n const composite = editor.state.doc.nodeAt(pos)\n const source = composite && sourceOf(composite, kinds)\n if (composite?.type.name !== 'composite' || !source) return\n const asset = source.asset\n if (!asset) {\n notify({ title: t('integrations.rendition.noSource'), kind: 'error' })\n return\n }\n if (!kindAccepts(kinds, String(composite.attrs.kind), 'rendition')) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n\n let replaceId: string | null = null\n if (options.replace) {\n const target = editor.state.doc.nodeAt(options.replace.pos)\n replaceId = target && options.replace.pos > pos && options.replace.pos < pos + composite.nodeSize ? blockIdOf(target) : null\n if (target?.type.name !== 'composite' || !replaceId) return\n }\n\n const descriptionPos = pos + 1 + composite.child(0).nodeSize\n const anchor = captureRange(editor, { from: descriptionPos + 1, to: descriptionPos + 1 + composite.child(1).content.size })\n const toastId = `rendition-${blockIdOf(composite) ?? asset.name}`\n const wantsBibliography = compositeKind(kinds, String(composite.attrs.kind)).fields.some(field => field.type === 'bibliography')\n const model = modelRef('generate')\n\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.rendition.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n try {\n const response = await ai.extract({ documentId: asset.documentId, name: asset.name, method: 'auto', model, bibliography: wantsBibliography }, controller.signal)\n if (editor.isDestroyed) return\n const body = renditionBody(editor, response, t)\n if (!body.length) {\n notify({ title: t('integrations.rendition.empty.title'), description: t('integrations.rendition.empty.description'), kind: 'error' })\n return\n }\n\n // The Baustein, found again through its anchored description; its source may have changed meanwhile.\n const range = resolveRange(editor.state, anchor)\n const $from = range && editor.state.doc.resolve(range.from)\n const parentPos = $from && $from.parent.type.name === 'compositeDescription' ? $from.before($from.depth - 1) : null\n const parent = parentPos === null ? null : editor.state.doc.nodeAt(parentPos)\n const currentSource = parent && sourceOf(parent, kinds)\n const replaced = replaceId ? findBlockById(editor.state.doc, replaceId) : null\n if (parentPos === null || !parent || !currentSource || (replaceId !== null && (!replaced || replaced.pos <= parentPos || replaced.pos >= parentPos + parent.nodeSize))) {\n notify({ title: t('integrations.rendition.gone.title'), description: t('integrations.rendition.gone.description'), kind: 'error' })\n return\n }\n\n // The model that wrote the content: the speech-to-text model for a transcription, the chat model for OCR and an\n // image description, none for the PDF text layer.\n const usedModel = response.method === 'transcription' ? response.model : response.method === 'ocr' || response.method === 'description' ? ('preset' in model ? model.preset : model.model) : undefined\n const derivation: Derivation = {\n from: { asset: asset.name },\n method: response.method,\n ...(usedModel ? { model: usedModel } : {}),\n createdAt: new Date().toISOString(),\n inputHash: response.inputHash,\n outputHash: '',\n ...(response.output ? { output: response.output } : {}),\n }\n const { schema } = editor\n const bodyNodes = body.map(block => schema.nodeFromJSON(block))\n const id = replaceId ?? newBlockId()\n let node: PMNode\n if (replaced) {\n const chrome = Array.from({ length: COMPOSITE_CHROME_COUNT }, (_, index) => replaced.node.child(index))\n node = sealed(editor, replaced.node.type.create(replaced.node.attrs, Fragment.from([...chrome, ...bodyNodes])), derivation)\n }\n else {\n const titleKey = TITLED_METHODS.includes(response.method) ? `integrations.rendition.title.${response.method}` as MessageKey : null\n const json = compositeJSON('rendition', body)\n const [title, ...rest] = json.content!\n const text = titleKey ? t(titleKey) : compositeKind(kinds, 'rendition').label\n const fresh = schema.nodeFromJSON({ ...json, attrs: { ...json.attrs, id }, content: [{ ...title!, content: [{ type: 'text', text }] }, ...rest] })\n node = sealed(editor, fresh, derivation)\n }\n\n const tr = editor.state.tr\n if (replaced) tr.replaceWith(replaced.pos, replaced.pos + replaced.node.nodeSize, node)\n else {\n let insertPos = parentPos + 1\n for (let index = 0; index <= currentSource.index; index++) insertPos += parent.child(index).nodeSize\n if (!parent.canReplace(currentSource.index + 1, currentSource.index + 1, Fragment.from(node))) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n tr.insert(insertPos, node)\n }\n // Bibliographic data fills only what is empty; the title is never part of `meta.bib`.\n const { bib } = response\n const workTitle = bib?.title?.trim()\n if (workTitle && !parent.child(0).textContent.trim()) tr.insert(parentPos + 2, schema.text(workTitle))\n if (bib && bibOf(parent) === null) {\n const csl = { ...bib }\n delete csl.title\n tr.setNodeMarkup(parentPos, undefined, { ...parent.attrs, meta: { ...parent.attrs.meta, bib: csl } })\n }\n editor.view.dispatch(tr)\n editor.commands.revealBlock(id)\n notify({ title: t('integrations.rendition.done'), kind: 'success', icon: 'i-lucide-captions' })\n if (response.warnings.length) {\n notify({\n title: t('integrations.rendition.warnings.title'),\n description: response.warnings.map(code => (WARNING_KEYS[code] ? t(WARNING_KEYS[code]) : code)).join(' '),\n kind: 'info',\n })\n }\n }\n catch (err) {\n if (controller.signal.aborted || editor.isDestroyed) return\n if (isRateLimited(err)) notifyAiRateLimited(notify, t)\n else notify({ title: t('integrations.rendition.failed'), description: fetchErrorMessage(err), kind: 'error' })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n\n/**\n * Whether „Lesefassung erzeugen“ applies to `node`: a Baustein of a source-holding kind whose source block was\n * found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else\n * is extracted by the server.\n */\nexport function canCreateRendition(editor: Editor, node: PMNode, transcription: boolean): boolean {\n const source = sourceOf(node, compositeKindsOf(editor))\n if (!source) return false\n return transcription || (source.node.type.name !== 'audio' && source.node.type.name !== 'video')\n}\n\n/** The source-holding Baustein around the asset-derived rendition at `pos`; null for anything else. */\nfunction renditionParentOf(editor: Editor, pos: number): { node: PMNode, pos: number } | null {\n const node = editor.state.doc.nodeAt(pos)\n const derivation = node && derivationOf(node)\n if (!derivation || !('asset' in derivation.from)) return null\n const $pos = editor.state.doc.resolve(pos)\n if ($pos.depth === 0 || $pos.parent.type.name !== 'composite' || !sourceOf($pos.parent, compositeKindsOf(editor))) return null\n return { node: $pos.parent, pos: $pos.before() }\n}\n\n/** Whether „Neu erzeugen (ersetzen)“ applies to the Baustein `node` at `pos`: an asset-derived rendition inside a Baustein that still has a source. */\nexport function canRegenerateRendition(editor: Editor, node: PMNode, pos: number, transcription: boolean): boolean {\n const parent = node.type.name === 'composite' ? renditionParentOf(editor, pos) : null\n return parent !== null && canCreateRendition(editor, parent.node, transcription)\n}\n\n/**\n * „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Baustein and replaces it in place\n * (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was\n * edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice\n * cancels. The rendition is found again by its id when the button is pressed.\n */\nexport function regenerateRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): void {\n const node = editor.state.doc.nodeAt(pos)\n const id = node && blockIdOf(node)\n const parent = renditionParentOf(editor, pos)\n if (!node || !id || !parent) return\n\n const replace = () => {\n const found = findBlockById(editor.state.doc, id)\n const current = found && renditionParentOf(editor, found.pos)\n if (found && current) void createRendition(editor, current.pos, ai, modelRef, notify, t, { replace: { pos: found.pos } })\n }\n const kinds = compositeKindsOf(editor)\n if (derivationState(parent.node, node, () => sha256Hex(bodyMarkdown(editor, node)), kinds).edited !== true) {\n replace()\n return\n }\n notify({\n id: `rendition-edited-${id}`,\n title: t('integrations.rendition.editedWarning.title'),\n description: t('integrations.rendition.editedWarning.description'),\n kind: 'warning',\n action: { label: t('integrations.rendition.editedWarning.confirm'), onClick: replace },\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rendition.js","names":[],"sources":["../../../src/integrations/composite-ai/rendition.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport type { ExtractResponse } from '../../core/backend-types'\nimport { capabilitiesOf, captureRange, DERIVATION_KEY, type Derivation, derivationOf, derivationState, fetchErrorMessage, parseBlocks, releaseRanges, resolveRange, sha256Hex, structureBlocks } from '../../core'\nimport type { MessageKey, Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf, findBlockById, newBlockId } from '../../core/schema'\nimport { isRateLimited, type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport {\n acceptsChild,\n bibOf,\n blockTypeOf,\n blockTypesOf,\n bodyMarkdown,\n COMPOSITE_CHROME_COUNT,\n compositeJSON,\n sourceOf,\n} from '../../features/composites/schema'\n\nexport interface RenditionOptions {\n /**\n * Replace the rendition at this position (a child of the source-holding Typed block) in place instead of adding a new one\n * after the source: its chrome (title, description, tags) and block id stay, body and derivation are new.\n */\n replace?: { pos: number }\n}\n\n/** Methods with their own title of a fresh rendition (`integrations.rendition.title.<method>`). */\nconst TITLED_METHODS: readonly string[] = ['transcription', 'pdf-text', 'ocr', 'description']\n\n/** What the server's `warnings` codes say; an unknown code is shown as it is. */\nconst WARNING_KEYS: Readonly<Record<string, MessageKey>> = {\n 'ocr-unavailable': 'integrations.rendition.warning.ocr-unavailable',\n 'crossref-unavailable': 'integrations.rendition.warning.crossref-unavailable',\n 'pages-truncated': 'integrations.rendition.warning.pages-truncated',\n 'ocr-truncated': 'integrations.rendition.warning.ocr-truncated',\n 'bibliography-failed': 'integrations.rendition.warning.bibliography-failed',\n}\n\n/** The `<!-- page N -->` line the server puts at the start of every PDF page after the first (`joinPages`). */\nconst PAGE_MARKER = /^<!-- page (\\d+) -->[ \\t]*$/gm\n\n/**\n * `markdown` with every page marker line replaced by an emphasised page label paragraph (`*S. 2*`): parsed as it is, a\n * marker is an HTML comment and would leave an empty paragraph without the page. The stored raw output keeps the markers.\n */\nfunction withPageLabels(markdown: string, t: Translate): string {\n return markdown.replace(PAGE_MARKER, (_marker, page: string) => `*${t('integrations.rendition.page', { n: page })}*`)\n}\n\n/**\n * The body blocks of a rendition: one `transcriptSegment` per timed segment (speaker empty, `start`/`end` in seconds)\n * when the editor has the transcript feature, else the Markdown parsed and brought into the preferred structure\n * (chapters become nested `section` Typed blocks in composite structure; PDF page breaks become page label paragraphs).\n */\nfunction renditionBody(editor: Editor, response: ExtractResponse, t: Translate): JSONContent[] {\n if (editor.schema.nodes.transcriptSegment && response.segments?.length) {\n const segments = response.segments\n .filter(segment => segment.text.trim())\n .map((segment): JSONContent => ({\n type: 'transcriptSegment',\n attrs: { speaker: '', start: segment.start, end: segment.end },\n content: [{ type: 'text', text: segment.text.trim() }],\n }))\n if (segments.length) return segments\n }\n return response.markdown.trim() ? structureBlocks(editor, parseBlocks(editor, withPageLabels(response.markdown, t)).blocks) : []\n}\n\n/** `node` with `derivation` in its meta, `outputHash` being the hash of the Markdown of its body (what `derivationState` compares later). */\nfunction sealed(editor: Editor, node: PMNode, derivation: Derivation): PMNode {\n const outputHash = sha256Hex(bodyMarkdown(editor, node))\n return node.type.create({ ...node.attrs, meta: { ...node.attrs.meta, [DERIVATION_KEY]: { ...derivation, outputHash } } }, node.content, node.marks)\n}\n\n/**\n * the „Create readable rendition“ action: extracts the readable content of the source of the Typed block at `pos` (`ai.extract`, method\n * `auto`: transcript with timestamps for audio/video, full text or OCR for a PDF, a description for an image) and adds\n * it as a `rendition` Typed block right after the source block, carrying `meta.derivation` (asset, method, model, hashes,\n * the stored raw output). Bibliographic data the server found fills an empty `meta.bib` of the Typed block, and the work's\n * title an empty Typed block title. With `options.replace` the existing rendition is replaced in place (same block id).\n * The Typed block is anchored through its description when the request starts and found again after it ends, so edits\n * while it runs do not misplace the result. Notices go through `notify`, in the language of `t`; the progress notice\n * stays until the request ends.\n */\nexport async function createRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: RenditionOptions = {}): Promise<void> {\n const kinds = blockTypesOf(editor)\n const composite = editor.state.doc.nodeAt(pos)\n const source = composite && sourceOf(composite, kinds)\n if (composite?.type.name !== 'typedBlock' || !source) return\n const asset = source.asset\n if (!asset) {\n notify({ title: t('integrations.rendition.noSource'), kind: 'error' })\n return\n }\n if (!acceptsChild(kinds, String(composite.attrs.blockType), 'rendition')) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n\n let replaceId: string | null = null\n if (options.replace) {\n const target = editor.state.doc.nodeAt(options.replace.pos)\n replaceId = target && options.replace.pos > pos && options.replace.pos < pos + composite.nodeSize ? blockIdOf(target) : null\n if (target?.type.name !== 'typedBlock' || !replaceId) return\n }\n\n const descriptionPos = pos + 1 + composite.child(0).nodeSize\n const anchor = captureRange(editor, { from: descriptionPos + 1, to: descriptionPos + 1 + composite.child(1).content.size })\n const toastId = `rendition-${blockIdOf(composite) ?? asset.name}`\n const wantsBibliography = capabilitiesOf(editor, composite).has('bibliography')\n const model = modelRef('generate')\n\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.rendition.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n try {\n const response = await ai.extract({ documentId: asset.documentId, name: asset.name, method: 'auto', model, bibliography: wantsBibliography }, controller.signal)\n if (editor.isDestroyed) return\n const body = renditionBody(editor, response, t)\n if (!body.length) {\n notify({ title: t('integrations.rendition.empty.title'), description: t('integrations.rendition.empty.description'), kind: 'error' })\n return\n }\n\n // The Typed block, found again through its anchored description; its source may have changed meanwhile.\n const range = resolveRange(editor.state, anchor)\n const $from = range && editor.state.doc.resolve(range.from)\n const parentPos = $from && $from.parent.type.name === 'typedBlockDescription' ? $from.before($from.depth - 1) : null\n const parent = parentPos === null ? null : editor.state.doc.nodeAt(parentPos)\n const currentSource = parent && sourceOf(parent, kinds)\n const replaced = replaceId ? findBlockById(editor.state.doc, replaceId) : null\n if (parentPos === null || !parent || !currentSource || (replaceId !== null && (!replaced || replaced.pos <= parentPos || replaced.pos >= parentPos + parent.nodeSize))) {\n notify({ title: t('integrations.rendition.gone.title'), description: t('integrations.rendition.gone.description'), kind: 'error' })\n return\n }\n\n // The model that wrote the content: the speech-to-text model for a transcription, the chat model for OCR and an\n // image description, none for the PDF text layer.\n const usedModel = response.method === 'transcription' ? response.model : response.method === 'ocr' || response.method === 'description' ? ('preset' in model ? model.preset : model.model) : undefined\n const derivation: Derivation = {\n from: { asset: asset.name },\n method: response.method,\n ...(usedModel ? { model: usedModel } : {}),\n createdAt: new Date().toISOString(),\n inputHash: response.inputHash,\n outputHash: '',\n ...(response.output ? { output: response.output } : {}),\n }\n const { schema } = editor\n const bodyNodes = body.map(block => schema.nodeFromJSON(block))\n const id = replaceId ?? newBlockId()\n let node: PMNode\n if (replaced) {\n const chrome = Array.from({ length: COMPOSITE_CHROME_COUNT }, (_, index) => replaced.node.child(index))\n node = sealed(editor, replaced.node.type.create(replaced.node.attrs, Fragment.from([...chrome, ...bodyNodes])), derivation)\n }\n else {\n const titleKey = TITLED_METHODS.includes(response.method) ? `integrations.rendition.title.${response.method}` as MessageKey : null\n const json = compositeJSON('rendition', body)\n const [title, ...rest] = json.content!\n const text = titleKey ? t(titleKey) : blockTypeOf(kinds, 'rendition').label\n const fresh = schema.nodeFromJSON({ ...json, attrs: { ...json.attrs, id }, content: [{ ...title!, content: [{ type: 'text', text }] }, ...rest] })\n node = sealed(editor, fresh, derivation)\n }\n\n const tr = editor.state.tr\n if (replaced) tr.replaceWith(replaced.pos, replaced.pos + replaced.node.nodeSize, node)\n else {\n let insertPos = parentPos + 1\n for (let index = 0; index <= currentSource.index; index++) insertPos += parent.child(index).nodeSize\n if (!parent.canReplace(currentSource.index + 1, currentSource.index + 1, Fragment.from(node))) {\n notify({ title: t('integrations.rendition.notAccepted'), kind: 'error' })\n return\n }\n tr.insert(insertPos, node)\n }\n // Bibliographic data fills only what is empty; the title is never part of `meta.bib`.\n const { bib } = response\n const workTitle = bib?.title?.trim()\n if (workTitle && !parent.child(0).textContent.trim()) tr.insert(parentPos + 2, schema.text(workTitle))\n if (bib && bibOf(parent) === null) {\n const csl = { ...bib }\n delete csl.title\n tr.setNodeMarkup(parentPos, undefined, { ...parent.attrs, meta: { ...parent.attrs.meta, bib: csl } })\n }\n editor.view.dispatch(tr)\n editor.commands.revealBlock(id)\n notify({ title: t('integrations.rendition.done'), kind: 'success', icon: 'i-lucide-captions' })\n if (response.warnings.length) {\n notify({\n title: t('integrations.rendition.warnings.title'),\n description: response.warnings.map(code => (WARNING_KEYS[code] ? t(WARNING_KEYS[code]) : code)).join(' '),\n kind: 'info',\n })\n }\n }\n catch (err) {\n if (controller.signal.aborted || editor.isDestroyed) return\n if (isRateLimited(err)) notifyAiRateLimited(notify, t)\n else notify({ title: t('integrations.rendition.failed'), description: fetchErrorMessage(err), kind: 'error' })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n\n/**\n * Whether the „Create readable rendition“ action applies to `node`: a Typed block of a source-holding Block type whose source block was\n * found. A recording needs speech-to-text (`transcription`: the app's public configuration enables it); everything else\n * is extracted by the server.\n */\nexport function canCreateRendition(editor: Editor, node: PMNode, transcription: boolean): boolean {\n const source = sourceOf(node, blockTypesOf(editor))\n if (!source) return false\n return transcription || (source.node.type.name !== 'audio' && source.node.type.name !== 'video')\n}\n\n/** The source-holding Typed block around the asset-derived rendition at `pos`; null for anything else. */\nfunction renditionParentOf(editor: Editor, pos: number): { node: PMNode, pos: number } | null {\n const node = editor.state.doc.nodeAt(pos)\n const derivation = node && derivationOf(node)\n if (!derivation || !('asset' in derivation.from)) return null\n const $pos = editor.state.doc.resolve(pos)\n if ($pos.depth === 0 || $pos.parent.type.name !== 'typedBlock' || !sourceOf($pos.parent, blockTypesOf(editor))) return null\n return { node: $pos.parent, pos: $pos.before() }\n}\n\n/** Whether „Neu erzeugen (ersetzen)“ applies to the Typed block `node` at `pos`: an asset-derived rendition inside a Typed block that still has a source. */\nexport function canRegenerateRendition(editor: Editor, node: PMNode, pos: number, transcription: boolean): boolean {\n const parent = renditionParentOf(editor, pos)\n return parent !== null && canCreateRendition(editor, parent.node, transcription)\n}\n\n/**\n * „Neu erzeugen (ersetzen)“: makes the rendition at `pos` again from the source of its Typed block and replaces it in place\n * (`createRendition` with `replace`; the block id stays, so references keep resolving). A rendition whose body was\n * edited since it was made is not replaced silently: a warning notice offers „Trotzdem ersetzen“, dismissing the notice\n * cancels. The rendition is found again by its id when the button is pressed.\n */\nexport function regenerateRendition(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): void {\n const node = editor.state.doc.nodeAt(pos)\n const id = node && blockIdOf(node)\n const parent = renditionParentOf(editor, pos)\n if (!node || !id || !parent) return\n\n const replace = () => {\n const found = findBlockById(editor.state.doc, id)\n const current = found && renditionParentOf(editor, found.pos)\n if (found && current) void createRendition(editor, current.pos, ai, modelRef, notify, t, { replace: { pos: found.pos } })\n }\n if (derivationState(editor.state.doc, pos, () => sha256Hex(bodyMarkdown(editor, node)))?.edited !== true) {\n replace()\n return\n }\n notify({\n id: `rendition-edited-${id}`,\n title: t('integrations.rendition.editedWarning.title'),\n description: t('integrations.rendition.editedWarning.description'),\n kind: 'warning',\n action: { label: t('integrations.rendition.editedWarning.confirm'), onClick: replace },\n })\n}\n"],"mappings":"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"}
@@ -18,27 +18,27 @@ export declare function bodyUnchanged(original: string, result: string): boolean
18
18
  * inserted) is split at those headings, or `null` when it yields fewer than two parts. Every part gets the model's
19
19
  * heading as a hidden title (`meta.titleHidden`), no block id.
20
20
  *
21
- * - `children`: one node, the composite with the blocks before the first heading followed by one sub-Baustein of
21
+ * - `children`: one node, the composite with the blocks before the first heading followed by one nested Typed block of
22
22
  * `kind` per heading.
23
23
  * - `siblings`: the composite keeps the blocks before the first heading (without any, the body of the first heading
24
- * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own kind.
24
+ * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own Block type.
25
25
  *
26
26
  * The headings of the result are level 2, so only the lowest level present is grouped (`groupHeadingsIntoComposites`,
27
27
  * not recursive).
28
28
  */
29
29
  export declare function splitByInsertedHeadings(schema: Schema, composite: Node$1, blocks: readonly Node$1[], mode: SplitMode, kind: string): Node$1[] | null;
30
30
  /**
31
- * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Baustein at `pos` (task `split-block`,
32
- * `targetChars` as the wanted section size, `generate` slot) and splits the body at them, in `mode`:
33
- * `children` makes sub-Bausteine, `siblings` makes following Bausteine of the same kind. The model may only insert
31
+ * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Typed block at `pos` (task `split-block`,
32
+ * `targetChars` as the wanted section size, `generate` Model role) and splits the body at them, in `mode`:
33
+ * `children` makes nested Typed blocks, `siblings` makes following Typed blocks of the same Block type. The model may only insert
34
34
  * headings: when the text minus those headings is not the original body (`bodyUnchanged`) nothing is written and a
35
- * warning is shown. The Baustein is anchored while the model runs; edits to its body meanwhile discard the result.
36
- * The write is one transaction. `defaultKind` is the setting `blocks.defaultKind` (see `childKindFor`). Notices go
35
+ * warning is shown. The Typed block is anchored while the model runs; edits to its body meanwhile discard the result.
36
+ * The write is one transaction. `defaultBlockType` is the setting `blocks.defaultBlockType` (see `childKindFor`). Notices go
37
37
  * through `notify`, in the language of `t`.
38
38
  */
39
39
  export declare function splitCompositeWithAi(editor: Editor, pos: number, mode: SplitMode, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: {
40
40
  targetChars: number;
41
- defaultKind: string;
41
+ defaultBlockType: string;
42
42
  }): Promise<void>;
43
43
  //#endregion
44
44
  //# sourceMappingURL=split.d.ts.map
@@ -2,9 +2,9 @@ import { AI_LIMITS } from "../../features/ai/protocol/tasks.js";
2
2
  import { parseBlocks } from "../../core/pipeline.js";
3
3
  import { captureRange, releaseRanges, resolveRange } from "../../core/doc-anchors.js";
4
4
  import { TITLE_HIDDEN_KEY } from "../../features/composites/meta-keys.js";
5
- import { bodyMarkdown } from "../../features/composites/derivation.js";
6
5
  import { groupHeadingsIntoComposites } from "../../features/composites/heading-composites.js";
7
- import { compositeKindsOf } from "../../features/composites/nodes.js";
6
+ import { blockTypesOf } from "../../features/composites/nodes.js";
7
+ import { bodyMarkdown } from "../../features/composites/source.js";
8
8
  import { notifyAiRateLimited } from "../../features/ai/rate-limit.js";
9
9
  import { postAiSse } from "../../features/ai/ai-sse.js";
10
10
  import { childKindFor } from "../../features/composites/split.js";
@@ -39,10 +39,10 @@ function bodyUnchanged(original, result) {
39
39
  * inserted) is split at those headings, or `null` when it yields fewer than two parts. Every part gets the model's
40
40
  * heading as a hidden title (`meta.titleHidden`), no block id.
41
41
  *
42
- * - `children`: one node, the composite with the blocks before the first heading followed by one sub-Baustein of
42
+ * - `children`: one node, the composite with the blocks before the first heading followed by one nested Typed block of
43
43
  * `kind` per heading.
44
44
  * - `siblings`: the composite keeps the blocks before the first heading (without any, the body of the first heading
45
- * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own kind.
45
+ * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own Block type.
46
46
  *
47
47
  * The headings of the result are level 2, so only the lowest level present is grouped (`groupHeadingsIntoComposites`,
48
48
  * not recursive).
@@ -78,20 +78,20 @@ function splitByInsertedHeadings(schema, composite, blocks, mode, kind) {
78
78
  return [withBody(firstBody), ...rest];
79
79
  }
80
80
  /**
81
- * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Baustein at `pos` (task `split-block`,
82
- * `targetChars` as the wanted section size, `generate` slot) and splits the body at them, in `mode`:
83
- * `children` makes sub-Bausteine, `siblings` makes following Bausteine of the same kind. The model may only insert
81
+ * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Typed block at `pos` (task `split-block`,
82
+ * `targetChars` as the wanted section size, `generate` Model role) and splits the body at them, in `mode`:
83
+ * `children` makes nested Typed blocks, `siblings` makes following Typed blocks of the same Block type. The model may only insert
84
84
  * headings: when the text minus those headings is not the original body (`bodyUnchanged`) nothing is written and a
85
- * warning is shown. The Baustein is anchored while the model runs; edits to its body meanwhile discard the result.
86
- * The write is one transaction. `defaultKind` is the setting `blocks.defaultKind` (see `childKindFor`). Notices go
85
+ * warning is shown. The Typed block is anchored while the model runs; edits to its body meanwhile discard the result.
86
+ * The write is one transaction. `defaultBlockType` is the setting `blocks.defaultBlockType` (see `childKindFor`). Notices go
87
87
  * through `notify`, in the language of `t`.
88
88
  */
89
89
  async function splitCompositeWithAi(editor, pos, mode, ai, modelRef, notify, t, options) {
90
90
  const composite = editor.state.doc.nodeAt(pos);
91
- if (composite?.type.name !== "composite") return;
91
+ if (composite?.type.name !== "typedBlock") return;
92
92
  const original = bodyMarkdown(editor, composite);
93
93
  if (!original.trim()) return;
94
- const kind = mode === "children" ? childKindFor(compositeKindsOf(editor), String(composite.attrs.kind), options.defaultKind) : String(composite.attrs.kind);
94
+ const kind = mode === "children" ? childKindFor(blockTypesOf(editor), String(composite.attrs.blockType), options.defaultBlockType) : String(composite.attrs.blockType);
95
95
  if (!kind) {
96
96
  notify({
97
97
  title: t("integrations.compositeSplit.notPossible"),
@@ -158,7 +158,7 @@ async function splitCompositeWithAi(editor, pos, mode, ai, modelRef, notify, t,
158
158
  }
159
159
  const range = resolveRange(editor.state, anchor);
160
160
  const current = range && editor.state.doc.nodeAt(range.from);
161
- if (!range || current?.type.name !== "composite" || range.from + current.nodeSize !== range.to || bodyMarkdown(editor, current) !== original) {
161
+ if (!range || current?.type.name !== "typedBlock" || range.from + current.nodeSize !== range.to || bodyMarkdown(editor, current) !== original) {
162
162
  notify({
163
163
  title: t("integrations.compositeSplit.gone"),
164
164
  kind: "error"
@@ -1 +1 @@
1
- {"version":3,"file":"split.js","names":[],"sources":["../../../src/integrations/composite-ai/split.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type Schema } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport { captureRange, parseBlocks, releaseRanges, resolveRange } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport type { Translate } from '../../i18n'\nimport { AI_LIMITS, type ModelRef, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { bodyMarkdown, COMPOSITE_CHROME_COUNT, compositeKindsOf, groupHeadingsIntoComposites, TITLE_HIDDEN_KEY } from '../../features/composites/schema'\nimport { childKindFor, type SplitMode } from '../../features/composites/split'\n\nconst HEADING_LINE = /^#{1,6}\\s/\nconst collapse = (text: string) => text.replace(/\\s+/g, ' ').trim()\n\n/**\n * Whether the model only inserted headings: `result` without its heading lines equals `original` with whitespace\n * collapsed (so line breaks and blank lines may differ, words may not). Heading lines the original already has stay\n * part of the comparison, so the model cannot drop or rewrite them.\n */\nexport function bodyUnchanged(original: string, result: string): boolean {\n const own = new Map<string, number>()\n for (const line of original.split('\\n')) {\n if (!HEADING_LINE.test(line)) continue\n const key = collapse(line)\n own.set(key, (own.get(key) ?? 0) + 1)\n }\n const kept = result.split('\\n').filter((line) => {\n if (!HEADING_LINE.test(line)) return true\n const key = collapse(line)\n const left = own.get(key) ?? 0\n if (!left) return false\n own.set(key, left - 1)\n return true\n })\n return collapse(kept.join('\\n')) === collapse(original)\n}\n\n/**\n * The nodes that replace `composite` when the model's result (`blocks`, the result Markdown as blocks, with headings\n * inserted) is split at those headings, or `null` when it yields fewer than two parts. Every part gets the model's\n * heading as a hidden title (`meta.titleHidden`), no block id.\n *\n * - `children`: one node, the composite with the blocks before the first heading followed by one sub-Baustein of\n * `kind` per heading.\n * - `siblings`: the composite keeps the blocks before the first heading (without any, the body of the first heading\n * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own kind.\n *\n * The headings of the result are level 2, so only the lowest level present is grouped (`groupHeadingsIntoComposites`,\n * not recursive).\n */\nexport function splitByInsertedHeadings(schema: Schema, composite: PMNode, blocks: readonly PMNode[], mode: SplitMode, kind: string): PMNode[] | null {\n let minLevel = Infinity\n for (const block of blocks) if (block.type.name === 'heading') minLevel = Math.min(minLevel, block.attrs.level as number)\n if (minLevel === Infinity) return null\n const preambleLength = blocks.findIndex(block => block.type.name === 'heading' && (block.attrs.level as number) === minLevel)\n const grouped = groupHeadingsIntoComposites(schema, blocks, false, kind)\n if (!grouped) return null\n const preamble = grouped.slice(0, preambleLength)\n const parts = grouped.slice(preambleLength).map(part => part.type.create({ ...part.attrs, meta: { ...(part.attrs.meta as Record<string, unknown> | null), [TITLE_HIDDEN_KEY]: true } }, part.content))\n if ((preamble.length ? 1 : 0) + parts.length < 2) return null\n\n const chrome: PMNode[] = []\n composite.forEach((child, _offset, index) => {\n if (index < COMPOSITE_CHROME_COUNT) chrome.push(child)\n })\n const withBody = (body: readonly PMNode[]) => composite.copy(Fragment.from([...chrome, ...body]))\n if (mode === 'children') return [withBody([...preamble, ...parts])]\n\n if (preamble.length) return [withBody(preamble), ...parts]\n const [first, ...rest] = parts\n const firstBody: PMNode[] = []\n first!.forEach((child, _offset, index) => {\n if (index >= COMPOSITE_CHROME_COUNT) firstBody.push(child)\n })\n return [withBody(firstBody), ...rest]\n}\n\n/**\n * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Baustein at `pos` (task `split-block`,\n * `targetChars` as the wanted section size, `generate` slot) and splits the body at them, in `mode`:\n * `children` makes sub-Bausteine, `siblings` makes following Bausteine of the same kind. The model may only insert\n * headings: when the text minus those headings is not the original body (`bodyUnchanged`) nothing is written and a\n * warning is shown. The Baustein is anchored while the model runs; edits to its body meanwhile discard the result.\n * The write is one transaction. `defaultKind` is the setting `blocks.defaultKind` (see `childKindFor`). Notices go\n * through `notify`, in the language of `t`.\n */\nexport async function splitCompositeWithAi(editor: Editor, pos: number, mode: SplitMode, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: { targetChars: number, defaultKind: string }): Promise<void> {\n const composite = editor.state.doc.nodeAt(pos)\n if (composite?.type.name !== 'composite') return\n const original = bodyMarkdown(editor, composite)\n if (!original.trim()) return\n const kind = mode === 'children' ? childKindFor(compositeKindsOf(editor), String(composite.attrs.kind), options.defaultKind) : String(composite.attrs.kind)\n if (!kind) {\n notify({ title: t('integrations.compositeSplit.notPossible'), kind: 'error' })\n return\n }\n if (original.length > AI_LIMITS.selection) {\n notify({ title: t('integrations.compositeSplit.tooLong'), kind: 'error' })\n return\n }\n\n const anchor = captureRange(editor, { from: pos, to: pos + composite.nodeSize }, { startInside: true })\n const toastId = `split-${anchor.id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.compositeSplit.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n let output = ''\n try {\n const outcome = await postAiSse(ai, 'generate', {\n task: 'split-block',\n prompt: String(options.targetChars),\n selection: original,\n context: '',\n model: modelRef('generate'),\n }, { signal: controller.signal, t, onDelta: (text) => { output += text } })\n\n if (outcome.status === 'aborted' || editor.isDestroyed) return\n if (outcome.status === 'rate-limited') {\n notifyAiRateLimited(notify, t)\n return\n }\n if (outcome.status === 'error') {\n notify({ title: t('integrations.compositeSplit.failed'), description: outcome.message, kind: 'error' })\n return\n }\n if (!bodyUnchanged(original, output)) {\n notify({ title: t('integrations.compositeSplit.changed'), kind: 'warning' })\n return\n }\n\n const range = resolveRange(editor.state, anchor)\n const current = range && editor.state.doc.nodeAt(range.from)\n if (!range || current?.type.name !== 'composite' || range.from + current.nodeSize !== range.to || bodyMarkdown(editor, current) !== original) {\n notify({ title: t('integrations.compositeSplit.gone'), kind: 'error' })\n return\n }\n const { schema } = editor\n const replacement = splitByInsertedHeadings(schema, current, parseBlocks(editor, output).blocks.map(block => schema.nodeFromJSON(block)), mode, kind)\n if (!replacement) {\n notify({ title: t('integrations.compositeSplit.notPossible'), kind: 'error' })\n return\n }\n editor.view.dispatch(editor.state.tr.replaceWith(range.from, range.to, replacement))\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"split.js","names":[],"sources":["../../../src/integrations/composite-ai/split.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type Schema } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport { captureRange, parseBlocks, releaseRanges, resolveRange } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport type { Translate } from '../../i18n'\nimport { AI_LIMITS, type ModelRef, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { blockTypesOf, bodyMarkdown, COMPOSITE_CHROME_COUNT, groupHeadingsIntoComposites, TITLE_HIDDEN_KEY } from '../../features/composites/schema'\nimport { childKindFor, type SplitMode } from '../../features/composites/split'\n\nconst HEADING_LINE = /^#{1,6}\\s/\nconst collapse = (text: string) => text.replace(/\\s+/g, ' ').trim()\n\n/**\n * Whether the model only inserted headings: `result` without its heading lines equals `original` with whitespace\n * collapsed (so line breaks and blank lines may differ, words may not). Heading lines the original already has stay\n * part of the comparison, so the model cannot drop or rewrite them.\n */\nexport function bodyUnchanged(original: string, result: string): boolean {\n const own = new Map<string, number>()\n for (const line of original.split('\\n')) {\n if (!HEADING_LINE.test(line)) continue\n const key = collapse(line)\n own.set(key, (own.get(key) ?? 0) + 1)\n }\n const kept = result.split('\\n').filter((line) => {\n if (!HEADING_LINE.test(line)) return true\n const key = collapse(line)\n const left = own.get(key) ?? 0\n if (!left) return false\n own.set(key, left - 1)\n return true\n })\n return collapse(kept.join('\\n')) === collapse(original)\n}\n\n/**\n * The nodes that replace `composite` when the model's result (`blocks`, the result Markdown as blocks, with headings\n * inserted) is split at those headings, or `null` when it yields fewer than two parts. Every part gets the model's\n * heading as a hidden title (`meta.titleHidden`), no block id.\n *\n * - `children`: one node, the composite with the blocks before the first heading followed by one nested Typed block of\n * `kind` per heading.\n * - `siblings`: the composite keeps the blocks before the first heading (without any, the body of the first heading\n * group, its heading is dropped); every further heading group becomes a following sibling of the composite's own Block type.\n *\n * The headings of the result are level 2, so only the lowest level present is grouped (`groupHeadingsIntoComposites`,\n * not recursive).\n */\nexport function splitByInsertedHeadings(schema: Schema, composite: PMNode, blocks: readonly PMNode[], mode: SplitMode, kind: string): PMNode[] | null {\n let minLevel = Infinity\n for (const block of blocks) if (block.type.name === 'heading') minLevel = Math.min(minLevel, block.attrs.level as number)\n if (minLevel === Infinity) return null\n const preambleLength = blocks.findIndex(block => block.type.name === 'heading' && (block.attrs.level as number) === minLevel)\n const grouped = groupHeadingsIntoComposites(schema, blocks, false, kind)\n if (!grouped) return null\n const preamble = grouped.slice(0, preambleLength)\n const parts = grouped.slice(preambleLength).map(part => part.type.create({ ...part.attrs, meta: { ...(part.attrs.meta as Record<string, unknown> | null), [TITLE_HIDDEN_KEY]: true } }, part.content))\n if ((preamble.length ? 1 : 0) + parts.length < 2) return null\n\n const chrome: PMNode[] = []\n composite.forEach((child, _offset, index) => {\n if (index < COMPOSITE_CHROME_COUNT) chrome.push(child)\n })\n const withBody = (body: readonly PMNode[]) => composite.copy(Fragment.from([...chrome, ...body]))\n if (mode === 'children') return [withBody([...preamble, ...parts])]\n\n if (preamble.length) return [withBody(preamble), ...parts]\n const [first, ...rest] = parts\n const firstBody: PMNode[] = []\n first!.forEach((child, _offset, index) => {\n if (index >= COMPOSITE_CHROME_COUNT) firstBody.push(child)\n })\n return [withBody(firstBody), ...rest]\n}\n\n/**\n * „Mit KI teilen“: asks the model to insert `##` headings into the body of the Typed block at `pos` (task `split-block`,\n * `targetChars` as the wanted section size, `generate` Model role) and splits the body at them, in `mode`:\n * `children` makes nested Typed blocks, `siblings` makes following Typed blocks of the same Block type. The model may only insert\n * headings: when the text minus those headings is not the original body (`bodyUnchanged`) nothing is written and a\n * warning is shown. The Typed block is anchored while the model runs; edits to its body meanwhile discard the result.\n * The write is one transaction. `defaultBlockType` is the setting `blocks.defaultBlockType` (see `childKindFor`). Notices go\n * through `notify`, in the language of `t`.\n */\nexport async function splitCompositeWithAi(editor: Editor, pos: number, mode: SplitMode, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, options: { targetChars: number, defaultBlockType: string }): Promise<void> {\n const composite = editor.state.doc.nodeAt(pos)\n if (composite?.type.name !== 'typedBlock') return\n const original = bodyMarkdown(editor, composite)\n if (!original.trim()) return\n const kind = mode === 'children' ? childKindFor(blockTypesOf(editor), String(composite.attrs.blockType), options.defaultBlockType) : String(composite.attrs.blockType)\n if (!kind) {\n notify({ title: t('integrations.compositeSplit.notPossible'), kind: 'error' })\n return\n }\n if (original.length > AI_LIMITS.selection) {\n notify({ title: t('integrations.compositeSplit.tooLong'), kind: 'error' })\n return\n }\n\n const anchor = captureRange(editor, { from: pos, to: pos + composite.nodeSize }, { startInside: true })\n const toastId = `split-${anchor.id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.compositeSplit.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n let output = ''\n try {\n const outcome = await postAiSse(ai, 'generate', {\n task: 'split-block',\n prompt: String(options.targetChars),\n selection: original,\n context: '',\n model: modelRef('generate'),\n }, { signal: controller.signal, t, onDelta: (text) => { output += text } })\n\n if (outcome.status === 'aborted' || editor.isDestroyed) return\n if (outcome.status === 'rate-limited') {\n notifyAiRateLimited(notify, t)\n return\n }\n if (outcome.status === 'error') {\n notify({ title: t('integrations.compositeSplit.failed'), description: outcome.message, kind: 'error' })\n return\n }\n if (!bodyUnchanged(original, output)) {\n notify({ title: t('integrations.compositeSplit.changed'), kind: 'warning' })\n return\n }\n\n const range = resolveRange(editor.state, anchor)\n const current = range && editor.state.doc.nodeAt(range.from)\n if (!range || current?.type.name !== 'typedBlock' || range.from + current.nodeSize !== range.to || bodyMarkdown(editor, current) !== original) {\n notify({ title: t('integrations.compositeSplit.gone'), kind: 'error' })\n return\n }\n const { schema } = editor\n const replacement = splitByInsertedHeadings(schema, current, parseBlocks(editor, output).blocks.map(block => schema.nodeFromJSON(block)), mode, kind)\n if (!replacement) {\n notify({ title: t('integrations.compositeSplit.notPossible'), kind: 'error' })\n return\n }\n editor.view.dispatch(editor.state.tr.replaceWith(range.from, range.to, replacement))\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n"],"mappings":";;;;;;;;;;;;AAUA,MAAM,eAAe;AACrB,MAAM,YAAY,SAAiB,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;;;;;;AAOlE,SAAgB,cAAc,UAAkB,QAAyB;CACvE,MAAM,sBAAM,IAAI,IAAoB;CACpC,KAAK,MAAM,QAAQ,SAAS,MAAM,IAAI,GAAG;EACvC,IAAI,CAAC,aAAa,KAAK,IAAI,GAAG;EAC9B,MAAM,MAAM,SAAS,IAAI;EACzB,IAAI,IAAI,MAAM,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC;CACtC;CACA,MAAM,OAAO,OAAO,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS;EAC/C,IAAI,CAAC,aAAa,KAAK,IAAI,GAAG,OAAO;EACrC,MAAM,MAAM,SAAS,IAAI;EACzB,MAAM,OAAO,IAAI,IAAI,GAAG,KAAK;EAC7B,IAAI,CAAC,MAAM,OAAO;EAClB,IAAI,IAAI,KAAK,OAAO,CAAC;EACrB,OAAO;CACT,CAAC;CACD,OAAO,SAAS,KAAK,KAAK,IAAI,CAAC,MAAM,SAAS,QAAQ;AACxD;;;;;;;;;;;;;;AAeA,SAAgB,wBAAwB,QAAgB,WAAmB,QAA2B,MAAiB,MAA+B;CACpJ,IAAI,WAAW;CACf,KAAK,MAAM,SAAS,QAAQ,IAAI,MAAM,KAAK,SAAS,WAAW,WAAW,KAAK,IAAI,UAAU,MAAM,MAAM,KAAe;CACxH,IAAI,aAAa,UAAU,OAAO;CAClC,MAAM,iBAAiB,OAAO,WAAU,UAAS,MAAM,KAAK,SAAS,aAAc,MAAM,MAAM,UAAqB,QAAQ;CAC5H,MAAM,UAAU,4BAA4B,QAAQ,QAAQ,OAAO,IAAI;CACvE,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,WAAW,QAAQ,MAAM,GAAG,cAAc;CAChD,MAAM,QAAQ,QAAQ,MAAM,cAAc,CAAC,CAAC,KAAI,SAAQ,KAAK,KAAK,OAAO;EAAE,GAAG,KAAK;EAAO,MAAM;GAAE,GAAI,KAAK,MAAM;IAA0C,mBAAmB;EAAK;CAAE,GAAG,KAAK,OAAO,CAAC;CACrM,KAAK,SAAS,SAAS,IAAI,KAAK,MAAM,SAAS,GAAG,OAAO;CAEzD,MAAM,SAAmB,CAAC;CAC1B,UAAU,SAAS,OAAO,SAAS,UAAU;EAC3C,IAAI,QAAA,GAAgC,OAAO,KAAK,KAAK;CACvD,CAAC;CACD,MAAM,YAAY,SAA4B,UAAU,KAAK,SAAS,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC,CAAC;CAChG,IAAI,SAAS,YAAY,OAAO,CAAC,SAAS,CAAC,GAAG,UAAU,GAAG,KAAK,CAAC,CAAC;CAElE,IAAI,SAAS,QAAQ,OAAO,CAAC,SAAS,QAAQ,GAAG,GAAG,KAAK;CACzD,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,MAAM,YAAsB,CAAC;CAC7B,MAAO,SAAS,OAAO,SAAS,UAAU;EACxC,IAAI,SAAA,GAAiC,UAAU,KAAK,KAAK;CAC3D,CAAC;CACD,OAAO,CAAC,SAAS,SAAS,GAAG,GAAG,IAAI;AACtC;;;;;;;;;;AAWA,eAAsB,qBAAqB,QAAgB,KAAa,MAAiB,IAAsC,UAA0C,QAAkB,GAAc,SAA2E;CAClR,MAAM,YAAY,OAAO,MAAM,IAAI,OAAO,GAAG;CAC7C,IAAI,WAAW,KAAK,SAAS,cAAc;CAC3C,MAAM,WAAW,aAAa,QAAQ,SAAS;CAC/C,IAAI,CAAC,SAAS,KAAK,GAAG;CACtB,MAAM,OAAO,SAAS,aAAa,aAAa,aAAa,MAAM,GAAG,OAAO,UAAU,MAAM,SAAS,GAAG,QAAQ,gBAAgB,IAAI,OAAO,UAAU,MAAM,SAAS;CACrK,IAAI,CAAC,MAAM;EACT,OAAO;GAAE,OAAO,EAAE,yCAAyC;GAAG,MAAM;EAAQ,CAAC;EAC7E;CACF;CACA,IAAI,SAAS,SAAS,UAAU,WAAW;EACzC,OAAO;GAAE,OAAO,EAAE,qCAAqC;GAAG,MAAM;EAAQ,CAAC;EACzE;CACF;CAEA,MAAM,SAAS,aAAa,QAAQ;EAAE,MAAM;EAAK,IAAI,MAAM,UAAU;CAAS,GAAG,EAAE,aAAa,KAAK,CAAC;CACtG,MAAM,UAAU,SAAS,OAAO;CAChC,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,cAAc,WAAW,MAAM;CACrC,OAAO,GAAG,WAAW,KAAK;CAC1B,OAAO;EAAE,IAAI;EAAS,OAAO,EAAE,qCAAqC;EAAG,MAAM;EAAQ,MAAM;EAA0B,UAAU;CAAE,CAAC;CAClI,IAAI,SAAS;CACb,IAAI;EACF,MAAM,UAAU,MAAM,UAAU,IAAI,YAAY;GAC9C,MAAM;GACN,QAAQ,OAAO,QAAQ,WAAW;GAClC,WAAW;GACX,SAAS;GACT,OAAO,SAAS,UAAU;EAC5B,GAAG;GAAE,QAAQ,WAAW;GAAQ;GAAG,UAAU,SAAS;IAAE,UAAU;GAAK;EAAE,CAAC;EAE1E,IAAI,QAAQ,WAAW,aAAa,OAAO,aAAa;EACxD,IAAI,QAAQ,WAAW,gBAAgB;GACrC,oBAAoB,QAAQ,CAAC;GAC7B;EACF;EACA,IAAI,QAAQ,WAAW,SAAS;GAC9B,OAAO;IAAE,OAAO,EAAE,oCAAoC;IAAG,aAAa,QAAQ;IAAS,MAAM;GAAQ,CAAC;GACtG;EACF;EACA,IAAI,CAAC,cAAc,UAAU,MAAM,GAAG;GACpC,OAAO;IAAE,OAAO,EAAE,qCAAqC;IAAG,MAAM;GAAU,CAAC;GAC3E;EACF;EAEA,MAAM,QAAQ,aAAa,OAAO,OAAO,MAAM;EAC/C,MAAM,UAAU,SAAS,OAAO,MAAM,IAAI,OAAO,MAAM,IAAI;EAC3D,IAAI,CAAC,SAAS,SAAS,KAAK,SAAS,gBAAgB,MAAM,OAAO,QAAQ,aAAa,MAAM,MAAM,aAAa,QAAQ,OAAO,MAAM,UAAU;GAC7I,OAAO;IAAE,OAAO,EAAE,kCAAkC;IAAG,MAAM;GAAQ,CAAC;GACtE;EACF;EACA,MAAM,EAAE,WAAW;EACnB,MAAM,cAAc,wBAAwB,QAAQ,SAAS,YAAY,QAAQ,MAAM,CAAC,CAAC,OAAO,KAAI,UAAS,OAAO,aAAa,KAAK,CAAC,GAAG,MAAM,IAAI;EACpJ,IAAI,CAAC,aAAa;GAChB,OAAO;IAAE,OAAO,EAAE,yCAAyC;IAAG,MAAM;GAAQ,CAAC;GAC7E;EACF;EACA,OAAO,KAAK,SAAS,OAAO,MAAM,GAAG,YAAY,MAAM,MAAM,MAAM,IAAI,WAAW,CAAC;CACrF,UACQ;EACN,OAAO,UAAU,OAAO;EACxB,OAAO,IAAI,WAAW,KAAK;EAC3B,cAAc,QAAQ,CAAC,MAAM,CAAC;CAChC;AACF"}
@@ -18,9 +18,9 @@ export declare function transferRequest(payload: BlockTransfer, blocks: readonly
18
18
  blocks: readonly AiBlock[];
19
19
  model: ModelRef;
20
20
  };
21
- /** „Zusammenfassung einfügen“: a new Baustein with a model-written summary of the dragged block (needs an AI backend). */
21
+ /** „Zusammenfassung einfügen“: a new Typed block with a model-written summary of the dragged block (needs an AI backend). */
22
22
  export declare const summaryTransform: BlockTransform;
23
- /** „Stichpunkte einfügen“: a new Baustein with the dragged block's key statements as a list (needs an AI backend). */
23
+ /** „Stichpunkte einfügen“: a new Typed block with the dragged block's key statements as a list (needs an AI backend). */
24
24
  export declare const bulletsTransform: BlockTransform;
25
25
  //#endregion
26
26
  export {};
@@ -1,13 +1,13 @@
1
1
  import { de } from "../../i18n/de.js";
2
2
  import { AI_LIMITS } from "../../features/ai/protocol/tasks.js";
3
- import { aiContextOf } from "../../core/pipeline.js";
4
3
  import { newBlockId } from "../../core/schema/block-ids.js";
5
- import "../../features/composites/meta-keys.js";
4
+ import { aiContextOf } from "../../core/pipeline.js";
5
+ import "../../core/derivation.js";
6
6
  import { compositeJSON } from "../../features/composites/nodes.js";
7
- import { transferKindOf, transferSourceHash } from "../../features/transfer/transforms.js";
8
7
  import { modelProfiles } from "../../features/ai/model-profiles.js";
9
8
  import { notifyAiRateLimited } from "../../features/ai/rate-limit.js";
10
9
  import { postAiSse } from "../../features/ai/ai-sse.js";
10
+ import { transferKindOf, transferSourceHash } from "../../features/transfer/transforms.js";
11
11
  import { discardDerived, writeDerivedBody } from "./derive.js";
12
12
  //#region src/integrations/composite-ai/transfer-transforms.ts
13
13
  /** The body of the `generate` request an AI transform sends: the dragged block's Markdown (cut to the task limit) as the selection. */
@@ -21,17 +21,17 @@ function transferRequest(payload, blocks, model, task) {
21
21
  model
22
22
  };
23
23
  }
24
- /** The `Creates` of the Baustein the AI transforms insert (`transferKindOf`). */
24
+ /** The `Creates` of the Typed block the AI transforms insert (`transferKindOf`). */
25
25
  const compositeCreates = (ctx) => ({
26
- type: "composite",
27
- attrs: { kind: transferKindOf(ctx.editor) }
26
+ type: "typedBlock",
27
+ attrs: { blockType: transferKindOf(ctx.editor) }
28
28
  });
29
29
  /** Whether the AI transforms can run for this drop: an AI backend, the source's Markdown and the composite node in the schema. */
30
- const aiAvailable = (ctx) => !!ctx.ai && ctx.payload.markdown.trim().length > 0 && ctx.editor.schema.nodes.composite !== void 0;
30
+ const aiAvailable = (ctx) => !!ctx.ai && ctx.payload.markdown.trim().length > 0 && ctx.editor.schema.nodes.typedBlock !== void 0;
31
31
  /**
32
- * An AI transform: inserts an empty Baustein (kind `transferKindOf`, titled after the source, `meta.derivation` naming the
33
- * source block and the transform), streams the model's answer (`transferRequest`) and writes it into the Baustein with the
34
- * write-back of „Ableiten (KI)“ (`writeDerivedBody`). A failed, aborted or empty run removes the Baustein again.
32
+ * An AI transform: inserts an empty Typed block (Block type `transferKindOf`, titled after the source, `meta.derivation` naming the
33
+ * source block and the transform), streams the model's answer (`transferRequest`) and writes it into the Typed block with the
34
+ * write-back of „Ableiten (KI)“ (`writeDerivedBody`). A failed, aborted or empty run removes the Typed block again.
35
35
  */
36
36
  function aiTransform(spec) {
37
37
  return {
@@ -127,7 +127,7 @@ function aiTransform(spec) {
127
127
  }
128
128
  };
129
129
  }
130
- /** „Zusammenfassung einfügen“: a new Baustein with a model-written summary of the dragged block (needs an AI backend). */
130
+ /** „Zusammenfassung einfügen“: a new Typed block with a model-written summary of the dragged block (needs an AI backend). */
131
131
  const summaryTransform = aiTransform({
132
132
  id: "summary",
133
133
  label: de["transfer.summary"],
@@ -137,7 +137,7 @@ const summaryTransform = aiTransform({
137
137
  method: "transform:summary",
138
138
  titleKey: "transfer.summaryTitle"
139
139
  });
140
- /** „Stichpunkte einfügen“: a new Baustein with the dragged block's key statements as a list (needs an AI backend). */
140
+ /** „Stichpunkte einfügen“: a new Typed block with the dragged block's key statements as a list (needs an AI backend). */
141
141
  const bulletsTransform = aiTransform({
142
142
  id: "bullets",
143
143
  label: de["transfer.bullets"],
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-transforms.js","names":[],"sources":["../../../src/integrations/composite-ai/transfer-transforms.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport type { BlockTransfer } from '../../core'\nimport { aiContextOf } from '../../core'\nimport type { Creates } from '../../core/command-types'\nimport type { AiBlock } from '../../core/feature'\nimport { newBlockId } from '../../core/schema'\nimport { de } from '../../i18n/de'\nimport type { MessageKey } from '../../i18n'\nimport { AI_LIMITS, type AiTaskId, type ModelRef, modelProfiles, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { compositeJSON, DERIVATION_KEY, type Derivation } from '../../features/composites/schema'\nimport { type BlockTransform, type TransformContext, transferKindOf, transferSourceHash } from '../../features/transfer'\nimport { discardDerived, writeDerivedBody } from './derive'\n\n/** The task ids of the AI transforms. */\ntype TransferTask = Extract<AiTaskId, 'transfer-summary' | 'transfer-bullets'>\n\n/** The body of the `generate` request an AI transform sends: the dragged block's Markdown (cut to the task limit) as the selection. */\nexport function transferRequest(payload: BlockTransfer, blocks: readonly AiBlock[], model: ModelRef, task: TransferTask) {\n return { task, prompt: '', selection: payload.markdown.slice(0, AI_LIMITS.selection), context: '', blocks, model }\n}\n\ninterface AiTransformSpec {\n id: string\n label: string\n labelKey: MessageKey\n icon: string\n task: TransferTask\n /** `Derivation.method` of the new Baustein. */\n method: 'transform:summary' | 'transform:bullets'\n titleKey: 'transfer.summaryTitle' | 'transfer.bulletsTitle'\n}\n\n/** The `Creates` of the Baustein the AI transforms insert (`transferKindOf`). */\nconst compositeCreates = (ctx: TransformContext): Creates => ({ type: 'composite', attrs: { kind: transferKindOf(ctx.editor) } })\n\n/** Whether the AI transforms can run for this drop: an AI backend, the source's Markdown and the composite node in the schema. */\nconst aiAvailable = (ctx: TransformContext) => !!ctx.ai && ctx.payload.markdown.trim().length > 0 && ctx.editor.schema.nodes.composite !== undefined\n\n/**\n * An AI transform: inserts an empty Baustein (kind `transferKindOf`, titled after the source, `meta.derivation` naming the\n * source block and the transform), streams the model's answer (`transferRequest`) and writes it into the Baustein with the\n * write-back of „Ableiten (KI)“ (`writeDerivedBody`). A failed, aborted or empty run removes the Baustein again.\n */\nfunction aiTransform(spec: AiTransformSpec): BlockTransform {\n return {\n id: spec.id,\n label: spec.label,\n labelKey: spec.labelKey,\n icon: spec.icon,\n available: aiAvailable,\n creates: compositeCreates,\n run: async ({ editor, payload, pos, ai, app, notify, t }) => {\n if (!ai || !payload.markdown.trim()) return\n const derivation: Derivation | undefined = payload.blockId\n ? {\n from: { block: payload.blockId, ...(payload.documentId && { document: payload.documentId }) },\n method: spec.method,\n createdAt: new Date().toISOString(),\n inputHash: transferSourceHash(editor, payload),\n outputHash: '',\n }\n : undefined\n const id = newBlockId()\n const title = t(spec.titleKey, { title: payload.title.trim() || t('composites.untitled') })\n const json = compositeJSON(transferKindOf(editor))\n const [titleRow, ...rest] = json.content as JSONContent[]\n const created: JSONContent = {\n ...json,\n attrs: { ...json.attrs, id, ...(derivation && { meta: { [DERIVATION_KEY]: derivation } }) },\n content: [{ ...titleRow!, content: [{ type: 'text', text: title }] }, ...rest],\n }\n editor.view.dispatch(editor.state.tr.insert(pos, editor.schema.nodeFromJSON(created)).scrollIntoView())\n\n const toastId = `transfer-${id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('transfer.running', { title }), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n const discard = () => discardDerived(editor, id)\n try {\n let output = ''\n const outcome = await postAiSse(ai, 'generate', transferRequest(payload, aiContextOf(editor).blocks, modelProfiles(app).modelRef('generate'), spec.task), { signal: controller.signal, t, onDelta: (text) => { output += text } })\n if (editor.isDestroyed) return\n if (outcome.status === 'aborted') {\n discard()\n return\n }\n if (outcome.status === 'rate-limited') {\n discard()\n notifyAiRateLimited(notify, t)\n return\n }\n if (outcome.status === 'error') {\n discard()\n notify({ title: t('integrations.compositeDerive.failed'), description: outcome.message, kind: 'error' })\n return\n }\n writeDerivedBody(editor, id, output, { ...(derivation && { derivation }), discard, notify, t, done: t('transfer.done', { title }) })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n }\n },\n }\n}\n\n/** „Zusammenfassung einfügen“: a new Baustein with a model-written summary of the dragged block (needs an AI backend). */\nexport const summaryTransform: BlockTransform = aiTransform({\n id: 'summary',\n label: de['transfer.summary'],\n labelKey: 'transfer.summary',\n icon: 'i-lucide-text-quote',\n task: 'transfer-summary',\n method: 'transform:summary',\n titleKey: 'transfer.summaryTitle',\n})\n\n/** „Stichpunkte einfügen“: a new Baustein with the dragged block's key statements as a list (needs an AI backend). */\nexport const bulletsTransform: BlockTransform = aiTransform({\n id: 'bullets',\n label: de['transfer.bullets'],\n labelKey: 'transfer.bullets',\n icon: 'i-lucide-list',\n task: 'transfer-bullets',\n method: 'transform:bullets',\n titleKey: 'transfer.bulletsTitle',\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"transfer-transforms.js","names":[],"sources":["../../../src/integrations/composite-ai/transfer-transforms.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport { aiContextOf, type BlockTransfer, DERIVATION_KEY, type Derivation } from '../../core'\nimport type { Creates } from '../../core/command-types'\nimport type { AiBlock } from '../../core/feature'\nimport { newBlockId } from '../../core/schema'\nimport { de } from '../../i18n/de'\nimport type { MessageKey } from '../../i18n'\nimport { AI_LIMITS, type AiTaskId, type ModelRef, modelProfiles, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { compositeJSON } from '../../features/composites/schema'\nimport { type BlockTransform, type TransformContext, transferKindOf, transferSourceHash } from '../../features/transfer'\nimport { discardDerived, writeDerivedBody } from './derive'\n\n/** The task ids of the AI transforms. */\ntype TransferTask = Extract<AiTaskId, 'transfer-summary' | 'transfer-bullets'>\n\n/** The body of the `generate` request an AI transform sends: the dragged block's Markdown (cut to the task limit) as the selection. */\nexport function transferRequest(payload: BlockTransfer, blocks: readonly AiBlock[], model: ModelRef, task: TransferTask) {\n return { task, prompt: '', selection: payload.markdown.slice(0, AI_LIMITS.selection), context: '', blocks, model }\n}\n\ninterface AiTransformSpec {\n id: string\n label: string\n labelKey: MessageKey\n icon: string\n task: TransferTask\n /** `Derivation.method` of the new Typed block. */\n method: 'transform:summary' | 'transform:bullets'\n titleKey: 'transfer.summaryTitle' | 'transfer.bulletsTitle'\n}\n\n/** The `Creates` of the Typed block the AI transforms insert (`transferKindOf`). */\nconst compositeCreates = (ctx: TransformContext): Creates => ({ type: 'typedBlock', attrs: { blockType: transferKindOf(ctx.editor) } })\n\n/** Whether the AI transforms can run for this drop: an AI backend, the source's Markdown and the composite node in the schema. */\nconst aiAvailable = (ctx: TransformContext) => !!ctx.ai && ctx.payload.markdown.trim().length > 0 && ctx.editor.schema.nodes.typedBlock !== undefined\n\n/**\n * An AI transform: inserts an empty Typed block (Block type `transferKindOf`, titled after the source, `meta.derivation` naming the\n * source block and the transform), streams the model's answer (`transferRequest`) and writes it into the Typed block with the\n * write-back of „Ableiten (KI)“ (`writeDerivedBody`). A failed, aborted or empty run removes the Typed block again.\n */\nfunction aiTransform(spec: AiTransformSpec): BlockTransform {\n return {\n id: spec.id,\n label: spec.label,\n labelKey: spec.labelKey,\n icon: spec.icon,\n available: aiAvailable,\n creates: compositeCreates,\n run: async ({ editor, payload, pos, ai, app, notify, t }) => {\n if (!ai || !payload.markdown.trim()) return\n const derivation: Derivation | undefined = payload.blockId\n ? {\n from: { block: payload.blockId, ...(payload.documentId && { document: payload.documentId }) },\n method: spec.method,\n createdAt: new Date().toISOString(),\n inputHash: transferSourceHash(editor, payload),\n outputHash: '',\n }\n : undefined\n const id = newBlockId()\n const title = t(spec.titleKey, { title: payload.title.trim() || t('composites.untitled') })\n const json = compositeJSON(transferKindOf(editor))\n const [titleRow, ...rest] = json.content as JSONContent[]\n const created: JSONContent = {\n ...json,\n attrs: { ...json.attrs, id, ...(derivation && { meta: { [DERIVATION_KEY]: derivation } }) },\n content: [{ ...titleRow!, content: [{ type: 'text', text: title }] }, ...rest],\n }\n editor.view.dispatch(editor.state.tr.insert(pos, editor.schema.nodeFromJSON(created)).scrollIntoView())\n\n const toastId = `transfer-${id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('transfer.running', { title }), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n const discard = () => discardDerived(editor, id)\n try {\n let output = ''\n const outcome = await postAiSse(ai, 'generate', transferRequest(payload, aiContextOf(editor).blocks, modelProfiles(app).modelRef('generate'), spec.task), { signal: controller.signal, t, onDelta: (text) => { output += text } })\n if (editor.isDestroyed) return\n if (outcome.status === 'aborted') {\n discard()\n return\n }\n if (outcome.status === 'rate-limited') {\n discard()\n notifyAiRateLimited(notify, t)\n return\n }\n if (outcome.status === 'error') {\n discard()\n notify({ title: t('integrations.compositeDerive.failed'), description: outcome.message, kind: 'error' })\n return\n }\n writeDerivedBody(editor, id, output, { ...(derivation && { derivation }), discard, notify, t, done: t('transfer.done', { title }) })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n }\n },\n }\n}\n\n/** „Zusammenfassung einfügen“: a new Typed block with a model-written summary of the dragged block (needs an AI backend). */\nexport const summaryTransform: BlockTransform = aiTransform({\n id: 'summary',\n label: de['transfer.summary'],\n labelKey: 'transfer.summary',\n icon: 'i-lucide-text-quote',\n task: 'transfer-summary',\n method: 'transform:summary',\n titleKey: 'transfer.summaryTitle',\n})\n\n/** „Stichpunkte einfügen“: a new Typed block with the dragged block's key statements as a list (needs an AI backend). */\nexport const bulletsTransform: BlockTransform = aiTransform({\n id: 'bullets',\n label: de['transfer.bullets'],\n labelKey: 'transfer.bullets',\n icon: 'i-lucide-list',\n task: 'transfer-bullets',\n method: 'transform:bullets',\n titleKey: 'transfer.bulletsTitle',\n})\n"],"mappings":";;;;;;;;;;;;;AAgBA,SAAgB,gBAAgB,SAAwB,QAA4B,OAAiB,MAAoB;CACvH,OAAO;EAAE;EAAM,QAAQ;EAAI,WAAW,QAAQ,SAAS,MAAM,GAAG,UAAU,SAAS;EAAG,SAAS;EAAI;EAAQ;CAAM;AACnH;;AAcA,MAAM,oBAAoB,SAAoC;CAAE,MAAM;CAAc,OAAO,EAAE,WAAW,eAAe,IAAI,MAAM,EAAE;AAAE;;AAGrI,MAAM,eAAe,QAA0B,CAAC,CAAC,IAAI,MAAM,IAAI,QAAQ,SAAS,KAAK,CAAC,CAAC,SAAS,KAAK,IAAI,OAAO,OAAO,MAAM,eAAe,KAAA;;;;;;AAO5I,SAAS,YAAY,MAAuC;CAC1D,OAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,UAAU,KAAK;EACf,MAAM,KAAK;EACX,WAAW;EACX,SAAS;EACT,KAAK,OAAO,EAAE,QAAQ,SAAS,KAAK,IAAI,KAAK,QAAQ,QAAQ;GAC3D,IAAI,CAAC,MAAM,CAAC,QAAQ,SAAS,KAAK,GAAG;GACrC,MAAM,aAAqC,QAAQ,UAC/C;IACE,MAAM;KAAE,OAAO,QAAQ;KAAS,GAAI,QAAQ,cAAc,EAAE,UAAU,QAAQ,WAAW;IAAG;IAC5F,QAAQ,KAAK;IACb,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;IAClC,WAAW,mBAAmB,QAAQ,OAAO;IAC7C,YAAY;GACd,IACA,KAAA;GACJ,MAAM,KAAK,WAAW;GACtB,MAAM,QAAQ,EAAE,KAAK,UAAU,EAAE,OAAO,QAAQ,MAAM,KAAK,KAAK,EAAE,qBAAqB,EAAE,CAAC;GAC1F,MAAM,OAAO,cAAc,eAAe,MAAM,CAAC;GACjD,MAAM,CAAC,UAAU,GAAG,QAAQ,KAAK;GACjC,MAAM,UAAuB;IAC3B,GAAG;IACH,OAAO;KAAE,GAAG,KAAK;KAAO;KAAI,GAAI,cAAc,EAAE,MAAM,GAAA,eAAoB,WAAW,EAAE;IAAG;IAC1F,SAAS,CAAC;KAAE,GAAG;KAAW,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;KAAM,CAAC;IAAE,GAAG,GAAG,IAAI;GAC/E;GACA,OAAO,KAAK,SAAS,OAAO,MAAM,GAAG,OAAO,KAAK,OAAO,OAAO,aAAa,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;GAEtG,MAAM,UAAU,YAAY;GAC5B,MAAM,aAAa,IAAI,gBAAgB;GACvC,MAAM,cAAc,WAAW,MAAM;GACrC,OAAO,GAAG,WAAW,KAAK;GAC1B,OAAO;IAAE,IAAI;IAAS,OAAO,EAAE,oBAAoB,EAAE,MAAM,CAAC;IAAG,MAAM;IAAQ,MAAM;IAA0B,UAAU;GAAE,CAAC;GAC1H,MAAM,gBAAgB,eAAe,QAAQ,EAAE;GAC/C,IAAI;IACF,IAAI,SAAS;IACb,MAAM,UAAU,MAAM,UAAU,IAAI,YAAY,gBAAgB,SAAS,YAAY,MAAM,CAAC,CAAC,QAAQ,cAAc,GAAG,CAAC,CAAC,SAAS,UAAU,GAAG,KAAK,IAAI,GAAG;KAAE,QAAQ,WAAW;KAAQ;KAAG,UAAU,SAAS;MAAE,UAAU;KAAK;IAAE,CAAC;IACjO,IAAI,OAAO,aAAa;IACxB,IAAI,QAAQ,WAAW,WAAW;KAChC,QAAQ;KACR;IACF;IACA,IAAI,QAAQ,WAAW,gBAAgB;KACrC,QAAQ;KACR,oBAAoB,QAAQ,CAAC;KAC7B;IACF;IACA,IAAI,QAAQ,WAAW,SAAS;KAC9B,QAAQ;KACR,OAAO;MAAE,OAAO,EAAE,qCAAqC;MAAG,aAAa,QAAQ;MAAS,MAAM;KAAQ,CAAC;KACvG;IACF;IACA,iBAAiB,QAAQ,IAAI,QAAQ;KAAE,GAAI,cAAc,EAAE,WAAW;KAAI;KAAS;KAAQ;KAAG,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC;IAAE,CAAC;GACrI,UACQ;IACN,OAAO,UAAU,OAAO;IACxB,OAAO,IAAI,WAAW,KAAK;GAC7B;EACF;CACF;AACF;;AAGA,MAAa,mBAAmC,YAAY;CAC1D,IAAI;CACJ,OAAO,GAAG;CACV,UAAU;CACV,MAAM;CACN,MAAM;CACN,QAAQ;CACR,UAAU;AACZ,CAAC;;AAGD,MAAa,mBAAmC,YAAY;CAC1D,IAAI;CACJ,OAAO,GAAG;CACV,UAAU;CACV,MAAM;CACN,MAAM;CACN,QAAQ;CACR,UAAU;AACZ,CAAC"}
@@ -6,9 +6,10 @@ import "../../core/index.js";
6
6
  *
7
7
  * - **Wrapping:** the `wrapImport` stage puts the blocks of every imported file (parsed text or Markdown, or the
8
8
  * uploaded media or file block; drop, paste, picker and recorder alike) into one composite titled with the
9
- * file's name stem and carrying its filename, type, size and import date as meta. The kind follows the MIME type:
10
- * audio and video become a `recording`, images a `figure`, everything else (PDFs, office files, text) a `document`.
11
- * Without this feature the blocks are inserted as they are.
9
+ * file's name stem and carrying its filename, type, size and import date as meta. The Block type is the one whose
10
+ * `import` capability takes the file's media: by default audio and video become a `recording`, images a `figure`, everything
11
+ * else (PDFs, office files, text) a `document`. Without a Block type that takes the file, or without this feature, the
12
+ * blocks are inserted as they are.
12
13
  * - **Actions:** the `/` command „Datei importieren“ (`datei`, ability `composite`) picks any files and imports them
13
14
  * through `editor.storage.media.importFiles` at the caret; the block action „Quelle ersetzen“ (`source-replace`, on
14
15
  * composites with a source block) uploads a new file into the existing source block, keeping its id.