@ecsplico/editor 3.5.1 → 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.
- package/CHANGELOG.md +71 -0
- package/dist/adapters/direct-ai.d.ts +4 -4
- package/dist/adapters/direct-ai.js +2 -2
- package/dist/adapters/direct-ai.js.map +1 -1
- package/dist/adapters/document-state.d.ts +1 -1
- package/dist/adapters/document-state.js.map +1 -1
- package/dist/adapters/forge.d.ts +2 -2
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -3
- package/dist/adapters/nitro.js +3 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -6
- package/dist/adapters/shared.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/config/index.d.ts +14 -14
- package/dist/config/index.js +8 -8
- package/dist/config/index.js.map +1 -1
- package/dist/core/backend-types.d.ts +3 -3
- package/dist/core/backend-types.js.map +1 -1
- package/dist/core/backend.d.ts +4 -4
- package/dist/core/backend.js.map +1 -1
- package/dist/core/block-convert.d.ts +1 -1
- package/dist/core/block-convert.js +5 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/block-transfer.d.ts +8 -4
- package/dist/core/block-transfer.js +23 -14
- package/dist/core/block-transfer.js.map +1 -1
- package/dist/core/capabilities.d.ts +113 -0
- package/dist/core/capabilities.js +155 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/command-types.d.ts +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/convert.d.ts +5 -5
- package/dist/core/convert.js +5 -5
- package/dist/core/convert.js.map +1 -1
- package/dist/core/core-feature.js +1 -1
- package/dist/core/define-editor.d.ts +2 -2
- package/dist/core/define-editor.js +34 -6
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/derivation.d.ts +119 -0
- package/dist/core/derivation.js +187 -0
- package/dist/core/derivation.js.map +1 -0
- package/dist/core/derive.d.ts +61 -0
- package/dist/core/derive.js +69 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/extension-points.d.ts +16 -0
- package/dist/core/feature-context.d.ts +5 -1
- package/dist/core/feature-context.js +10 -3
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +41 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.js +1 -1
- package/dist/core/fences.js.map +1 -1
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +5 -1
- package/dist/core/pipeline.d.ts +14 -5
- package/dist/core/pipeline.js +19 -7
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/properties.d.ts +22 -0
- package/dist/core/properties.js +17 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/schema/block-ids.js +5 -5
- package/dist/core/schema/block-ids.js.map +1 -1
- package/dist/core/schema/index.d.ts +2 -1
- package/dist/core/schema/index.js +2 -1
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/opaque-fence.d.ts +4 -4
- package/dist/core/schema/opaque-fence.js +7 -7
- package/dist/core/schema/opaque-fence.js.map +1 -1
- package/dist/core/schema/persisted-names.d.ts +58 -0
- package/dist/core/schema/persisted-names.js +96 -0
- package/dist/core/schema/persisted-names.js.map +1 -0
- package/dist/core/toolbar-items.js +1 -1
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +5 -1
- package/dist/core/util.js.map +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/assistant.d.ts +4 -4
- package/dist/features/ai/assistant.js +1 -1
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
- package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
- package/dist/features/ai/components/SettingsAiTab.js +8 -8
- package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +2 -2
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +2 -2
- package/dist/features/ai/document-chat.js.map +1 -1
- package/dist/features/ai/feature.d.ts +2 -2
- package/dist/features/ai/feature.js +2 -2
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
- package/dist/features/ai/ghost-autocomplete.js +1 -1
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +3 -3
- package/dist/features/ai/index.js +2 -2
- package/dist/features/ai/model-profiles.d.ts +9 -9
- package/dist/features/ai/model-profiles.js +13 -13
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
- package/dist/features/ai/protocol/agent-ops.js +1 -1
- package/dist/features/ai/protocol/agent-ops.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.d.ts +7 -7
- package/dist/features/ai/protocol/block-lines.js +10 -10
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.d.ts +5 -5
- package/dist/features/ai/protocol/chat.js +12 -12
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/generate.d.ts +1 -1
- package/dist/features/ai/protocol/generate.js +1 -1
- package/dist/features/ai/protocol/generate.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -3
- package/dist/features/ai/protocol/index.js +2 -2
- package/dist/features/ai/protocol/models.d.ts +3 -3
- package/dist/features/ai/protocol/models.js +3 -3
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/protocol/schemas.d.ts +1 -1
- package/dist/features/ai/protocol/schemas.js +1 -1
- package/dist/features/ai/protocol/schemas.js.map +1 -1
- package/dist/features/ai/protocol/tasks.d.ts +5 -5
- package/dist/features/ai/protocol/tasks.js +12 -12
- package/dist/features/ai/protocol/tasks.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
- package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
- package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
- package/dist/features/ai/react/SettingsAiTab.js +8 -8
- package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +1 -1
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
- package/dist/features/ai/react/use-model-profiles.js +2 -2
- package/dist/features/ai/react/use-model-profiles.js.map +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +1 -1
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +4 -4
- package/dist/features/ai/use-model-profiles.js +2 -2
- package/dist/features/ai/use-model-profiles.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +8 -4
- package/dist/features/block-ui/block-actions.js +38 -22
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/block-target.d.ts +29 -0
- package/dist/features/block-ui/block-target.js +63 -0
- package/dist/features/block-ui/block-target.js.map +1 -0
- package/dist/features/block-ui/components/BlockHandles.js +3 -3
- package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +11 -23
- package/dist/features/block-ui/components/BlockUi.js.map +1 -1
- package/dist/features/block-ui/feature.d.ts +3 -2
- package/dist/features/block-ui/feature.js +3 -2
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/handle-geometry.js +12 -23
- package/dist/features/block-ui/handle-geometry.js.map +1 -1
- package/dist/features/block-ui/index.d.ts +2 -1
- package/dist/features/block-ui/index.js +2 -1
- package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
- package/dist/features/block-ui/react/BlockHandles.js +4 -4
- package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +13 -25
- package/dist/features/block-ui/react/BlockUi.js.map +1 -1
- package/dist/features/comments/model.js +1 -1
- package/dist/features/composites/accepted-children.d.ts +5 -4
- package/dist/features/composites/accepted-children.js +26 -26
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.d.ts +4 -4
- package/dist/features/composites/ai-brief.js +14 -12
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/anchors.d.ts +1 -1
- package/dist/features/composites/anchors.js.map +1 -1
- package/dist/features/composites/baskets.d.ts +1 -1
- package/dist/features/composites/baskets.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +1 -1
- package/dist/features/composites/bibliography-form.js +1 -1
- package/dist/features/composites/bibliography-form.js.map +1 -1
- package/dist/features/composites/bibliography.js.map +1 -1
- package/dist/features/composites/block-types-json.d.ts +38 -0
- package/dist/features/composites/block-types-json.js +122 -0
- package/dist/features/composites/block-types-json.js.map +1 -0
- package/dist/features/composites/block-types.d.ts +119 -0
- package/dist/features/composites/block-types.js +343 -0
- package/dist/features/composites/block-types.js.map +1 -0
- package/dist/features/composites/capabilities.js +109 -0
- package/dist/features/composites/capabilities.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +5 -5
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.js +18 -8
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeDetails.js +11 -10
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
- package/dist/features/composites/components/CompositeInspector.js +136 -113
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
- package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeTable.js +2 -2
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeView.js +19 -17
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +15 -6
- package/dist/features/composites/components/DerivationBadge.js.map +1 -1
- package/dist/features/composites/components/FocusChip.js +1 -1
- package/dist/features/composites/components/FocusChip.js.map +1 -1
- package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
- package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/components/ReferenceView.js +1 -1
- package/dist/features/composites/components/ReferenceView.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.js +18 -18
- package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
- package/dist/features/composites/convert.d.ts +4 -4
- package/dist/features/composites/convert.js +27 -28
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derived-chrome.js +34 -28
- package/dist/features/composites/derived-chrome.js.map +1 -1
- package/dist/features/composites/editing-settings-keys.js +6 -6
- package/dist/features/composites/editing-settings-keys.js.map +1 -1
- package/dist/features/composites/feature.d.ts +10 -10
- package/dist/features/composites/feature.js +58 -46
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +3 -3
- package/dist/features/composites/fences.js +18 -13
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/focus.d.ts +10 -10
- package/dist/features/composites/focus.js +11 -11
- package/dist/features/composites/focus.js.map +1 -1
- package/dist/features/composites/heading-composites.d.ts +5 -5
- package/dist/features/composites/heading-composites.js +13 -16
- package/dist/features/composites/heading-composites.js.map +1 -1
- package/dist/features/composites/index.d.ts +20 -18
- package/dist/features/composites/index.js +9 -7
- package/dist/features/composites/inspector-model.d.ts +45 -22
- package/dist/features/composites/inspector-model.js +53 -14
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +5 -4
- package/dist/features/composites/legacy.js +16 -23
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/markdown-export.js +3 -3
- package/dist/features/composites/markdown-export.js.map +1 -1
- package/dist/features/composites/merge.d.ts +8 -7
- package/dist/features/composites/merge.js +39 -12
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/features/composites/meta-display.js +5 -5
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +5 -5
- package/dist/features/composites/meta-keys.js +8 -8
- package/dist/features/composites/meta-keys.js.map +1 -1
- package/dist/features/composites/node-views.d.ts +3 -3
- package/dist/features/composites/node-views.js +2 -2
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +13 -13
- package/dist/features/composites/nodes.js +100 -77
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/outline.d.ts +15 -12
- package/dist/features/composites/outline.js +24 -21
- package/dist/features/composites/outline.js.map +1 -1
- package/dist/features/composites/properties.d.ts +51 -0
- package/dist/features/composites/properties.js +89 -0
- package/dist/features/composites/properties.js.map +1 -0
- package/dist/features/composites/react/BibliographyEditor.js +5 -5
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
- package/dist/features/composites/react/CompositeChrome.js +15 -6
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
- package/dist/features/composites/react/CompositeDetails.js +11 -10
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
- package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
- package/dist/features/composites/react/CompositeInspector.js +142 -128
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeTable.d.ts +1 -1
- package/dist/features/composites/react/CompositeTable.js +3 -3
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeView.js +17 -15
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +13 -4
- package/dist/features/composites/react/DerivationBadge.js.map +1 -1
- package/dist/features/composites/react/FocusChip.d.ts +1 -1
- package/dist/features/composites/react/FocusChip.js +1 -1
- package/dist/features/composites/react/FocusChip.js.map +1 -1
- package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/react/ReferenceView.d.ts +1 -1
- package/dist/features/composites/react/ReferenceView.js +1 -1
- package/dist/features/composites/react/ReferenceView.js.map +1 -1
- package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
- package/dist/features/composites/react/SettingsEditingTab.js +20 -20
- package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/react.js +1 -1
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +1 -1
- package/dist/features/composites/reference-ai.js.map +1 -1
- package/dist/features/composites/reference-label.d.ts +3 -3
- package/dist/features/composites/reference-label.js +6 -6
- package/dist/features/composites/reference-label.js.map +1 -1
- package/dist/features/composites/reference-suggestion.d.ts +1 -1
- package/dist/features/composites/reference-suggestion.js +3 -3
- package/dist/features/composites/reference-suggestion.js.map +1 -1
- package/dist/features/composites/reference-text.d.ts +2 -2
- package/dist/features/composites/reference-text.js +4 -4
- package/dist/features/composites/reference-text.js.map +1 -1
- package/dist/features/composites/reference.d.ts +3 -3
- package/dist/features/composites/reference.js +1 -1
- package/dist/features/composites/reference.js.map +1 -1
- package/dist/features/composites/reveal-source.d.ts +3 -3
- package/dist/features/composites/reveal-source.js +6 -6
- package/dist/features/composites/reveal-source.js.map +1 -1
- package/dist/features/composites/rows-model.d.ts +2 -2
- package/dist/features/composites/rows-model.js +4 -3
- package/dist/features/composites/rows-model.js.map +1 -1
- package/dist/features/composites/rows.d.ts +16 -28
- package/dist/features/composites/rows.js +20 -54
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +12 -11
- package/dist/features/composites/schema.js +10 -9
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/source.d.ts +20 -0
- package/dist/features/composites/source.js +40 -0
- package/dist/features/composites/source.js.map +1 -0
- package/dist/features/composites/split.d.ts +11 -11
- package/dist/features/composites/split.js +20 -20
- package/dist/features/composites/split.js.map +1 -1
- package/dist/features/composites/structure-mode.js +3 -3
- package/dist/features/composites/structure-mode.js.map +1 -1
- package/dist/features/composites/table-model.js +2 -2
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/use-composite-inspector.js +3 -1
- package/dist/features/composites/use-composite-inspector.js.map +1 -1
- package/dist/features/composites/use-composite-rows.d.ts +2 -2
- package/dist/features/composites/use-composite-rows.js.map +1 -1
- package/dist/features/composites/vue.js +1 -1
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
- package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/feature.d.ts +1 -1
- package/dist/features/image-studio/feature.js +1 -1
- package/dist/features/image-studio/feature.js.map +1 -1
- package/dist/features/image-studio/node-core.d.ts +3 -3
- package/dist/features/image-studio/node-core.js +1 -1
- package/dist/features/image-studio/node-core.js.map +1 -1
- package/dist/features/image-studio/node-store.d.ts +1 -1
- package/dist/features/image-studio/node-store.js +1 -1
- package/dist/features/image-studio/node-store.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/react/store.d.ts +3 -3
- package/dist/features/image-studio/react/store.js.map +1 -1
- package/dist/features/image-studio/react.d.ts +1 -1
- package/dist/features/image-studio/react.js +1 -1
- package/dist/features/image-studio/react.js.map +1 -1
- package/dist/features/image-studio/schema.d.ts +1 -1
- package/dist/features/image-studio/schema.js +1 -1
- package/dist/features/image-studio/schema.js.map +1 -1
- package/dist/features/image-studio/state.d.ts +3 -3
- package/dist/features/image-studio/state.js +2 -2
- package/dist/features/image-studio/state.js.map +1 -1
- package/dist/features/image-studio/store.d.ts +3 -3
- package/dist/features/image-studio/vue.d.ts +1 -1
- package/dist/features/image-studio/vue.js +1 -1
- package/dist/features/image-studio/vue.js.map +1 -1
- package/dist/features/media/index.js +1 -1
- package/dist/features/media/react/AudioRecorderModal.js +1 -1
- package/dist/features/media/react.js +1 -1
- package/dist/features/mentions/tag.js +2 -1
- package/dist/features/mentions/tag.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.d.ts +1 -1
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/theme-runtime.js +1 -1
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/features/transfer/feature.js +1 -1
- package/dist/features/transfer/feature.js.map +1 -1
- package/dist/features/transfer/transforms.d.ts +4 -4
- package/dist/features/transfer/transforms.js +12 -12
- package/dist/features/transfer/transforms.js.map +1 -1
- package/dist/i18n/de/ai.js +4 -4
- package/dist/i18n/de/ai.js.map +1 -1
- package/dist/i18n/de/authors.js +1 -1
- package/dist/i18n/de/authors.js.map +1 -1
- package/dist/i18n/de/comments.js +1 -1
- package/dist/i18n/de/comments.js.map +1 -1
- package/dist/i18n/de/composites.js +62 -59
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/image-studio.js +2 -2
- package/dist/i18n/de/image-studio.js.map +1 -1
- package/dist/i18n/de/integrations.js +20 -20
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/markdown.js +1 -1
- package/dist/i18n/de/markdown.js.map +1 -1
- package/dist/i18n/de/palette.js +1 -1
- package/dist/i18n/de/palette.js.map +1 -1
- package/dist/i18n/de/themes.js +3 -3
- package/dist/i18n/de/themes.js.map +1 -1
- package/dist/i18n/de/transfer.js +2 -2
- package/dist/i18n/de/transfer.js.map +1 -1
- package/dist/i18n/de/tree.js +6 -6
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +101 -98
- package/dist/i18n/en/ai.js +2 -2
- package/dist/i18n/en/ai.js.map +1 -1
- package/dist/i18n/en/composites.js +64 -61
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +9 -9
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/markdown.js +1 -1
- package/dist/i18n/en/markdown.js.map +1 -1
- package/dist/i18n/en/palette.js +1 -1
- package/dist/i18n/en/palette.js.map +1 -1
- package/dist/i18n/en/themes.js +4 -4
- package/dist/i18n/en/themes.js.map +1 -1
- package/dist/i18n/en/tree.js +5 -5
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
- package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
- package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
- package/dist/integrations/composite-ai/composite-fill.js +5 -5
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
- package/dist/integrations/composite-ai/composite-summary.js +5 -5
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +17 -17
- package/dist/integrations/composite-ai/derive.js +27 -26
- package/dist/integrations/composite-ai/derive.js.map +1 -1
- package/dist/integrations/composite-ai/index.d.ts +14 -15
- package/dist/integrations/composite-ai/index.js +98 -77
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +9 -9
- package/dist/integrations/composite-ai/rendition.js +27 -27
- package/dist/integrations/composite-ai/rendition.js.map +1 -1
- package/dist/integrations/composite-ai/split.d.ts +8 -8
- package/dist/integrations/composite-ai/split.js +12 -12
- package/dist/integrations/composite-ai/split.js.map +1 -1
- package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
- package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
- package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
- package/dist/integrations/composite-media/index.d.ts +4 -3
- package/dist/integrations/composite-media/index.js +20 -14
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/document.js.map +1 -1
- package/dist/nuxt/module.d.ts +30 -24
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +6 -6
- package/dist/presets/compose.js +8 -5
- package/dist/presets/compose.js.map +1 -1
- package/dist/react/AdvancedEditor.d.ts +2 -2
- package/dist/react/AdvancedEditor.js +1 -1
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/compose.d.ts +1 -1
- package/dist/react/compose.js +2 -2
- package/dist/react/compose.js.map +1 -1
- package/dist/react/composed-surface.d.ts +5 -5
- package/dist/react/composed-surface.js +2 -2
- package/dist/react/composed-surface.js.map +1 -1
- package/dist/server/ai.d.ts +7 -7
- package/dist/server/ai.js +1 -1
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +4 -4
- package/dist/server/collab.js +22 -17
- package/dist/server/collab.js.map +1 -1
- package/dist/server/handlers/ai.d.ts +9 -6
- package/dist/server/handlers/ai.js +13 -17
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +4 -0
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +33 -32
- package/dist/server/handlers/editor.js +13 -8
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/images.d.ts +1 -1
- package/dist/server/handlers/images.js +1 -1
- package/dist/server/handlers/images.js.map +1 -1
- package/dist/server/host.d.ts +4 -0
- package/dist/server/host.js +10 -2
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/ports.d.ts +8 -8
- package/dist/server/ports.js.map +1 -1
- package/dist/settings/index.d.ts +20 -19
- package/dist/settings/index.js +25 -24
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +18 -0
- package/dist/settings/migrate.js +46 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/values.d.ts +12 -12
- package/dist/settings/values.js +11 -11
- package/dist/settings/values.js.map +1 -1
- package/dist/styles/composites.css +10 -10
- package/dist/tree/DocumentTree.js +12 -5
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/drop-rules.js +5 -5
- package/dist/tree/drop-rules.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +14 -5
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +6 -6
- package/dist/tree/tree-host.js.map +1 -1
- package/dist/tree/tree-items.js +34 -28
- package/dist/tree/tree-items.js.map +1 -1
- package/dist/tree/tree-model.js +16 -16
- package/dist/tree/tree-model.js.map +1 -1
- package/dist/tree/tree-rows.js +2 -2
- package/dist/tree/tree-rows.js.map +1 -1
- package/dist/tree/tree-view-model.d.ts +2 -2
- package/dist/tree/tree-view-model.js.map +1 -1
- package/dist/vue/AdvancedEditor.js +2 -2
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/dist/vue/compose.d.ts +1 -1
- package/dist/vue/compose.js +2 -2
- package/dist/vue/compose.js.map +1 -1
- package/package.json +1 -1
- package/dist/features/composites/derivation.d.ts +0 -62
- package/dist/features/composites/derivation.js +0 -102
- package/dist/features/composites/derivation.js.map +0 -1
- package/dist/features/composites/kinds.d.ts +0 -83
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { blockIdOf } from "../../core/schema/block-ids.js";
|
|
2
|
+
import { capabilitiesOf, capabilityConfigOf } from "../../core/capabilities.js";
|
|
2
3
|
import { fetchErrorMessage } from "../../core/fetch-error.js";
|
|
3
|
-
import { compositeKind } from "../../features/composites/kinds.js";
|
|
4
4
|
import "../../features/composites/meta-keys.js";
|
|
5
|
-
import {
|
|
6
|
-
import { compositeKindsOf } from "../../features/composites/nodes.js";
|
|
5
|
+
import { blockTypesOf } from "../../features/composites/nodes.js";
|
|
7
6
|
import { bibOf } from "../../features/composites/bibliography.js";
|
|
7
|
+
import { sourceOf } from "../../features/composites/source.js";
|
|
8
|
+
import { metaWithProperty } from "../../features/composites/properties.js";
|
|
8
9
|
import { isRateLimited, notifyAiRateLimited } from "../../features/ai/rate-limit.js";
|
|
9
|
-
import {
|
|
10
|
+
import { compositeOfRow } from "../../features/composites/rows.js";
|
|
10
11
|
//#region src/integrations/composite-ai/bibliography-fetch.ts
|
|
11
12
|
/** A DOI as the extract route accepts it (`DOI_PATTERN` of the server handler). */
|
|
12
13
|
const DOI = /^10\.\d{4,9}\/\S+$/;
|
|
@@ -14,7 +15,7 @@ const DOI_PREFIX = /^(?:https?:\/\/(?:dx\.)?doi\.org\/|doi:\s*)/i;
|
|
|
14
15
|
/** Block IDs with a running request, so a second click does not start another one. */
|
|
15
16
|
const running = /* @__PURE__ */ new Set();
|
|
16
17
|
/**
|
|
17
|
-
* The DOI of the
|
|
18
|
+
* The DOI of the Typed block: `meta.doi`, else the DOI of `meta.bib`, with a `https://doi.org/` or `doi:` prefix removed;
|
|
18
19
|
* '' when there is none, `null` when the stored text is no DOI.
|
|
19
20
|
*/
|
|
20
21
|
function doiOf(composite) {
|
|
@@ -24,33 +25,32 @@ function doiOf(composite) {
|
|
|
24
25
|
return DOI.test(doi) ? doi : null;
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
* Whether „Literaturangaben abrufen“ applies to the
|
|
28
|
+
* Whether „Literaturangaben abrufen“ applies to the Typed block: its Block type has a `bibliography` field and bibliographic
|
|
28
29
|
* data can be looked up — it has a DOI (`meta.doi`, `meta.bib.DOI`) or a PDF source stored as an asset to read it from.
|
|
29
30
|
*/
|
|
30
31
|
function canFetchBibliography(editor, node) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (!compositeKind(kinds, String(node.attrs.kind)).fields.some((field) => field.type === "bibliography")) return false;
|
|
32
|
+
const kinds = blockTypesOf(editor);
|
|
33
|
+
if (!capabilitiesOf(editor, node).has("bibliography")) return false;
|
|
34
34
|
if (doiOf(node)) return true;
|
|
35
35
|
const source = sourceOf(node, kinds);
|
|
36
36
|
return source?.asset != null && source.node.attrs.mimeType === "application/pdf";
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* „Literaturangaben abrufen“ / „DOI abrufen“: fetches the bibliographic data of the
|
|
39
|
+
* „Literaturangaben abrufen“ / „DOI abrufen“: fetches the bibliographic data of the Typed block at `pos` (`ai.extract`,
|
|
40
40
|
* method `bibliography`: Crossref by the DOI — `meta.doi`, else `meta.bib.DOI` — and, without one, from the PDF source's
|
|
41
41
|
* first pages by the model) and stores it as `meta.bib`, replacing the previous data. The title of the result is only
|
|
42
|
-
* applied to an untitled
|
|
43
|
-
*
|
|
44
|
-
* `documentId` is the document whose assets the request addresses when the
|
|
42
|
+
* applied to an untitled Typed block and never stored in `meta.bib`. Both changes are one transaction (one undo step). The
|
|
43
|
+
* Typed block is found again by its block ID after the request, so edits while it runs do not misplace the result.
|
|
44
|
+
* `documentId` is the document whose assets the request addresses when the Typed block has no stored source (a DOI-only
|
|
45
45
|
* lookup needs no file). Notices go through `notify`, in the language of `t`; the progress notice stays until the
|
|
46
46
|
* request ends.
|
|
47
47
|
*/
|
|
48
48
|
async function fetchBibliography(editor, pos, ai, modelRef, notify, t, documentId) {
|
|
49
49
|
const composite = editor.state.doc.nodeAt(pos);
|
|
50
50
|
const id = composite && blockIdOf(composite);
|
|
51
|
-
if (composite?.type.name !== "
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
51
|
+
if (composite?.type.name !== "typedBlock" || !id) return;
|
|
52
|
+
const definitions = capabilityConfigOf(editor, composite, "properties")?.definitions ?? [];
|
|
53
|
+
if (!capabilitiesOf(editor, composite).has("bibliography") || running.has(id)) return;
|
|
54
54
|
const doi = doiOf(composite);
|
|
55
55
|
if (doi === null) {
|
|
56
56
|
notify({
|
|
@@ -59,7 +59,7 @@ async function fetchBibliography(editor, pos, ai, modelRef, notify, t, documentI
|
|
|
59
59
|
});
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
|
-
const source = sourceOf(composite,
|
|
62
|
+
const source = sourceOf(composite, blockTypesOf(editor));
|
|
63
63
|
const asset = source?.asset != null && source.node.attrs.mimeType === "application/pdf" ? source.asset : null;
|
|
64
64
|
const targetDocument = doi ? documentId ?? asset?.documentId : asset?.documentId;
|
|
65
65
|
if (!targetDocument) {
|
|
@@ -107,13 +107,13 @@ async function fetchBibliography(editor, pos, ai, modelRef, notify, t, documentI
|
|
|
107
107
|
pos
|
|
108
108
|
});
|
|
109
109
|
if (!found) return false;
|
|
110
|
-
const field =
|
|
110
|
+
const field = definitions.find((candidate) => candidate.key === "bib") ?? {
|
|
111
111
|
key: "bib",
|
|
112
112
|
type: "bibliography"
|
|
113
113
|
};
|
|
114
114
|
tr.setNodeMarkup(found.pos, void 0, {
|
|
115
115
|
...found.node.attrs,
|
|
116
|
-
meta:
|
|
116
|
+
meta: metaWithProperty(found.node.attrs.meta ?? {}, field, bib)
|
|
117
117
|
});
|
|
118
118
|
const heading = found.node.child(0);
|
|
119
119
|
if (title?.trim() && !heading.textContent.trim()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bibliography-fetch.js","names":[],"sources":["../../../src/integrations/composite-ai/bibliography-fetch.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport { fetchErrorMessage } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { isRateLimited, type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport { BIB_KEY, bibOf,
|
|
1
|
+
{"version":3,"file":"bibliography-fetch.js","names":[],"sources":["../../../src/integrations/composite-ai/bibliography-fetch.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport type { EditorBackend } from '../../core/backend'\nimport { capabilitiesOf, capabilityConfigOf, fetchErrorMessage } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { isRateLimited, type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport { BIB_KEY, bibOf, blockTypesOf, type PropertiesConfig, sourceOf } from '../../features/composites/schema'\nimport { metaWithProperty } from '../../features/composites/properties'\nimport { compositeOfRow } from '../../features/composites/rows'\n\n/** A DOI as the extract route accepts it (`DOI_PATTERN` of the server handler). */\nconst DOI = /^10\\.\\d{4,9}\\/\\S+$/\nconst DOI_PREFIX = /^(?:https?:\\/\\/(?:dx\\.)?doi\\.org\\/|doi:\\s*)/i\n\n/** Block IDs with a running request, so a second click does not start another one. */\nconst running = new Set<string>()\n\n/**\n * The DOI of the Typed block: `meta.doi`, else the DOI of `meta.bib`, with a `https://doi.org/` or `doi:` prefix removed;\n * '' when there is none, `null` when the stored text is no DOI.\n */\nexport function doiOf(composite: PMNode): string | null {\n const raw = [(composite.attrs.meta as Record<string, unknown> | null | undefined)?.doi, bibOf(composite)?.DOI]\n .find((value): value is string => typeof value === 'string' && value.trim() !== '')\n if (raw === undefined) return ''\n const doi = raw.trim().replace(DOI_PREFIX, '')\n return DOI.test(doi) ? doi : null\n}\n\n/**\n * Whether „Literaturangaben abrufen“ applies to the Typed block: its Block type has a `bibliography` field and bibliographic\n * data can be looked up — it has a DOI (`meta.doi`, `meta.bib.DOI`) or a PDF source stored as an asset to read it from.\n */\nexport function canFetchBibliography(editor: Editor, node: PMNode): boolean {\n const kinds = blockTypesOf(editor)\n if (!capabilitiesOf(editor, node).has('bibliography')) return false\n if (doiOf(node)) return true\n const source = sourceOf(node, kinds)\n return source?.asset != null && source.node.attrs.mimeType === 'application/pdf'\n}\n\n/**\n * „Literaturangaben abrufen“ / „DOI abrufen“: fetches the bibliographic data of the Typed block at `pos` (`ai.extract`,\n * method `bibliography`: Crossref by the DOI — `meta.doi`, else `meta.bib.DOI` — and, without one, from the PDF source's\n * first pages by the model) and stores it as `meta.bib`, replacing the previous data. The title of the result is only\n * applied to an untitled Typed block and never stored in `meta.bib`. Both changes are one transaction (one undo step). The\n * Typed block is found again by its block ID after the request, so edits while it runs do not misplace the result.\n * `documentId` is the document whose assets the request addresses when the Typed block has no stored source (a DOI-only\n * lookup needs no file). Notices go through `notify`, in the language of `t`; the progress notice stays until the\n * request ends.\n */\nexport async function fetchBibliography(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate, documentId?: string): Promise<void> {\n const composite = editor.state.doc.nodeAt(pos)\n const id = composite && blockIdOf(composite)\n if (composite?.type.name !== 'typedBlock' || !id) return\n const definitions = capabilityConfigOf<PropertiesConfig>(editor, composite, 'properties')?.definitions ?? []\n if (!capabilitiesOf(editor, composite).has('bibliography') || running.has(id)) return\n\n const doi = doiOf(composite)\n if (doi === null) {\n notify({ title: t('integrations.bibliographyFetch.invalidDoi'), kind: 'error' })\n return\n }\n const source = sourceOf(composite, blockTypesOf(editor))\n const asset = source?.asset != null && source.node.attrs.mimeType === 'application/pdf' ? source.asset : null\n // A DOI is looked up without any file; without one the PDF source is read.\n const targetDocument = doi ? documentId ?? asset?.documentId : asset?.documentId\n if (!targetDocument) {\n notify({ title: t('integrations.bibliographyFetch.noSource'), kind: 'error' })\n return\n }\n\n running.add(id)\n const toastId = `bibliography-fetch-${id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.bibliographyFetch.running'), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n try {\n const result = await ai.extract({\n documentId: targetDocument,\n ...(doi ? { doi } : { name: asset!.name }),\n method: 'bibliography',\n model: modelRef('generate'),\n }, controller.signal)\n if (editor.isDestroyed) return\n if (!result.bib) {\n notify({ title: t('integrations.bibliographyFetch.empty'), kind: 'error' })\n return\n }\n const { title, ...item } = result.bib\n\n const bib = { ...item, ...(doi && !item.DOI ? { DOI: doi } : {}) }\n const applied = editor.commands.command(({ tr }) => {\n const found = compositeOfRow(tr.doc, { id, pos })\n if (!found) return false\n const field = definitions.find(candidate => candidate.key === BIB_KEY) ?? { key: BIB_KEY, type: 'bibliography' as const }\n tr.setNodeMarkup(found.pos, undefined, { ...found.node.attrs, meta: metaWithProperty(found.node.attrs.meta ?? {}, field, bib) })\n const heading = found.node.child(0)\n if (title?.trim() && !heading.textContent.trim()) {\n const from = found.pos + 2\n tr.replaceWith(from, from + heading.content.size, editor.schema.text(title.trim()))\n }\n return true\n })\n if (!applied) {\n notify({ title: t('integrations.bibliographyFetch.gone.title'), description: t('integrations.bibliographyFetch.gone.description'), kind: 'error' })\n return\n }\n notify({ title: t('integrations.bibliographyFetch.done'), kind: 'success', icon: 'i-lucide-book-marked' })\n // The data is applied either way; this tells where it came from.\n if (result.warnings.includes('crossref-unavailable')) {\n notify({ title: t('integrations.bibliographyFetch.crossrefUnavailable.title'), description: t('integrations.bibliographyFetch.crossrefUnavailable.description'), kind: 'info' })\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.bibliographyFetch.failed'), description: fetchErrorMessage(err), kind: 'error' })\n }\n finally {\n running.delete(id)\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n }\n}\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { Editor } from "@tiptap/core";
|
|
|
8
8
|
/**
|
|
9
9
|
* How `generateCompositeBody` ended. `done` carries the streamed Markdown (possibly empty); `data-error`: a
|
|
10
10
|
* contributor of `aiBlockData` rejected, before any request was sent (`message`); `error`: the request failed
|
|
11
|
-
* (`message`); `aborted` also covers a destroyed editor and a node that is no composite of an `ai`
|
|
11
|
+
* (`message`); `aborted` also covers a destroyed editor and a node that is no composite of a Block type with an `ai` configuration.
|
|
12
12
|
*/
|
|
13
13
|
export type CompositeBodyResult = {
|
|
14
14
|
status: 'done';
|
|
@@ -22,9 +22,9 @@ export type CompositeBodyResult = {
|
|
|
22
22
|
message: string;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
|
-
* The request half of „
|
|
26
|
-
* `aiBlockData` → task `fill-block` (`generate`
|
|
27
|
-
* the diff review with the result, `deriveComposite` writes it into a new
|
|
25
|
+
* The request half of „Block füllen (KI)“: the brief (`compositeAiBrief`) of the composite at `pos` plus the preset's
|
|
26
|
+
* `aiBlockData` → task `fill-block` (`generate` Model role), streamed to completion. Writes nothing; `fillComposite` opens
|
|
27
|
+
* the diff review with the result, `deriveComposite` writes it into a new Typed block. A contributor that rejects cancels
|
|
28
28
|
* the run before any request is sent. Never throws.
|
|
29
29
|
*/
|
|
30
30
|
export declare function generateCompositeBody(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, t: Translate, signal: AbortSignal): Promise<CompositeBodyResult>;
|
|
@@ -11,9 +11,9 @@ import { postAiSse } from "../../features/ai/ai-sse.js";
|
|
|
11
11
|
/** Entries of `aiBlockData` that travel with a request (the server accepts at most as many). */
|
|
12
12
|
const MAX_BLOCK_DATA = 10;
|
|
13
13
|
/**
|
|
14
|
-
* The request half of „
|
|
15
|
-
* `aiBlockData` → task `fill-block` (`generate`
|
|
16
|
-
* the diff review with the result, `deriveComposite` writes it into a new
|
|
14
|
+
* The request half of „Block füllen (KI)“: the brief (`compositeAiBrief`) of the composite at `pos` plus the preset's
|
|
15
|
+
* `aiBlockData` → task `fill-block` (`generate` Model role), streamed to completion. Writes nothing; `fillComposite` opens
|
|
16
|
+
* the diff review with the result, `deriveComposite` writes it into a new Typed block. A contributor that rejects cancels
|
|
17
17
|
* the run before any request is sent. Never throws.
|
|
18
18
|
*/
|
|
19
19
|
async function generateCompositeBody(editor, pos, ai, modelRef, t, signal) {
|
|
@@ -59,7 +59,7 @@ async function generateCompositeBody(editor, pos, ai, modelRef, t, signal) {
|
|
|
59
59
|
value
|
|
60
60
|
})),
|
|
61
61
|
instructions: brief.instructions,
|
|
62
|
-
|
|
62
|
+
contentTemplate: brief.contentTemplate,
|
|
63
63
|
body: brief.body,
|
|
64
64
|
data
|
|
65
65
|
};
|
|
@@ -145,7 +145,7 @@ async function fillComposite(editor, pos, ai, modelRef, notify, t) {
|
|
|
145
145
|
}
|
|
146
146
|
const range = resolveRange(editor.state, anchor);
|
|
147
147
|
const $from = range && editor.state.doc.resolve(range.from);
|
|
148
|
-
if (!range || !$from || $from.parent.type.name !== "
|
|
148
|
+
if (!range || !$from || $from.parent.type.name !== "typedBlock" || $from.index() < 3 || !$from.sameParent(editor.state.doc.resolve(range.to))) {
|
|
149
149
|
notify({
|
|
150
150
|
title: t("integrations.compositeFill.gone.title"),
|
|
151
151
|
description: t("integrations.compositeFill.gone.description"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite-fill.js","names":[],"sources":["../../../src/integrations/composite-ai/composite-fill.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { EditorBackend } from '../../core/backend'\nimport { aiApplyFailure, AI_LIMITS, type AiBlockInput, type AiSseOutcome, documentMarkdown, type ModelRef, notifyAiRateLimited, postAiSse, startAiReview } from '../../features/ai'\nimport { aiBlockDataOf, aiContextOf, captureRange, releaseRanges, resolveRange } from '../../core'\nimport type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\nimport { COMPOSITE_CHROME_COUNT, compositeAiBrief } from '../../features/composites/schema'\n\n/** Entries of `aiBlockData` that travel with a request (the server accepts at most as many). */\nconst MAX_BLOCK_DATA = 10\n\n/**\n * How `generateCompositeBody` ended. `done` carries the streamed Markdown (possibly empty); `data-error`: a\n * contributor of `aiBlockData` rejected, before any request was sent (`message`); `error`: the request failed\n * (`message`); `aborted` also covers a destroyed editor and a node that is no composite of an `ai`
|
|
1
|
+
{"version":3,"file":"composite-fill.js","names":[],"sources":["../../../src/integrations/composite-ai/composite-fill.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { EditorBackend } from '../../core/backend'\nimport { aiApplyFailure, AI_LIMITS, type AiBlockInput, type AiSseOutcome, documentMarkdown, type ModelRef, notifyAiRateLimited, postAiSse, startAiReview } from '../../features/ai'\nimport { aiBlockDataOf, aiContextOf, captureRange, releaseRanges, resolveRange } from '../../core'\nimport type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\nimport { COMPOSITE_CHROME_COUNT, compositeAiBrief } from '../../features/composites/schema'\n\n/** Entries of `aiBlockData` that travel with a request (the server accepts at most as many). */\nconst MAX_BLOCK_DATA = 10\n\n/**\n * How `generateCompositeBody` ended. `done` carries the streamed Markdown (possibly empty); `data-error`: a\n * contributor of `aiBlockData` rejected, before any request was sent (`message`); `error`: the request failed\n * (`message`); `aborted` also covers a destroyed editor and a node that is no composite of a Block type with an `ai` configuration.\n */\nexport type CompositeBodyResult =\n | { status: 'done', output: string }\n | { status: 'rate-limited' | 'aborted', output: string }\n | { status: 'data-error' | 'error', output: string, message: string }\n\n/**\n * The request half of „Block füllen (KI)“: the brief (`compositeAiBrief`) of the composite at `pos` plus the preset's\n * `aiBlockData` → task `fill-block` (`generate` Model role), streamed to completion. Writes nothing; `fillComposite` opens\n * the diff review with the result, `deriveComposite` writes it into a new Typed block. A contributor that rejects cancels\n * the run before any request is sent. Never throws.\n */\nexport async function generateCompositeBody(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, t: Translate, signal: AbortSignal): Promise<CompositeBodyResult> {\n const brief = compositeAiBrief(editor, pos)\n const node = editor.state.doc.nodeAt(pos)\n if (!brief || !node) return { status: 'aborted', output: '' }\n\n let data: AiBlockInput['data']\n try {\n const material = await aiBlockDataOf(editor)({ editor, node, pos, signal })\n data = material.slice(0, MAX_BLOCK_DATA).map(({ label, text }) => ({ label, text: text.slice(0, AI_LIMITS.block.data) }))\n }\n catch (error) {\n if (signal.aborted || editor.isDestroyed) return { status: 'aborted', output: '' }\n return { status: 'data-error', output: '', message: error instanceof Error ? error.message : String(error) }\n }\n if (signal.aborted || editor.isDestroyed) return { status: 'aborted', output: '' }\n\n const block: AiBlockInput = {\n kind: brief.kind,\n path: brief.path,\n title: brief.title,\n description: brief.description,\n fields: brief.fields.map(({ label, value }) => ({ label, value })),\n instructions: brief.instructions,\n contentTemplate: brief.contentTemplate,\n body: brief.body,\n data,\n }\n let output = ''\n const outcome: AiSseOutcome = await postAiSse(ai, 'generate', {\n task: 'fill-block',\n prompt: '',\n selection: '',\n context: documentMarkdown(editor),\n blocks: aiContextOf(editor).blocks,\n block,\n model: modelRef('generate'),\n }, { signal, t, onDelta: (text) => { output += text } })\n\n if (outcome.status === 'aborted' || editor.isDestroyed) return { status: 'aborted', output }\n if (outcome.status === 'error') return { status: 'error', output, message: outcome.message }\n return { status: outcome.status, output }\n}\n\n/**\n * Fills the body of the composite at `pos` (`generateCompositeBody`); the result opens the in-document diff review over\n * the body (`startAiReview`), so nothing is written until accepted. The body range is anchored when the run starts, so\n * edits while the data loads or the result streams do not misplace it. Title, fields and the other chrome stay\n * untouched. Notices go through `notify`, in the language of `t`.\n */\nexport async function fillComposite(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): Promise<void> {\n const brief = compositeAiBrief(editor, pos)\n const node = editor.state.doc.nodeAt(pos)\n if (!brief || !node) return\n\n const from = pos + 1 + node.child(0).nodeSize + node.child(1).nodeSize + node.child(2).nodeSize\n const anchor = captureRange(editor, { from, to: pos + node.nodeSize - 1 }, { startInside: true })\n\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n try {\n const result = await generateCompositeBody(editor, pos, ai, modelRef, t, controller.signal)\n if (result.status === 'aborted') return\n if (result.status === 'data-error') {\n notify({ title: t('integrations.compositeFill.dataMissing'), description: result.message, kind: 'error' })\n return\n }\n if (result.status === 'rate-limited') {\n notifyAiRateLimited(notify, t)\n return\n }\n if (result.status === 'error') {\n notify({ title: t('integrations.compositeFill.failed'), description: result.message, kind: 'error' })\n return\n }\n const { output } = result\n if (!output.trim()) {\n notify({ title: t('integrations.compositeFill.empty.title'), description: t('integrations.compositeFill.empty.description'), kind: 'error' })\n return\n }\n\n // The body must still be where it was: a range directly inside a composite, after its chrome.\n const range = resolveRange(editor.state, anchor)\n const $from = range && editor.state.doc.resolve(range.from)\n if (!range || !$from || $from.parent.type.name !== 'typedBlock' || $from.index() < COMPOSITE_CHROME_COUNT || !$from.sameParent(editor.state.doc.resolve(range.to))) {\n notify({ title: t('integrations.compositeFill.gone.title'), description: t('integrations.compositeFill.gone.description'), kind: 'error' })\n return\n }\n const review = startAiReview(editor, [{ id: 'fill', range: anchor, markdown: output }])\n if (review.hunks === 0) notify(aiApplyFailure(review.skipped[0]?.reason ?? 'unchanged', t))\n }\n finally {\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n"],"mappings":"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"}
|
|
@@ -6,12 +6,12 @@ import "../../features/ai/index.js";
|
|
|
6
6
|
import { Editor } from "@tiptap/core";
|
|
7
7
|
import { Node as Node$1 } from "@tiptap/pm/model";
|
|
8
8
|
//#region src/integrations/composite-ai/composite-summary.d.ts
|
|
9
|
-
/** Index of a composite's first body block, after `
|
|
9
|
+
/** Index of a composite's first body block, after `typedBlockTitle`, `typedBlockDescription` and `typedBlockTags`. */
|
|
10
10
|
export declare const COMPOSITE_BODY_START = 3;
|
|
11
11
|
/** What a summary is made from: the text of a composite's body blocks (renditions included). Empty for other nodes. */
|
|
12
12
|
export declare function compositeSourceText(composite: Node$1): string;
|
|
13
13
|
/**
|
|
14
|
-
* Streams an AI summary of the composite at `pos` (its body as Markdown, task `summarize`, `rewrite`
|
|
14
|
+
* Streams an AI summary of the composite at `pos` (its body as Markdown, task `summarize`, `rewrite` Model role) into
|
|
15
15
|
* the composite's description, replacing what it held, and shows description and tags. The description is anchored
|
|
16
16
|
* when the request starts, so edits while it streams do not misplace the result. Notices go through `notify`, in the language of `t`.
|
|
17
17
|
*/
|
|
@@ -6,10 +6,10 @@ import { notifyAiRateLimited } from "../../features/ai/rate-limit.js";
|
|
|
6
6
|
import { postAiSse } from "../../features/ai/ai-sse.js";
|
|
7
7
|
import { Fragment } from "@tiptap/pm/model";
|
|
8
8
|
//#region src/integrations/composite-ai/composite-summary.ts
|
|
9
|
-
/** Index of a composite's first body block, after `
|
|
9
|
+
/** Index of a composite's first body block, after `typedBlockTitle`, `typedBlockDescription` and `typedBlockTags`. */
|
|
10
10
|
const COMPOSITE_BODY_START = 3;
|
|
11
11
|
function compositeBody(composite) {
|
|
12
|
-
if (composite.type.name !== "
|
|
12
|
+
if (composite.type.name !== "typedBlock") return [];
|
|
13
13
|
const body = [];
|
|
14
14
|
composite.forEach((child, _offset, index) => {
|
|
15
15
|
if (index >= COMPOSITE_BODY_START) body.push(child);
|
|
@@ -37,13 +37,13 @@ function firstInlineContent(editor, parsed) {
|
|
|
37
37
|
return inline;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Streams an AI summary of the composite at `pos` (its body as Markdown, task `summarize`, `rewrite`
|
|
40
|
+
* Streams an AI summary of the composite at `pos` (its body as Markdown, task `summarize`, `rewrite` Model role) into
|
|
41
41
|
* the composite's description, replacing what it held, and shows description and tags. The description is anchored
|
|
42
42
|
* when the request starts, so edits while it streams do not misplace the result. Notices go through `notify`, in the language of `t`.
|
|
43
43
|
*/
|
|
44
44
|
async function summarizeComposite(editor, pos, ai, modelRef, notify, t) {
|
|
45
45
|
const composite = editor.state.doc.nodeAt(pos);
|
|
46
|
-
if (composite?.type.name !== "
|
|
46
|
+
if (composite?.type.name !== "typedBlock" || composite.childCount <= COMPOSITE_BODY_START) return;
|
|
47
47
|
const title = composite.child(0);
|
|
48
48
|
const description = composite.child(1);
|
|
49
49
|
const body = compositeBody(composite).map((child) => child.toJSON());
|
|
@@ -98,7 +98,7 @@ async function summarizeComposite(editor, pos, ai, modelRef, notify, t) {
|
|
|
98
98
|
}
|
|
99
99
|
const range = resolveRange(editor.state, anchor);
|
|
100
100
|
const $from = range && editor.state.doc.resolve(range.from);
|
|
101
|
-
if (!range || !$from || $from.parent.type.name !== "
|
|
101
|
+
if (!range || !$from || $from.parent.type.name !== "typedBlockDescription" || !$from.sameParent(editor.state.doc.resolve(range.to))) {
|
|
102
102
|
notify({
|
|
103
103
|
title: t("integrations.compositeSummary.gone.title"),
|
|
104
104
|
description: t("integrations.compositeSummary.gone.description"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite-summary.js","names":[],"sources":["../../../src/integrations/composite-ai/composite-summary.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 { AI_LIMITS, type ModelRef, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { COMPOSITE_CHROME_COUNT } from '../../features/composites/schema'\nimport { captureRange, parseBlocks, releaseRanges, resolveRange } from '../../core'\nimport type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\n\n/** Index of a composite's first body block, after `
|
|
1
|
+
{"version":3,"file":"composite-summary.js","names":[],"sources":["../../../src/integrations/composite-ai/composite-summary.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 { AI_LIMITS, type ModelRef, notifyAiRateLimited, postAiSse } from '../../features/ai'\nimport { COMPOSITE_CHROME_COUNT } from '../../features/composites/schema'\nimport { captureRange, parseBlocks, releaseRanges, resolveRange } from '../../core'\nimport type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\n\n/** Index of a composite's first body block, after `typedBlockTitle`, `typedBlockDescription` and `typedBlockTags`. */\nexport const COMPOSITE_BODY_START = COMPOSITE_CHROME_COUNT\n\nfunction compositeBody(composite: PMNode): PMNode[] {\n if (composite.type.name !== 'typedBlock') return []\n const body: PMNode[] = []\n composite.forEach((child, _offset, index) => {\n if (index >= COMPOSITE_BODY_START) body.push(child)\n })\n return body\n}\n\n/** What a summary is made from: the text of a composite's body blocks (renditions included). Empty for other nodes. */\nexport function compositeSourceText(composite: PMNode): string {\n return compositeBody(composite).map(child => child.textContent).join('\\n')\n}\n\n/** Inline content of the first textblock of a parsed AI result. */\nfunction firstInlineContent(editor: Editor, parsed: JSONContent): Fragment | null {\n let doc: PMNode\n try {\n doc = editor.schema.nodeFromJSON(parsed)\n }\n catch {\n return null\n }\n let inline: Fragment | null = null\n doc.descendants((node) => {\n if (inline) return false\n if (node.isTextblock && node.content.size) inline = node.content\n return !inline\n })\n return inline\n}\n\n/**\n * Streams an AI summary of the composite at `pos` (its body as Markdown, task `summarize`, `rewrite` Model role) into\n * the composite's description, replacing what it held, and shows description and tags. The description is anchored\n * when the request starts, so edits while it streams do not misplace the result. Notices go through `notify`, in the language of `t`.\n */\nexport async function summarizeComposite(editor: Editor, pos: number, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'rewrite') => ModelRef, notify: Notifier, t: Translate): Promise<void> {\n const composite = editor.state.doc.nodeAt(pos)\n if (composite?.type.name !== 'typedBlock' || composite.childCount <= COMPOSITE_BODY_START) return\n const title = composite.child(0)\n const description = composite.child(1)\n const body = compositeBody(composite).map(child => child.toJSON() as JSONContent)\n const bodyMarkdown = compositeSourceText(composite).trim()\n ? editor.markdown!.serialize({ type: 'doc', content: body })\n : ''\n const descriptionPos = pos + 1 + title.nodeSize\n const anchor = captureRange(editor, { from: descriptionPos + 1, to: descriptionPos + 1 + description.content.size })\n const model = modelRef('rewrite')\n\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n let output = ''\n try {\n const outcome = await postAiSse(ai, 'generate', {\n task: 'summarize',\n prompt: '',\n selection: bodyMarkdown.slice(0, AI_LIMITS.selection),\n context: '',\n model,\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.compositeSummary.failed'), description: outcome.message, kind: 'error' })\n return\n }\n if (!output.trim()) {\n notify({ title: t('integrations.compositeSummary.empty.title'), description: t('integrations.compositeSummary.empty.description'), kind: 'error' })\n return\n }\n\n const range = resolveRange(editor.state, anchor)\n const $from = range && editor.state.doc.resolve(range.from)\n if (!range || !$from || $from.parent.type.name !== 'typedBlockDescription' || !$from.sameParent(editor.state.doc.resolve(range.to))) {\n notify({ title: t('integrations.compositeSummary.gone.title'), description: t('integrations.compositeSummary.gone.description'), kind: 'error' })\n return\n }\n const inline = firstInlineContent(editor, parseBlocks(editor, output).parsed) ?? Fragment.from(editor.schema.text(output.trim()))\n editor.view.dispatch(editor.state.tr.replaceWith(range.from, range.to, inline))\n notify({ title: t('integrations.compositeSummary.done'), kind: 'success', icon: 'i-lucide-text-quote' })\n }\n finally {\n editor.off('destroy', abort)\n releaseRanges(editor, [anchor])\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,30 +2,30 @@ import { Translate } from "../../i18n/index.js";
|
|
|
2
2
|
import { EditorBackend } from "../../core/backend.js";
|
|
3
3
|
import { Notifier } from "../../core/notify.js";
|
|
4
4
|
import { ModelRef } from "../../core/backend-types.js";
|
|
5
|
+
import { BlockType } from "../../features/composites/block-types.js";
|
|
6
|
+
import { Derivation } from "../../core/derivation.js";
|
|
7
|
+
import "../../core/index.js";
|
|
5
8
|
import "../../features/ai/index.js";
|
|
6
|
-
import { CompositeKind } from "../../features/composites/kinds.js";
|
|
7
|
-
import { Derivation } from "../../features/composites/derivation.js";
|
|
8
|
-
import "../../features/composites/schema.js";
|
|
9
9
|
import "../../features/composites/index.js";
|
|
10
10
|
import { Editor } from "@tiptap/core";
|
|
11
11
|
import { Node as Node$1 } from "@tiptap/pm/model";
|
|
12
12
|
//#region src/integrations/composite-ai/derive.d.ts
|
|
13
|
-
/**
|
|
14
|
-
export declare const
|
|
15
|
-
/** Whether the
|
|
13
|
+
/** Block types a Typed block can be derived into: the ones with the `ai-brief` capability (their brief drives the generation). */
|
|
14
|
+
export declare const derivableBlockTypesOf: (editor: Editor) => BlockType[];
|
|
15
|
+
/** Whether the Typed block `node` can be the source of a derivation: a container block with a block id (the derivation points at it by id). */
|
|
16
16
|
export declare const isDerivableSource: (editor: Editor, node: Node$1) => boolean;
|
|
17
|
-
/** Whether a
|
|
17
|
+
/** Whether a Typed block of `kindId` may be inserted right after the Typed block at `pos` (the same guards as creating it there). */
|
|
18
18
|
export declare function canDeriveAfter(editor: Editor, pos: number, kindId: string): boolean;
|
|
19
|
-
/** Drops the derived
|
|
19
|
+
/** Drops the derived Typed block `id` again, unless its body got content meanwhile (the user may have started writing in it). */
|
|
20
20
|
export declare function discardDerived(editor: Editor, id: string): void;
|
|
21
21
|
/**
|
|
22
22
|
* The write-back half of every derivation: parses the streamed `markdown` through the block pipeline and replaces the
|
|
23
|
-
* body of the (still empty) derived
|
|
24
|
-
* body as `outputHash` (kept next to the `derivation` the
|
|
23
|
+
* body of the (still empty) derived Typed block `id` with it, in one transaction together with the hash of exactly that
|
|
24
|
+
* body as `outputHash` (kept next to the `derivation` the Typed block already carries, else `options.derivation`; a Typed block
|
|
25
25
|
* with neither only gets its body), so one
|
|
26
|
-
* undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a
|
|
27
|
-
* that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the
|
|
28
|
-
* `options.done` shown as success notice. The
|
|
26
|
+
* undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a Typed block
|
|
27
|
+
* that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the Typed block is revealed and
|
|
28
|
+
* `options.done` shown as success notice. The Typed block is found again by its block id, so edits while the model ran do
|
|
29
29
|
* not misplace the result. Returns whether the body was written.
|
|
30
30
|
*/
|
|
31
31
|
export declare function writeDerivedBody(editor: Editor, id: string, markdown: string, options: {
|
|
@@ -36,14 +36,14 @@ export declare function writeDerivedBody(editor: Editor, id: string, markdown: s
|
|
|
36
36
|
done: string;
|
|
37
37
|
}): boolean;
|
|
38
38
|
/**
|
|
39
|
-
* „Ableiten (KI) → <Art>“: inserts a sibling
|
|
39
|
+
* „Ableiten (KI) → <Art>“: inserts a sibling Typed block of Block type `kindId` right after the Typed block at `pos`, titled
|
|
40
40
|
* „<Art>: <Quelle>“, whose `meta.derivation` points back at the source block (`from.block`, method `ai:<kindId>`, the
|
|
41
41
|
* Markdown hash of the source's body as `inputHash`), generates its body from the source (`generateCompositeBody`; the
|
|
42
42
|
* `aiBlockData` of composites hands the model the source's Markdown) and writes the result directly into the new
|
|
43
|
-
*
|
|
44
|
-
* edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new
|
|
43
|
+
* Typed block — no review, the new Typed block is the proposal. The hash of the written body becomes `outputHash`, so a later
|
|
44
|
+
* edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new Typed block is found again by its
|
|
45
45
|
* block id after every await, so edits while the model runs do not misplace the result. When the run fails or yields
|
|
46
|
-
* nothing the still-empty
|
|
46
|
+
* nothing the still-empty Typed block is removed again. Notices go through `notify`, in the language of `t`.
|
|
47
47
|
*/
|
|
48
48
|
export declare function deriveComposite(editor: Editor, pos: number, kindId: string, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): Promise<void>;
|
|
49
49
|
//#endregion
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
+
import { blockIdOf, findBlockById, newBlockId } from "../../core/schema/block-ids.js";
|
|
2
|
+
import { capabilitiesOf } from "../../core/capabilities.js";
|
|
1
3
|
import { parseBlocks } from "../../core/pipeline.js";
|
|
2
4
|
import { guardsAccept } from "../../core/commands.js";
|
|
3
|
-
import {
|
|
5
|
+
import { DERIVATION_KEY, derivationOf } from "../../core/derivation.js";
|
|
4
6
|
import { sha256Hex } from "../../core/hash.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { bodyMarkdown
|
|
8
|
-
import { compositeJSON, compositeKindsOf } from "../../features/composites/nodes.js";
|
|
7
|
+
import { aiBriefOf, blockTypeOf } from "../../features/composites/block-types.js";
|
|
8
|
+
import { blockTypesOf, compositeJSON } from "../../features/composites/nodes.js";
|
|
9
|
+
import { bodyMarkdown } from "../../features/composites/source.js";
|
|
9
10
|
import { notifyAiRateLimited } from "../../features/ai/rate-limit.js";
|
|
10
11
|
import { generateCompositeBody } from "./composite-fill.js";
|
|
11
12
|
import { Fragment } from "@tiptap/pm/model";
|
|
12
13
|
//#region src/integrations/composite-ai/derive.ts
|
|
13
|
-
/**
|
|
14
|
-
const
|
|
15
|
-
/** Whether the
|
|
16
|
-
const isDerivableSource = (editor, node) => node.
|
|
17
|
-
/** Whether a
|
|
14
|
+
/** Block types a Typed block can be derived into: the ones with the `ai-brief` capability (their brief drives the generation). */
|
|
15
|
+
const derivableBlockTypesOf = (editor) => blockTypesOf(editor).filter((blockType) => aiBriefOf(blockType) !== void 0);
|
|
16
|
+
/** Whether the Typed block `node` can be the source of a derivation: a container block with a block id (the derivation points at it by id). */
|
|
17
|
+
const isDerivableSource = (editor, node) => capabilitiesOf(editor, node).has("container") && blockIdOf(node) !== null && derivableBlockTypesOf(editor).length > 0;
|
|
18
|
+
/** Whether a Typed block of `kindId` may be inserted right after the Typed block at `pos` (the same guards as creating it there). */
|
|
18
19
|
function canDeriveAfter(editor, pos, kindId) {
|
|
19
20
|
const source = editor.state.doc.nodeAt(pos);
|
|
20
21
|
if (!source) return false;
|
|
21
22
|
const $at = editor.state.doc.resolve(pos + source.nodeSize);
|
|
22
23
|
return guardsAccept(editor, $at, {
|
|
23
|
-
type: "
|
|
24
|
-
attrs: {
|
|
24
|
+
type: "typedBlock",
|
|
25
|
+
attrs: { blockType: kindId }
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
|
-
/** Drops the derived
|
|
28
|
+
/** Drops the derived Typed block `id` again, unless its body got content meanwhile (the user may have started writing in it). */
|
|
28
29
|
function discardDerived(editor, id) {
|
|
29
30
|
const found = editor.isDestroyed ? null : findBlockById(editor.state.doc, id);
|
|
30
31
|
if (!found) return;
|
|
@@ -33,12 +34,12 @@ function discardDerived(editor, id) {
|
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* The write-back half of every derivation: parses the streamed `markdown` through the block pipeline and replaces the
|
|
36
|
-
* body of the (still empty) derived
|
|
37
|
-
* body as `outputHash` (kept next to the `derivation` the
|
|
37
|
+
* body of the (still empty) derived Typed block `id` with it, in one transaction together with the hash of exactly that
|
|
38
|
+
* body as `outputHash` (kept next to the `derivation` the Typed block already carries, else `options.derivation`; a Typed block
|
|
38
39
|
* with neither only gets its body), so one
|
|
39
|
-
* undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a
|
|
40
|
-
* that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the
|
|
41
|
-
* `options.done` shown as success notice. The
|
|
40
|
+
* undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a Typed block
|
|
41
|
+
* that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the Typed block is revealed and
|
|
42
|
+
* `options.done` shown as success notice. The Typed block is found again by its block id, so edits while the model ran do
|
|
42
43
|
* not misplace the result. Returns whether the body was written.
|
|
43
44
|
*/
|
|
44
45
|
function writeDerivedBody(editor, id, markdown, options) {
|
|
@@ -86,20 +87,20 @@ function writeDerivedBody(editor, id, markdown, options) {
|
|
|
86
87
|
return true;
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
89
|
-
* „Ableiten (KI) → <Art>“: inserts a sibling
|
|
90
|
+
* „Ableiten (KI) → <Art>“: inserts a sibling Typed block of Block type `kindId` right after the Typed block at `pos`, titled
|
|
90
91
|
* „<Art>: <Quelle>“, whose `meta.derivation` points back at the source block (`from.block`, method `ai:<kindId>`, the
|
|
91
92
|
* Markdown hash of the source's body as `inputHash`), generates its body from the source (`generateCompositeBody`; the
|
|
92
93
|
* `aiBlockData` of composites hands the model the source's Markdown) and writes the result directly into the new
|
|
93
|
-
*
|
|
94
|
-
* edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new
|
|
94
|
+
* Typed block — no review, the new Typed block is the proposal. The hash of the written body becomes `outputHash`, so a later
|
|
95
|
+
* edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new Typed block is found again by its
|
|
95
96
|
* block id after every await, so edits while the model runs do not misplace the result. When the run fails or yields
|
|
96
|
-
* nothing the still-empty
|
|
97
|
+
* nothing the still-empty Typed block is removed again. Notices go through `notify`, in the language of `t`.
|
|
97
98
|
*/
|
|
98
99
|
async function deriveComposite(editor, pos, kindId, ai, modelRef, notify, t) {
|
|
99
100
|
const source = editor.state.doc.nodeAt(pos);
|
|
100
101
|
const sourceId = source && blockIdOf(source);
|
|
101
|
-
const kind =
|
|
102
|
-
if (source?.type.name !== "
|
|
102
|
+
const kind = blockTypesOf(editor).find((candidate) => candidate.id === kindId);
|
|
103
|
+
if (source?.type.name !== "typedBlock" || !sourceId || !kind || !aiBriefOf(kind)) return;
|
|
103
104
|
if (!canDeriveAfter(editor, pos, kindId)) {
|
|
104
105
|
notify({
|
|
105
106
|
title: t("integrations.compositeDerive.notAccepted"),
|
|
@@ -107,7 +108,7 @@ async function deriveComposite(editor, pos, kindId, ai, modelRef, notify, t) {
|
|
|
107
108
|
});
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
110
|
-
const sourceKind =
|
|
111
|
+
const sourceKind = blockTypeOf(blockTypesOf(editor), String(source.attrs.blockType));
|
|
111
112
|
const derivation = {
|
|
112
113
|
from: { block: sourceId },
|
|
113
114
|
method: `ai:${kindId}`,
|
|
@@ -190,6 +191,6 @@ async function deriveComposite(editor, pos, kindId, ai, modelRef, notify, t) {
|
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
//#endregion
|
|
193
|
-
export { canDeriveAfter,
|
|
194
|
+
export { canDeriveAfter, derivableBlockTypesOf, deriveComposite, discardDerived, isDerivableSource, writeDerivedBody };
|
|
194
195
|
|
|
195
196
|
//# sourceMappingURL=derive.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive.js","names":[],"sources":["../../../src/integrations/composite-ai/derive.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 { guardsAccept, parseBlocks, sha256Hex } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf, findBlockById, newBlockId } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport { bodyMarkdown, COMPOSITE_CHROME_COUNT, compositeJSON, compositeKind, compositeKindsOf, DERIVATION_KEY, type Derivation, derivationOf } from '../../features/composites/schema'\nimport { generateCompositeBody } from './composite-fill'\n\n/** Kinds a Baustein can be derived into: the ones with an `ai` configuration (their brief drives the generation). */\nexport const derivableKindsOf = (editor: Editor) => compositeKindsOf(editor).filter(kind => kind.ai !== undefined)\n\n/** Whether the Baustein `node` can be the source of a derivation: a composite with a block id (the derivation points at it by id). */\nexport const isDerivableSource = (editor: Editor, node: PMNode) => node.type.name === 'composite' && blockIdOf(node) !== null && derivableKindsOf(editor).length > 0\n\n/** Whether a Baustein of `kindId` may be inserted right after the Baustein at `pos` (the same guards as creating it there). */\nexport function canDeriveAfter(editor: Editor, pos: number, kindId: string): boolean {\n const source = editor.state.doc.nodeAt(pos)\n if (!source) return false\n const $at = editor.state.doc.resolve(pos + source.nodeSize)\n return guardsAccept(editor, $at, { type: 'composite', attrs: { kind: kindId } })\n}\n\n/** Drops the derived Baustein `id` again, unless its body got content meanwhile (the user may have started writing in it). */\nexport function discardDerived(editor: Editor, id: string): void {\n const found = editor.isDestroyed ? null : findBlockById(editor.state.doc, id)\n if (!found) return\n const body = Array.from({ length: found.node.childCount - COMPOSITE_CHROME_COUNT }, (_, index) => found.node.child(COMPOSITE_CHROME_COUNT + index))\n if (body.some(child => child.textContent.trim() || child.type.name !== 'paragraph')) return\n editor.view.dispatch(editor.state.tr.delete(found.pos, found.pos + found.node.nodeSize))\n}\n\n/**\n * The write-back half of every derivation: parses the streamed `markdown` through the block pipeline and replaces the\n * body of the (still empty) derived Baustein `id` with it, in one transaction together with the hash of exactly that\n * body as `outputHash` (kept next to the `derivation` the Baustein already carries, else `options.derivation`; a Baustein\n * with neither only gets its body), so one\n * undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a Baustein\n * that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the Baustein is revealed and\n * `options.done` shown as success notice. The Baustein is found again by its block id, so edits while the model ran do\n * not misplace the result. Returns whether the body was written.\n */\nexport function writeDerivedBody(editor: Editor, id: string, markdown: string, options: { derivation?: Derivation, discard: () => void, notify: Notifier, t: Translate, done: string }): boolean {\n const { derivation, discard, notify, t, done } = options\n const blocks = markdown.trim() ? parseBlocks(editor, markdown).blocks.map(block => editor.schema.nodeFromJSON(block)) : []\n if (!blocks.length) {\n discard()\n notify({ title: t('integrations.compositeDerive.empty.title'), description: t('integrations.compositeDerive.empty.description'), kind: 'error' })\n return false\n }\n const found = findBlockById(editor.state.doc, id)\n if (!found || !found.node.canReplace(COMPOSITE_CHROME_COUNT, found.node.childCount, Fragment.from(blocks))) {\n notify({ title: t('integrations.compositeDerive.gone.title'), description: t('integrations.compositeDerive.gone.description'), kind: 'error' })\n return false\n }\n\n // One transaction: body and the hash of exactly that body, so one undo step removes both.\n const chromeSize = Array.from({ length: COMPOSITE_CHROME_COUNT }, (_, index) => found.node.child(index).nodeSize).reduce((sum, size) => sum + size, 0)\n const tr = editor.state.tr.replaceWith(found.pos + 1 + chromeSize, found.pos + found.node.nodeSize - 1, blocks)\n const written = findBlockById(tr.doc, id)!\n const stored = derivationOf(written.node) ?? derivation\n if (stored) {\n tr.setNodeMarkup(written.pos, undefined, {\n ...written.node.attrs,\n meta: { ...written.node.attrs.meta, [DERIVATION_KEY]: { ...stored, outputHash: sha256Hex(bodyMarkdown(editor, written.node)) } },\n })\n }\n editor.view.dispatch(tr)\n editor.commands.revealBlock(id)\n notify({ title: done, kind: 'success', icon: 'i-lucide-git-branch' })\n return true\n}\n\n/**\n * „Ableiten (KI) → <Art>“: inserts a sibling Baustein of kind `kindId` right after the Baustein at `pos`, titled\n * „<Art>: <Quelle>“, whose `meta.derivation` points back at the source block (`from.block`, method `ai:<kindId>`, the\n * Markdown hash of the source's body as `inputHash`), generates its body from the source (`generateCompositeBody`; the\n * `aiBlockData` of composites hands the model the source's Markdown) and writes the result directly into the new\n * Baustein — no review, the new Baustein is the proposal. The hash of the written body becomes `outputHash`, so a later\n * edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new Baustein is found again by its\n * block id after every await, so edits while the model runs do not misplace the result. When the run fails or yields\n * nothing the still-empty Baustein is removed again. Notices go through `notify`, in the language of `t`.\n */\nexport async function deriveComposite(editor: Editor, pos: number, kindId: string, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): Promise<void> {\n const source = editor.state.doc.nodeAt(pos)\n const sourceId = source && blockIdOf(source)\n const kind = compositeKindsOf(editor).find(candidate => candidate.id === kindId)\n if (source?.type.name !== 'composite' || !sourceId || !kind?.ai) return\n if (!canDeriveAfter(editor, pos, kindId)) {\n notify({ title: t('integrations.compositeDerive.notAccepted'), kind: 'error' })\n return\n }\n\n const sourceKind = compositeKind(compositeKindsOf(editor), String(source.attrs.kind))\n const derivation: Derivation = {\n from: { block: sourceId },\n method: `ai:${kindId}`,\n createdAt: new Date().toISOString(),\n inputHash: sha256Hex(bodyMarkdown(editor, source)),\n outputHash: '',\n }\n const id = newBlockId()\n const json = compositeJSON(kindId)\n const [title, ...rest] = json.content as JSONContent[]\n const text = `${kind.label}: ${source.child(0).textContent.trim() || sourceKind.label}`\n const created: JSONContent = {\n ...json,\n attrs: { ...json.attrs, id, meta: { [DERIVATION_KEY]: derivation } },\n content: [{ ...title!, content: [{ type: 'text', text }] }, ...rest],\n }\n editor.view.dispatch(editor.state.tr.insert(pos + source.nodeSize, editor.schema.nodeFromJSON(created)))\n\n const toastId = `derive-${id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.compositeDerive.running', { kind: kind.label }), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n\n const discard = () => discardDerived(editor, id)\n\n try {\n const target = findBlockById(editor.state.doc, id)\n const result = target ? await generateCompositeBody(editor, target.pos, ai, modelRef, t, controller.signal) : null\n if (!result || result.status === 'aborted' || editor.isDestroyed) {\n if (!editor.isDestroyed) discard()\n return\n }\n if (result.status === 'rate-limited') {\n discard()\n notifyAiRateLimited(notify, t)\n return\n }\n if (result.status === 'data-error') {\n discard()\n notify({ title: t('integrations.compositeFill.dataMissing'), description: result.message, kind: 'error' })\n return\n }\n if (result.status === 'error') {\n discard()\n notify({ title: t('integrations.compositeDerive.failed'), description: result.message, kind: 'error' })\n return\n }\n\n writeDerivedBody(editor, id, result.output, { derivation, discard, notify, t, done: t('integrations.compositeDerive.done', { kind: kind.label }) })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"derive.js","names":[],"sources":["../../../src/integrations/composite-ai/derive.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 { capabilitiesOf, DERIVATION_KEY, type Derivation, derivationOf, guardsAccept, parseBlocks, sha256Hex } from '../../core'\nimport type { Notifier } from '../../core/notify'\nimport { blockIdOf, findBlockById, newBlockId } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { type ModelRef, notifyAiRateLimited } from '../../features/ai'\nimport { aiBriefOf, blockTypeOf, blockTypesOf, bodyMarkdown, COMPOSITE_CHROME_COUNT, compositeJSON } from '../../features/composites/schema'\nimport { generateCompositeBody } from './composite-fill'\n\n/** Block types a Typed block can be derived into: the ones with the `ai-brief` capability (their brief drives the generation). */\nexport const derivableBlockTypesOf = (editor: Editor) => blockTypesOf(editor).filter(blockType => aiBriefOf(blockType) !== undefined)\n\n/** Whether the Typed block `node` can be the source of a derivation: a container block with a block id (the derivation points at it by id). */\nexport const isDerivableSource = (editor: Editor, node: PMNode) => capabilitiesOf(editor, node).has('container') && blockIdOf(node) !== null && derivableBlockTypesOf(editor).length > 0\n\n/** Whether a Typed block of `kindId` may be inserted right after the Typed block at `pos` (the same guards as creating it there). */\nexport function canDeriveAfter(editor: Editor, pos: number, kindId: string): boolean {\n const source = editor.state.doc.nodeAt(pos)\n if (!source) return false\n const $at = editor.state.doc.resolve(pos + source.nodeSize)\n return guardsAccept(editor, $at, { type: 'typedBlock', attrs: { blockType: kindId } })\n}\n\n/** Drops the derived Typed block `id` again, unless its body got content meanwhile (the user may have started writing in it). */\nexport function discardDerived(editor: Editor, id: string): void {\n const found = editor.isDestroyed ? null : findBlockById(editor.state.doc, id)\n if (!found) return\n const body = Array.from({ length: found.node.childCount - COMPOSITE_CHROME_COUNT }, (_, index) => found.node.child(COMPOSITE_CHROME_COUNT + index))\n if (body.some(child => child.textContent.trim() || child.type.name !== 'paragraph')) return\n editor.view.dispatch(editor.state.tr.delete(found.pos, found.pos + found.node.nodeSize))\n}\n\n/**\n * The write-back half of every derivation: parses the streamed `markdown` through the block pipeline and replaces the\n * body of the (still empty) derived Typed block `id` with it, in one transaction together with the hash of exactly that\n * body as `outputHash` (kept next to the `derivation` the Typed block already carries, else `options.derivation`; a Typed block\n * with neither only gets its body), so one\n * undo step removes both. An empty result calls `options.discard` and shows the „Leeres Ergebnis“ notice; a Typed block\n * that vanished or no longer takes the body shows „nicht mehr gefunden“; on success the Typed block is revealed and\n * `options.done` shown as success notice. The Typed block is found again by its block id, so edits while the model ran do\n * not misplace the result. Returns whether the body was written.\n */\nexport function writeDerivedBody(editor: Editor, id: string, markdown: string, options: { derivation?: Derivation, discard: () => void, notify: Notifier, t: Translate, done: string }): boolean {\n const { derivation, discard, notify, t, done } = options\n const blocks = markdown.trim() ? parseBlocks(editor, markdown).blocks.map(block => editor.schema.nodeFromJSON(block)) : []\n if (!blocks.length) {\n discard()\n notify({ title: t('integrations.compositeDerive.empty.title'), description: t('integrations.compositeDerive.empty.description'), kind: 'error' })\n return false\n }\n const found = findBlockById(editor.state.doc, id)\n if (!found || !found.node.canReplace(COMPOSITE_CHROME_COUNT, found.node.childCount, Fragment.from(blocks))) {\n notify({ title: t('integrations.compositeDerive.gone.title'), description: t('integrations.compositeDerive.gone.description'), kind: 'error' })\n return false\n }\n\n // One transaction: body and the hash of exactly that body, so one undo step removes both.\n const chromeSize = Array.from({ length: COMPOSITE_CHROME_COUNT }, (_, index) => found.node.child(index).nodeSize).reduce((sum, size) => sum + size, 0)\n const tr = editor.state.tr.replaceWith(found.pos + 1 + chromeSize, found.pos + found.node.nodeSize - 1, blocks)\n const written = findBlockById(tr.doc, id)!\n const stored = derivationOf(written.node) ?? derivation\n if (stored) {\n tr.setNodeMarkup(written.pos, undefined, {\n ...written.node.attrs,\n meta: { ...written.node.attrs.meta, [DERIVATION_KEY]: { ...stored, outputHash: sha256Hex(bodyMarkdown(editor, written.node)) } },\n })\n }\n editor.view.dispatch(tr)\n editor.commands.revealBlock(id)\n notify({ title: done, kind: 'success', icon: 'i-lucide-git-branch' })\n return true\n}\n\n/**\n * „Ableiten (KI) → <Art>“: inserts a sibling Typed block of Block type `kindId` right after the Typed block at `pos`, titled\n * „<Art>: <Quelle>“, whose `meta.derivation` points back at the source block (`from.block`, method `ai:<kindId>`, the\n * Markdown hash of the source's body as `inputHash`), generates its body from the source (`generateCompositeBody`; the\n * `aiBlockData` of composites hands the model the source's Markdown) and writes the result directly into the new\n * Typed block — no review, the new Typed block is the proposal. The hash of the written body becomes `outputHash`, so a later\n * edit shows as „bearbeitet“ and a later edit of the source as „Quelle geändert“. The new Typed block is found again by its\n * block id after every await, so edits while the model runs do not misplace the result. When the run fails or yields\n * nothing the still-empty Typed block is removed again. Notices go through `notify`, in the language of `t`.\n */\nexport async function deriveComposite(editor: Editor, pos: number, kindId: string, ai: NonNullable<EditorBackend['ai']>, modelRef: (slot: 'generate') => ModelRef, notify: Notifier, t: Translate): Promise<void> {\n const source = editor.state.doc.nodeAt(pos)\n const sourceId = source && blockIdOf(source)\n const kind = blockTypesOf(editor).find(candidate => candidate.id === kindId)\n if (source?.type.name !== 'typedBlock' || !sourceId || !kind || !aiBriefOf(kind)) return\n if (!canDeriveAfter(editor, pos, kindId)) {\n notify({ title: t('integrations.compositeDerive.notAccepted'), kind: 'error' })\n return\n }\n\n const sourceKind = blockTypeOf(blockTypesOf(editor), String(source.attrs.blockType))\n const derivation: Derivation = {\n from: { block: sourceId },\n method: `ai:${kindId}`,\n createdAt: new Date().toISOString(),\n inputHash: sha256Hex(bodyMarkdown(editor, source)),\n outputHash: '',\n }\n const id = newBlockId()\n const json = compositeJSON(kindId)\n const [title, ...rest] = json.content as JSONContent[]\n const text = `${kind.label}: ${source.child(0).textContent.trim() || sourceKind.label}`\n const created: JSONContent = {\n ...json,\n attrs: { ...json.attrs, id, meta: { [DERIVATION_KEY]: derivation } },\n content: [{ ...title!, content: [{ type: 'text', text }] }, ...rest],\n }\n editor.view.dispatch(editor.state.tr.insert(pos + source.nodeSize, editor.schema.nodeFromJSON(created)))\n\n const toastId = `derive-${id}`\n const controller = new AbortController()\n const abort = () => controller.abort()\n editor.on('destroy', abort)\n notify({ id: toastId, title: t('integrations.compositeDerive.running', { kind: kind.label }), kind: 'info', icon: 'i-lucide-loader-circle', duration: 0 })\n\n const discard = () => discardDerived(editor, id)\n\n try {\n const target = findBlockById(editor.state.doc, id)\n const result = target ? await generateCompositeBody(editor, target.pos, ai, modelRef, t, controller.signal) : null\n if (!result || result.status === 'aborted' || editor.isDestroyed) {\n if (!editor.isDestroyed) discard()\n return\n }\n if (result.status === 'rate-limited') {\n discard()\n notifyAiRateLimited(notify, t)\n return\n }\n if (result.status === 'data-error') {\n discard()\n notify({ title: t('integrations.compositeFill.dataMissing'), description: result.message, kind: 'error' })\n return\n }\n if (result.status === 'error') {\n discard()\n notify({ title: t('integrations.compositeDerive.failed'), description: result.message, kind: 'error' })\n return\n }\n\n writeDerivedBody(editor, id, result.output, { derivation, discard, notify, t, done: t('integrations.compositeDerive.done', { kind: kind.label }) })\n }\n finally {\n notify.dismiss?.(toastId)\n editor.off('destroy', abort)\n }\n}\n"],"mappings":"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"}
|