@agent-native/core 0.92.10 → 0.92.12
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +29 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +214 -17
- package/corpus/core/src/agent/run-manager.ts +72 -14
- package/corpus/core/src/agent/run-store.ts +152 -27
- package/corpus/core/src/cli/design-connect.ts +433 -151
- package/corpus/core/src/cli/skills.ts +14 -0
- package/corpus/core/src/client/AssistantChat.tsx +25 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
- package/corpus/core/src/client/agent-chat-adapter.ts +56 -12
- package/corpus/core/src/client/agent-chat.ts +165 -1
- package/corpus/core/src/client/chat/index.ts +9 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
- package/corpus/core/src/collab/awareness-store.ts +23 -12
- package/corpus/core/src/collab/client.ts +16 -5
- package/corpus/core/src/collab/index.ts +4 -0
- package/corpus/core/src/collab/recent-edits.ts +65 -2
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
- package/corpus/core/src/server/builder-design-systems.ts +30 -4
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/create-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
- package/corpus/templates/clips/actions/request-transcript.ts +102 -33
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +75 -9
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
- package/corpus/templates/clips/app/routes/record.tsx +17 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +12 -2
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +6 -3
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
- package/corpus/templates/clips/shared/recording-core.ts +12 -0
- package/corpus/templates/content/AGENTS.md +7 -6
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +82 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +149 -30
- package/corpus/templates/content/actions/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +4 -7
- package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
- package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/pull-document.ts +5 -7
- package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
- package/corpus/templates/content/actions/push-notion-page.ts +10 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
- package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
- package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/content/app/i18n-data.ts +18 -0
- package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
- package/corpus/templates/content/shared/api.ts +1 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
- package/corpus/templates/design/AGENTS.md +45 -10
- package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
- package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
- package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
- package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
- package/corpus/templates/design/actions/generate-design.ts +79 -12
- package/corpus/templates/design/actions/generate-screens.ts +57 -12
- package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
- package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
- package/corpus/templates/design/actions/import-design-source.ts +4 -31
- package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
- package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/design/actions/list-design-components.ts +104 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
- package/corpus/templates/design/actions/open-component-source.ts +2 -4
- package/corpus/templates/design/actions/present-design-variants.ts +412 -16
- package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
- package/corpus/templates/design/actions/run-design-audit.ts +25 -3
- package/corpus/templates/design/actions/show-design-questions.ts +10 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
- package/corpus/templates/design/actions/write-local-file.ts +25 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
- package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
- package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
- package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
- package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
- package/corpus/templates/design/app/components/design/types.ts +33 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
- package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
- package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
- package/corpus/templates/design/app/i18n-data.ts +1217 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
- package/corpus/templates/design/app/lib/design-import.ts +24 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
- package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
- package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
- package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
- package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -6
- package/corpus/templates/design/e2e/helpers.ts +27 -6
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
- package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
- package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
- package/corpus/templates/design/server/plugins/db.ts +41 -0
- package/corpus/templates/design/server/source-workspace.ts +64 -0
- package/corpus/templates/design/shared/board-file.ts +13 -2
- package/corpus/templates/design/shared/canvas-math.ts +231 -33
- package/corpus/templates/design/shared/code-layer.ts +122 -8
- package/corpus/templates/design/shared/component-library.ts +161 -0
- package/corpus/templates/design/shared/db-conflict.ts +27 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
- package/corpus/templates/design/shared/figma-url.ts +149 -0
- package/corpus/templates/design/shared/pen-path.ts +16 -7
- package/corpus/templates/design/shared/source-mode.ts +1 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
- package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
- package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
- package/dist/agent/production-agent.d.ts +82 -7
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +180 -17
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +63 -14
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +46 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +129 -22
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/design-connect.d.ts +6 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +336 -139
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +14 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +19 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +38 -18
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +48 -12
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts +60 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +122 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +36 -2
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +5 -0
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +19 -12
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +13 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +3 -1
- package/dist/collab/recent-edits.d.ts.map +1 -1
- package/dist/collab/recent-edits.js +57 -2
- package/dist/collab/recent-edits.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +87 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +15 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -4
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,62 +1,177 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
appStateDelete,
|
|
3
5
|
appStateGet,
|
|
4
6
|
appStatePut,
|
|
5
7
|
} from "@agent-native/core/application-state";
|
|
6
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
AGENT_CLIENT_ID,
|
|
10
|
+
hasCollabState,
|
|
11
|
+
loadAwarenessRowsStrict,
|
|
12
|
+
} from "@agent-native/core/collab";
|
|
7
13
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
8
14
|
|
|
9
15
|
const FLUSH_POLL_INTERVAL_MS = 200;
|
|
10
16
|
const FLUSH_TIMEOUT_MS = 4000;
|
|
11
17
|
|
|
18
|
+
function parseAwarenessState(state: string): {
|
|
19
|
+
canFlushDocument?: unknown;
|
|
20
|
+
visible?: boolean;
|
|
21
|
+
user?: { email?: unknown };
|
|
22
|
+
} | null {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(state) as {
|
|
25
|
+
canFlushDocument?: unknown;
|
|
26
|
+
visible?: boolean;
|
|
27
|
+
user?: { email?: unknown };
|
|
28
|
+
};
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function awarenessFlushCandidate(entry: {
|
|
35
|
+
clientId: number;
|
|
36
|
+
state: string;
|
|
37
|
+
}): { sessionEmail: string | null; required: boolean } | null {
|
|
38
|
+
if (entry.clientId === AGENT_CLIENT_ID) return null;
|
|
39
|
+
const state = parseAwarenessState(entry.state);
|
|
40
|
+
if (!state || state.visible === false || !state.user) return null;
|
|
41
|
+
// New clients publish an exact boolean. `false` is a known read-only viewer
|
|
42
|
+
// and must never block. A missing field is a pre-deploy client which may be
|
|
43
|
+
// an editor, so offer it the old handshake on a best-effort basis. Invalid
|
|
44
|
+
// values are neither a trustworthy editor capability nor a legacy omission.
|
|
45
|
+
if (state.canFlushDocument !== true && state.canFlushDocument !== undefined) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const email = state.user.email;
|
|
49
|
+
return {
|
|
50
|
+
sessionEmail:
|
|
51
|
+
typeof email === "string" && email.trim() ? email.trim() : null,
|
|
52
|
+
required: state.canFlushDocument === true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
12
56
|
export async function flushOpenDocumentEditorToSql(args: {
|
|
13
57
|
documentId: string;
|
|
14
58
|
ownerEmail?: string | null;
|
|
15
59
|
}) {
|
|
16
60
|
// If a live Yjs collab session is open, the in-memory editor doc is fresher
|
|
17
61
|
// than the SQL column. Ask the open editor to serialize + save, then wait
|
|
18
|
-
// for
|
|
62
|
+
// for an explicit request-id-matched acknowledgement.
|
|
19
63
|
if (!(await hasCollabState(args.documentId))) return;
|
|
20
64
|
|
|
65
|
+
// Persisted Yjs state outlives browser tabs. Modern clients distinguish
|
|
66
|
+
// editors (`true`) from viewers (`false`), so only the former are a hard
|
|
67
|
+
// freshness barrier. Pre-deploy tabs omit the field; they still know how to
|
|
68
|
+
// service this request, but may also be legacy viewers, so offer them the
|
|
69
|
+
// bounded handshake without failing if they stay silent. This preserves live
|
|
70
|
+
// legacy editor changes without making viewer-only tabs time out sync actions.
|
|
71
|
+
const awarenessRows = await loadAwarenessRowsStrict(args.documentId);
|
|
72
|
+
const flushCandidates = awarenessRows
|
|
73
|
+
.map(awarenessFlushCandidate)
|
|
74
|
+
.filter((candidate): candidate is NonNullable<typeof candidate> => {
|
|
75
|
+
return candidate !== null;
|
|
76
|
+
});
|
|
77
|
+
if (flushCandidates.length === 0) return;
|
|
78
|
+
const acknowledgementRequired = flushCandidates.some(
|
|
79
|
+
(candidate) => candidate.required,
|
|
80
|
+
);
|
|
81
|
+
const activeSessionEmails = flushCandidates
|
|
82
|
+
.map((candidate) => candidate.sessionEmail)
|
|
83
|
+
.filter((email): email is string => !!email);
|
|
84
|
+
|
|
21
85
|
const flushKey = `flush-request-${args.documentId}`;
|
|
22
86
|
// The editor polls `flush-request-<id>` via the framework app-state route,
|
|
23
|
-
// which scopes reads to the logged-in browser user
|
|
24
|
-
//
|
|
25
|
-
//
|
|
87
|
+
// which scopes reads to the logged-in browser user. Target every active
|
|
88
|
+
// collaborator email plus owner/caller fallbacks so shared editors and
|
|
89
|
+
// cross-instance actions reach the tab that can serialize the live Y.Doc.
|
|
26
90
|
const callerEmail = getRequestUserEmail() || undefined;
|
|
27
91
|
const targetSessions = Array.from(
|
|
28
92
|
new Set(
|
|
29
|
-
[
|
|
30
|
-
|
|
31
|
-
|
|
93
|
+
[
|
|
94
|
+
...activeSessionEmails,
|
|
95
|
+
args.ownerEmail ?? undefined,
|
|
96
|
+
callerEmail,
|
|
97
|
+
].filter((s): s is string => typeof s === "string" && s.length > 0),
|
|
32
98
|
),
|
|
33
99
|
);
|
|
34
|
-
if (targetSessions.length === 0)
|
|
100
|
+
if (targetSessions.length === 0) {
|
|
101
|
+
if (!acknowledgementRequired) return;
|
|
102
|
+
throw new Error("Could not identify the open document editor to flush.");
|
|
103
|
+
}
|
|
35
104
|
|
|
36
|
-
const
|
|
37
|
-
|
|
105
|
+
const requestId = randomUUID();
|
|
106
|
+
const flushValue = {
|
|
107
|
+
id: args.documentId,
|
|
108
|
+
ts: Date.now(),
|
|
109
|
+
requestId,
|
|
110
|
+
status: "pending",
|
|
111
|
+
};
|
|
112
|
+
const writes = await Promise.allSettled(
|
|
38
113
|
targetSessions.map((session) =>
|
|
39
114
|
appStatePut(session, flushKey, flushValue, {
|
|
40
115
|
requestSource: "agent",
|
|
41
|
-
})
|
|
116
|
+
}),
|
|
42
117
|
),
|
|
43
118
|
);
|
|
119
|
+
const writtenSessions = targetSessions.filter(
|
|
120
|
+
(_session, index) => writes[index]?.status === "fulfilled",
|
|
121
|
+
);
|
|
122
|
+
if (writtenSessions.length === 0) {
|
|
123
|
+
if (!acknowledgementRequired) return;
|
|
124
|
+
throw new Error("Could not ask the open document editor to save.");
|
|
125
|
+
}
|
|
44
126
|
|
|
45
127
|
const deadline = Date.now() + FLUSH_TIMEOUT_MS;
|
|
128
|
+
let flushError: string | null = null;
|
|
129
|
+
let acknowledged = false;
|
|
46
130
|
while (Date.now() < deadline) {
|
|
47
131
|
await new Promise((resolve) => setTimeout(resolve, FLUSH_POLL_INTERVAL_MS));
|
|
48
|
-
const
|
|
49
|
-
|
|
132
|
+
const reads = await Promise.allSettled(
|
|
133
|
+
writtenSessions.map((session) => appStateGet(session, flushKey)),
|
|
134
|
+
);
|
|
135
|
+
const responses = reads.flatMap((result) =>
|
|
136
|
+
result.status === "fulfilled" && result.value ? [result.value] : [],
|
|
137
|
+
);
|
|
138
|
+
const failed = responses.find(
|
|
139
|
+
(
|
|
140
|
+
value,
|
|
141
|
+
): value is {
|
|
142
|
+
requestId: string;
|
|
143
|
+
status: "error";
|
|
144
|
+
error?: string;
|
|
145
|
+
} => value.requestId === requestId && value.status === "error",
|
|
146
|
+
);
|
|
147
|
+
if (failed) {
|
|
148
|
+
flushError =
|
|
149
|
+
typeof failed.error === "string" && failed.error.trim()
|
|
150
|
+
? failed.error
|
|
151
|
+
: "The live document could not be saved before syncing.";
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
acknowledged = responses.some(
|
|
155
|
+
(value) => value.requestId === requestId && value.status === "success",
|
|
50
156
|
);
|
|
51
|
-
if (
|
|
157
|
+
if (acknowledged) break;
|
|
52
158
|
}
|
|
53
159
|
|
|
54
|
-
// Best-effort cleanup
|
|
160
|
+
// Best-effort cleanup after success, explicit failure, or timeout.
|
|
55
161
|
await Promise.all(
|
|
56
|
-
|
|
162
|
+
writtenSessions.map((session) =>
|
|
57
163
|
appStateDelete(session, flushKey, { requestSource: "agent" }).catch(
|
|
58
164
|
() => {},
|
|
59
165
|
),
|
|
60
166
|
),
|
|
61
167
|
);
|
|
168
|
+
|
|
169
|
+
if (flushError) {
|
|
170
|
+
throw new Error(flushError);
|
|
171
|
+
}
|
|
172
|
+
if (!acknowledged && acknowledgementRequired) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
"The open document editor did not finish saving before sync timed out.",
|
|
175
|
+
);
|
|
176
|
+
}
|
|
62
177
|
}
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
} from "@agent-native/core/server";
|
|
5
5
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
6
6
|
|
|
7
|
+
import { flushOpenDocumentEditorToSql } from "./_document-flush.js";
|
|
8
|
+
|
|
7
9
|
export function getCurrentNotionOwner() {
|
|
8
10
|
const owner = getRequestUserEmail();
|
|
9
11
|
if (!owner) throw new Error("no authenticated user");
|
|
@@ -23,6 +25,19 @@ export async function getNotionDocumentOwner(documentId: string) {
|
|
|
23
25
|
return owner;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Flush the live collaborative editor before a user-triggered Notion operation
|
|
30
|
+
* reads or replaces SQL content. The Y.Doc can be ahead of the debounced
|
|
31
|
+
* documents row; without this handshake "Use local" can push a stale snapshot,
|
|
32
|
+
* while "Use Notion" can discard edits that never reached version history.
|
|
33
|
+
*/
|
|
34
|
+
export async function flushNotionDocumentEditor(
|
|
35
|
+
documentId: string,
|
|
36
|
+
ownerEmail: string,
|
|
37
|
+
) {
|
|
38
|
+
await flushOpenDocumentEditorToSql({ documentId, ownerEmail });
|
|
39
|
+
}
|
|
40
|
+
|
|
26
41
|
export function resolveDocumentId(args: { documentId?: string; id?: string }) {
|
|
27
42
|
const documentId = args.documentId?.trim() || args.id?.trim();
|
|
28
43
|
if (!documentId) {
|
|
@@ -201,10 +201,7 @@ export function sourceFieldPropertyOptions(args: {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
function builderFieldNameForSourceKey(sourceFieldKey: string) {
|
|
204
|
-
return sourceFieldKey
|
|
205
|
-
.replace(/^data\./, "")
|
|
206
|
-
.trim()
|
|
207
|
-
.toLowerCase();
|
|
204
|
+
return sourceFieldKey.replace(/^data\./, "").trim();
|
|
208
205
|
}
|
|
209
206
|
|
|
210
207
|
function builderModelFieldsFromMetadata(
|
|
@@ -231,15 +228,15 @@ function builderModelFieldsFromMetadata(
|
|
|
231
228
|
}
|
|
232
229
|
}
|
|
233
230
|
|
|
234
|
-
function builderMetadataForSourceField(args: {
|
|
231
|
+
export function builderMetadataForSourceField(args: {
|
|
235
232
|
sourceFieldKey: string;
|
|
236
233
|
sourceMetadataJson: string | null | undefined;
|
|
237
234
|
}) {
|
|
238
235
|
const fieldName = builderFieldNameForSourceKey(args.sourceFieldKey);
|
|
239
|
-
const sourceFieldKey = args.sourceFieldKey.trim()
|
|
236
|
+
const sourceFieldKey = args.sourceFieldKey.trim();
|
|
240
237
|
return (
|
|
241
238
|
builderModelFieldsFromMetadata(args.sourceMetadataJson).find((field) => {
|
|
242
|
-
const name = field.name.trim()
|
|
239
|
+
const name = field.name.trim();
|
|
243
240
|
return name === fieldName || `data.${name}` === sourceFieldKey;
|
|
244
241
|
}) ?? null
|
|
245
242
|
);
|
|
@@ -48,13 +48,41 @@ const BUILDER_CMS_ATTACH_INITIAL_PAGES = 1;
|
|
|
48
48
|
export async function readInitialBuilderCmsAttachEntries(
|
|
49
49
|
sourceTable: string,
|
|
50
50
|
readEntries: typeof readBuilderCmsContentEntries = readBuilderCmsContentEntries,
|
|
51
|
+
fieldPaths: readonly string[] = [],
|
|
51
52
|
) {
|
|
52
53
|
return readEntries({
|
|
53
54
|
model: sourceTable,
|
|
55
|
+
fieldPaths,
|
|
54
56
|
maxPages: BUILDER_CMS_ATTACH_INITIAL_PAGES,
|
|
55
57
|
});
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
export async function readInitialBuilderCmsAttachSource(
|
|
61
|
+
sourceTable: string,
|
|
62
|
+
dependencies: {
|
|
63
|
+
readModelFields?: typeof readBuilderCmsModelFields;
|
|
64
|
+
readEntries?: typeof readBuilderCmsContentEntries;
|
|
65
|
+
} = {},
|
|
66
|
+
) {
|
|
67
|
+
const readModelFields =
|
|
68
|
+
dependencies.readModelFields ?? readBuilderCmsModelFields;
|
|
69
|
+
const readEntries = dependencies.readEntries ?? readBuilderCmsContentEntries;
|
|
70
|
+
let modelFields: BuilderCmsModelFieldSummary[] = [];
|
|
71
|
+
let modelFieldsError: unknown = null;
|
|
72
|
+
try {
|
|
73
|
+
modelFields = await readModelFields({ model: sourceTable });
|
|
74
|
+
} catch (error) {
|
|
75
|
+
modelFieldsError = error;
|
|
76
|
+
}
|
|
77
|
+
const read = await readInitialBuilderCmsAttachEntries(
|
|
78
|
+
sourceTable,
|
|
79
|
+
readEntries,
|
|
80
|
+
modelFields.map((field) => `data.${field.name}`),
|
|
81
|
+
);
|
|
82
|
+
if (modelFieldsError) throw modelFieldsError;
|
|
83
|
+
return { read, modelFields };
|
|
84
|
+
}
|
|
85
|
+
|
|
58
86
|
function builderReadHasMore(read: BuilderCmsReadResult | null | undefined) {
|
|
59
87
|
return read?.state === "live" && read.progress?.hasMore === true;
|
|
60
88
|
}
|
|
@@ -238,9 +266,10 @@ export default defineAction({
|
|
|
238
266
|
let modelFields: BuilderCmsModelFieldSummary[];
|
|
239
267
|
let builderRead: BuilderCmsReadResult | null = null;
|
|
240
268
|
if (sourceType === "builder-cms") {
|
|
241
|
-
|
|
269
|
+
const initial = await readInitialBuilderCmsAttachSource(sourceTable);
|
|
270
|
+
modelFields = initial.modelFields;
|
|
271
|
+
builderRead = initial.read;
|
|
242
272
|
entries = builderRead.state === "live" ? builderRead.entries : [];
|
|
243
|
-
modelFields = await readBuilderCmsModelFields({ model: sourceTable });
|
|
244
273
|
} else if (sourceType === "local-table") {
|
|
245
274
|
// sourceTable carries the target database id for a local-table source.
|
|
246
275
|
({ entries, modelFields } = await readLocalTableEntries(sourceTable, {
|
|
@@ -327,13 +356,12 @@ export default defineAction({
|
|
|
327
356
|
if (await databaseSourceExistsForTable(database.id, sourceTable)) {
|
|
328
357
|
throw new Error(`"${sourceTable}" is already attached as a source.`);
|
|
329
358
|
}
|
|
330
|
-
const
|
|
331
|
-
await
|
|
359
|
+
const additionalInitial =
|
|
360
|
+
await readInitialBuilderCmsAttachSource(sourceTable);
|
|
361
|
+
const additionalModelFields = additionalInitial.modelFields;
|
|
362
|
+
const additionalRead = additionalInitial.read;
|
|
332
363
|
const additionalEntries =
|
|
333
364
|
additionalRead.state === "live" ? additionalRead.entries : [];
|
|
334
|
-
const additionalModelFields = await readBuilderCmsModelFields({
|
|
335
|
-
model: sourceTable,
|
|
336
|
-
});
|
|
337
365
|
const additionalSourceId = await insertSecondarySource({
|
|
338
366
|
database,
|
|
339
367
|
sourceType,
|
|
@@ -436,6 +464,10 @@ export default defineAction({
|
|
|
436
464
|
const existingSourceRows = existingSource
|
|
437
465
|
? await getSourceRows(existingSource.id)
|
|
438
466
|
: [];
|
|
467
|
+
const builderInitial =
|
|
468
|
+
sourceType === "builder-cms"
|
|
469
|
+
? await readInitialBuilderCmsAttachSource(sourceTable)
|
|
470
|
+
: null;
|
|
439
471
|
const sourceId = await replaceSourceMetadata({
|
|
440
472
|
database,
|
|
441
473
|
source: existingSource,
|
|
@@ -444,18 +476,10 @@ export default defineAction({
|
|
|
444
476
|
sourceTable,
|
|
445
477
|
now,
|
|
446
478
|
});
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
? await readInitialBuilderCmsAttachEntries(sourceTable)
|
|
450
|
-
: null;
|
|
479
|
+
const builderModelFields = builderInitial?.modelFields ?? [];
|
|
480
|
+
const builderRead = builderInitial?.read ?? null;
|
|
451
481
|
const builderEntries =
|
|
452
482
|
builderRead?.state === "live" ? builderRead.entries : [];
|
|
453
|
-
const builderModelFields =
|
|
454
|
-
sourceType === "builder-cms"
|
|
455
|
-
? await readBuilderCmsModelFields({
|
|
456
|
-
model: sourceTable,
|
|
457
|
-
})
|
|
458
|
-
: [];
|
|
459
483
|
let importedEntriesByDocumentId = new Map<string, BuilderCmsSourceEntry>();
|
|
460
484
|
if (builderRead?.state === "live") {
|
|
461
485
|
const importResult = await importBuilderCmsEntriesAsDatabaseItems({
|
|
@@ -187,6 +187,37 @@ async function removeRowsOwnedOnlyBySource(args: {
|
|
|
187
187
|
);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
export async function readBuilderCmsEntriesForRoleChange(
|
|
191
|
+
args: {
|
|
192
|
+
model: string;
|
|
193
|
+
existingFieldPaths?: readonly string[];
|
|
194
|
+
},
|
|
195
|
+
dependencies: {
|
|
196
|
+
readModelFields?: typeof readBuilderCmsModelFields;
|
|
197
|
+
readEntries?: typeof readBuilderCmsContentEntries;
|
|
198
|
+
} = {},
|
|
199
|
+
) {
|
|
200
|
+
const readModelFields =
|
|
201
|
+
dependencies.readModelFields ?? readBuilderCmsModelFields;
|
|
202
|
+
const readEntries = dependencies.readEntries ?? readBuilderCmsContentEntries;
|
|
203
|
+
let modelFields: BuilderCmsModelFieldSummary[] = [];
|
|
204
|
+
let modelFieldsError: unknown = null;
|
|
205
|
+
try {
|
|
206
|
+
modelFields = await readModelFields({ model: args.model });
|
|
207
|
+
} catch (error) {
|
|
208
|
+
modelFieldsError = error;
|
|
209
|
+
}
|
|
210
|
+
const read = await readEntries({
|
|
211
|
+
model: args.model,
|
|
212
|
+
fieldPaths: [
|
|
213
|
+
...(args.existingFieldPaths ?? []),
|
|
214
|
+
...modelFields.map((field) => `data.${field.name}`),
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
if (modelFieldsError) throw modelFieldsError;
|
|
218
|
+
return { read, modelFields };
|
|
219
|
+
}
|
|
220
|
+
|
|
190
221
|
async function readSourceEntries(args: {
|
|
191
222
|
sourceType: ContentDatabaseSourceType;
|
|
192
223
|
sourceTable: string;
|
|
@@ -200,12 +231,12 @@ async function readSourceEntries(args: {
|
|
|
200
231
|
message: string | null;
|
|
201
232
|
}> {
|
|
202
233
|
if (args.sourceType === "builder-cms") {
|
|
203
|
-
const read = await
|
|
234
|
+
const { read, modelFields } = await readBuilderCmsEntriesForRoleChange({
|
|
204
235
|
model: args.sourceTable,
|
|
205
236
|
});
|
|
206
237
|
return {
|
|
207
238
|
entries: read.state === "live" ? read.entries : [],
|
|
208
|
-
modelFields
|
|
239
|
+
modelFields,
|
|
209
240
|
readState: read.state,
|
|
210
241
|
fetchedAt: read.fetchedAt,
|
|
211
242
|
message: read.message,
|
|
@@ -328,13 +359,20 @@ export default defineAction({
|
|
|
328
359
|
throw new Error("Only Builder sources can add more items right now.");
|
|
329
360
|
}
|
|
330
361
|
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
362
|
+
const existingSourceFields = await db
|
|
363
|
+
.select({
|
|
364
|
+
sourceFieldKey: schema.contentDatabaseSourceFields.sourceFieldKey,
|
|
365
|
+
})
|
|
366
|
+
.from(schema.contentDatabaseSourceFields)
|
|
367
|
+
.where(eq(schema.contentDatabaseSourceFields.sourceId, source.id));
|
|
368
|
+
const { read, modelFields: builderModelFields } =
|
|
369
|
+
await readBuilderCmsEntriesForRoleChange({
|
|
370
|
+
model: source.sourceTable,
|
|
371
|
+
existingFieldPaths: existingSourceFields.map(
|
|
372
|
+
(field) => field.sourceFieldKey,
|
|
373
|
+
),
|
|
374
|
+
});
|
|
334
375
|
const entries = read.state === "live" ? read.entries : [];
|
|
335
|
-
const builderModelFields = await readBuilderCmsModelFields({
|
|
336
|
-
model: source.sourceTable,
|
|
337
|
-
});
|
|
338
376
|
await db
|
|
339
377
|
.delete(schema.contentDatabaseSourceFields)
|
|
340
378
|
.where(eq(schema.contentDatabaseSourceFields.sourceId, source.id));
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { createAndLinkNotionPage } from "../server/lib/notion-sync.js";
|
|
5
5
|
import {
|
|
6
|
+
flushNotionDocumentEditor,
|
|
6
7
|
getNotionDocumentOwner,
|
|
7
8
|
resolveDocumentId,
|
|
8
9
|
} from "./_notion-action-utils.js";
|
|
@@ -18,6 +19,7 @@ export default defineAction({
|
|
|
18
19
|
run: async (args) => {
|
|
19
20
|
const documentId = resolveDocumentId(args);
|
|
20
21
|
const owner = await getNotionDocumentOwner(documentId);
|
|
22
|
+
await flushNotionDocumentEditor(documentId, owner);
|
|
21
23
|
return createAndLinkNotionPage(owner, documentId, args.parentPageIdOrUrl);
|
|
22
24
|
},
|
|
23
25
|
});
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { linkDocumentToNotionPage } from "../server/lib/notion-sync.js";
|
|
5
5
|
import {
|
|
6
|
+
flushNotionDocumentEditor,
|
|
6
7
|
getNotionDocumentOwner,
|
|
7
8
|
resolveDocumentId,
|
|
8
9
|
} from "./_notion-action-utils.js";
|
|
@@ -26,6 +27,7 @@ export default defineAction({
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const owner = await getNotionDocumentOwner(documentId);
|
|
30
|
+
await flushNotionDocumentEditor(documentId, owner);
|
|
29
31
|
return linkDocumentToNotionPage(owner, documentId, pageIdOrUrl);
|
|
30
32
|
},
|
|
31
33
|
});
|
|
@@ -29,12 +29,10 @@ import {
|
|
|
29
29
|
* never saw the key, so every external `pull-document` waited the full
|
|
30
30
|
* timeout and returned stale DB content.
|
|
31
31
|
* 2. The editor polls that key, serializes its current Y.Doc to markdown
|
|
32
|
-
* through its existing serializer, calls `update-document`, then
|
|
33
|
-
*
|
|
34
|
-
* 3. We poll
|
|
35
|
-
*
|
|
36
|
-
* clears (no editor actually open), we fall back to the DB column, which
|
|
37
|
-
* is the best available snapshot.
|
|
32
|
+
* through its existing serializer, calls `update-document`, then writes an
|
|
33
|
+
* explicit success/error acknowledgement for that request id.
|
|
34
|
+
* 3. We poll every active collaborator session for the acknowledgement, fail
|
|
35
|
+
* closed on editor errors/timeouts, and then read the now-fresh row.
|
|
38
36
|
*
|
|
39
37
|
* When there is no live collab session the DB column is authoritative and we
|
|
40
38
|
* skip the handshake entirely. The helper bounds the wait so stale collab
|
|
@@ -90,7 +88,7 @@ export default defineAction({
|
|
|
90
88
|
|
|
91
89
|
// If a live Yjs collab session is open, the in-memory editor doc is fresher
|
|
92
90
|
// than the SQL column. Ask the open editor to serialize + save, then wait
|
|
93
|
-
// for
|
|
91
|
+
// for its explicit request-id-matched acknowledgement.
|
|
94
92
|
await flushOpenDocumentEditorToSql({
|
|
95
93
|
documentId: id,
|
|
96
94
|
ownerEmail: (access.resource.ownerEmail as string | undefined) || null,
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { pullDocumentFromNotion } from "../server/lib/notion-sync.js";
|
|
5
5
|
import {
|
|
6
|
+
flushNotionDocumentEditor,
|
|
6
7
|
getNotionDocumentOwner,
|
|
7
8
|
resolveDocumentId,
|
|
8
9
|
} from "./_notion-action-utils.js";
|
|
@@ -17,6 +18,7 @@ export default defineAction({
|
|
|
17
18
|
run: async (args) => {
|
|
18
19
|
const documentId = resolveDocumentId(args);
|
|
19
20
|
const owner = await getNotionDocumentOwner(documentId);
|
|
21
|
+
await flushNotionDocumentEditor(documentId, owner);
|
|
20
22
|
return pullDocumentFromNotion(owner, documentId, true);
|
|
21
23
|
},
|
|
22
24
|
});
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { pushDocumentToNotion } from "../server/lib/notion-sync.js";
|
|
5
5
|
import {
|
|
6
|
+
flushNotionDocumentEditor,
|
|
6
7
|
getNotionDocumentOwner,
|
|
7
8
|
resolveDocumentId,
|
|
8
9
|
} from "./_notion-action-utils.js";
|
|
@@ -12,11 +13,20 @@ export default defineAction({
|
|
|
12
13
|
schema: z.object({
|
|
13
14
|
documentId: z.string().optional().describe("Document ID (required)"),
|
|
14
15
|
id: z.string().optional().describe("Alias for --documentId"),
|
|
16
|
+
flushOpenEditor: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.default(true)
|
|
19
|
+
.describe(
|
|
20
|
+
"Flush an open collaborative editor before pushing (disable only when the caller just persisted the exact editor content)",
|
|
21
|
+
),
|
|
15
22
|
}),
|
|
16
23
|
http: { method: "POST" },
|
|
17
24
|
run: async (args) => {
|
|
18
25
|
const documentId = resolveDocumentId(args);
|
|
19
26
|
const owner = await getNotionDocumentOwner(documentId);
|
|
27
|
+
if (args.flushOpenEditor) {
|
|
28
|
+
await flushNotionDocumentEditor(documentId, owner);
|
|
29
|
+
}
|
|
20
30
|
return pushDocumentToNotion(owner, documentId);
|
|
21
31
|
},
|
|
22
32
|
});
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
|
|
4
4
|
import { resolveDocumentSyncConflict } from "../server/lib/notion-sync.js";
|
|
5
5
|
import {
|
|
6
|
+
flushNotionDocumentEditor,
|
|
6
7
|
getNotionDocumentOwner,
|
|
7
8
|
resolveDocumentId,
|
|
8
9
|
} from "./_notion-action-utils.js";
|
|
@@ -18,6 +19,7 @@ export default defineAction({
|
|
|
18
19
|
run: async (args) => {
|
|
19
20
|
const documentId = resolveDocumentId(args);
|
|
20
21
|
const owner = await getNotionDocumentOwner(documentId);
|
|
22
|
+
await flushNotionDocumentEditor(documentId, owner);
|
|
21
23
|
return resolveDocumentSyncConflict(owner, documentId, args.direction);
|
|
22
24
|
},
|
|
23
25
|
});
|
|
@@ -6,7 +6,10 @@ import type {
|
|
|
6
6
|
DocumentPropertyValue,
|
|
7
7
|
SuggestSourceJoinKeyResponse,
|
|
8
8
|
} from "../shared/api.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
readBuilderCmsContentEntries,
|
|
11
|
+
readBuilderCmsModelFields,
|
|
12
|
+
} from "./_builder-cms-read-client.js";
|
|
10
13
|
import {
|
|
11
14
|
getContentDatabaseSourceSnapshot,
|
|
12
15
|
resolveDatabaseForSourceMutation,
|
|
@@ -52,8 +55,12 @@ export default defineAction({
|
|
|
52
55
|
|
|
53
56
|
let secondaryValues: Record<string, DocumentPropertyValue>[];
|
|
54
57
|
if (args.candidateSourceType === "builder-cms") {
|
|
58
|
+
const modelFields = await readBuilderCmsModelFields({
|
|
59
|
+
model: args.candidateSourceTable,
|
|
60
|
+
}).catch(() => []);
|
|
55
61
|
const read = await readBuilderCmsContentEntries({
|
|
56
62
|
model: args.candidateSourceTable,
|
|
63
|
+
fieldPaths: modelFields.map((field) => `data.${field.name}`),
|
|
57
64
|
});
|
|
58
65
|
secondaryValues = (read.state === "live" ? read.entries : [])
|
|
59
66
|
.map((entry) => entry.sourceValues)
|