@agent-native/core 0.92.10 → 0.92.11
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 +23 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +181 -15
- package/corpus/core/src/agent/run-manager.ts +31 -4
- package/corpus/core/src/agent/run-store.ts +80 -0
- 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.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 +48 -4
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- 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/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/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- 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/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-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/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 +79 -6
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +161 -14
- 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 +29 -5
- 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 +61 -0
- 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.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/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/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/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
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { callAction } from "@agent-native/core/client";
|
|
2
|
+
|
|
3
|
+
import type { DrawAnnotation } from "@/components/visual-editor";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Draw-to-agent visual capture.
|
|
7
|
+
*
|
|
8
|
+
* DrawOverlay's `onSend` still hands the caller a text summary of stroke
|
|
9
|
+
* paths and text labels (see DesignCanvas's `onSend` wiring) — that stays,
|
|
10
|
+
* because raw coordinates remain useful for precision edits. This module
|
|
11
|
+
* additionally rasterizes the annotated screen into ONE PNG the agent can
|
|
12
|
+
* actually see, mirroring the Claude-design-style "draw over a screenshot"
|
|
13
|
+
* flow instead of forcing the agent to reconstruct a picture from
|
|
14
|
+
* coordinates alone.
|
|
15
|
+
*
|
|
16
|
+
* Pipeline: reuse `take-design-screenshot` (already renders the live screen
|
|
17
|
+
* server-side via headless Chromium — see that action's docblock) at the
|
|
18
|
+
* exact on-screen rect the user drew on, composite the serialized
|
|
19
|
+
* strokes/text on top client-side, then hand the finished PNG to the shared
|
|
20
|
+
* `upload-image` core action so only a durable URL — never base64 — reaches
|
|
21
|
+
* the agent chat message or any persisted state.
|
|
22
|
+
*
|
|
23
|
+
* Every step degrades silently to `null` (no thrown errors): a missing
|
|
24
|
+
* Chromium binary in hosted/serverless deploys, a slow render, a network
|
|
25
|
+
* blip fetching the screenshot, or an unconfigured upload provider should
|
|
26
|
+
* never block the user's drawing from reaching the agent as text — see
|
|
27
|
+
* `captureAnnotatedScreenshot`'s caller in DesignCanvas.tsx, which always
|
|
28
|
+
* falls through to the text-only summary.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** Bounds the whole capture pipeline so a slow/hung Chromium render or
|
|
32
|
+
* upload never leaves the user waiting indefinitely to see their message
|
|
33
|
+
* land in chat. Generous enough for a local Playwright cold start. */
|
|
34
|
+
const CAPTURE_TIMEOUT_MS = 9000;
|
|
35
|
+
|
|
36
|
+
const MIN_DIMENSION_PX = 200;
|
|
37
|
+
const MAX_WIDTH_PX = 3840;
|
|
38
|
+
const MAX_HEIGHT_PX = 4096;
|
|
39
|
+
|
|
40
|
+
interface TakeDesignScreenshotResult {
|
|
41
|
+
ok: boolean;
|
|
42
|
+
reason?: string;
|
|
43
|
+
screenshots?: Array<{ url?: string }>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface UploadImageResult {
|
|
47
|
+
url?: string;
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CaptureAnnotatedScreenshotOptions {
|
|
52
|
+
/** Stable design id — used as fallback screen lookup and upload filename. */
|
|
53
|
+
designId?: string;
|
|
54
|
+
/** Specific design_files.id for the annotated screen. Preferred lookup key. */
|
|
55
|
+
fileId?: string;
|
|
56
|
+
/** Filename fallback when `fileId` is not available (paired with `designId`). */
|
|
57
|
+
filename?: string;
|
|
58
|
+
/** Only inline (SQL-backed HTML) screens can be rendered by take-design-screenshot. */
|
|
59
|
+
sourceType?: "inline" | "localhost" | "fusion";
|
|
60
|
+
annotations: DrawAnnotation[];
|
|
61
|
+
/** Layout-space canvas size the annotations were serialized against. */
|
|
62
|
+
canvasSize: { width: number; height: number };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const timer = setTimeout(() => {
|
|
68
|
+
reject(
|
|
69
|
+
new Error(`annotation screenshot capture timed out after ${ms}ms`),
|
|
70
|
+
);
|
|
71
|
+
}, ms);
|
|
72
|
+
promise.then(
|
|
73
|
+
(value) => {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
resolve(value);
|
|
76
|
+
},
|
|
77
|
+
(error) => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
reject(error);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function loadImageFromUrl(url: string): Promise<HTMLImageElement> {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const image = new Image();
|
|
88
|
+
image.onload = () => resolve(image);
|
|
89
|
+
image.onerror = () =>
|
|
90
|
+
reject(new Error("Failed to decode screenshot image"));
|
|
91
|
+
image.src = url;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Draw one annotation (a stroke path or a text label) onto a 2D canvas
|
|
97
|
+
* context, in the same layout-pixel coordinate space DrawOverlay used when
|
|
98
|
+
* it serialized `pathData`/`position` in its own `send()` — see
|
|
99
|
+
* DrawOverlay.tsx's coordinate-model docblock. Parses the "M x,y L x,y ..."
|
|
100
|
+
* syntax with a small regex instead of `new Path2D(...)`: this is the exact
|
|
101
|
+
* (and only) format DrawOverlay's `send()` emits, and avoiding Path2D keeps
|
|
102
|
+
* this rasterizer testable against a plain fake context object — Path2D
|
|
103
|
+
* isn't implemented in jsdom/happy-dom, only real browsers. Exported for unit
|
|
104
|
+
* testing against a fake context (canvas 2D isn't implemented in jsdom).
|
|
105
|
+
*/
|
|
106
|
+
export function drawAnnotationsOnContext(
|
|
107
|
+
ctx: Pick<
|
|
108
|
+
CanvasRenderingContext2D,
|
|
109
|
+
| "save"
|
|
110
|
+
| "restore"
|
|
111
|
+
| "beginPath"
|
|
112
|
+
| "moveTo"
|
|
113
|
+
| "lineTo"
|
|
114
|
+
| "stroke"
|
|
115
|
+
| "fillText"
|
|
116
|
+
| "strokeStyle"
|
|
117
|
+
| "fillStyle"
|
|
118
|
+
| "lineWidth"
|
|
119
|
+
| "lineCap"
|
|
120
|
+
| "lineJoin"
|
|
121
|
+
| "font"
|
|
122
|
+
| "textBaseline"
|
|
123
|
+
>,
|
|
124
|
+
annotations: DrawAnnotation[],
|
|
125
|
+
): void {
|
|
126
|
+
for (const annotation of annotations) {
|
|
127
|
+
if (annotation.type === "path" && annotation.pathData) {
|
|
128
|
+
const points = parsePathDataPoints(annotation.pathData);
|
|
129
|
+
if (points.length < 2) continue;
|
|
130
|
+
ctx.save();
|
|
131
|
+
ctx.strokeStyle = annotation.color;
|
|
132
|
+
ctx.lineWidth = annotation.lineWidth;
|
|
133
|
+
ctx.lineCap = "round";
|
|
134
|
+
ctx.lineJoin = "round";
|
|
135
|
+
ctx.beginPath();
|
|
136
|
+
ctx.moveTo(points[0].x, points[0].y);
|
|
137
|
+
for (let i = 1; i < points.length; i++) {
|
|
138
|
+
ctx.lineTo(points[i].x, points[i].y);
|
|
139
|
+
}
|
|
140
|
+
ctx.stroke();
|
|
141
|
+
ctx.restore();
|
|
142
|
+
} else if (annotation.type === "text" && annotation.text) {
|
|
143
|
+
ctx.save();
|
|
144
|
+
ctx.fillStyle = annotation.color;
|
|
145
|
+
ctx.font = `600 ${14 + annotation.lineWidth}px sans-serif`;
|
|
146
|
+
ctx.textBaseline = "top";
|
|
147
|
+
ctx.fillText(
|
|
148
|
+
annotation.text,
|
|
149
|
+
annotation.position.x,
|
|
150
|
+
annotation.position.y,
|
|
151
|
+
);
|
|
152
|
+
ctx.restore();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const PATH_DATA_POINT_RE = /[ML]\s*(-?[\d.]+),(-?[\d.]+)/g;
|
|
158
|
+
|
|
159
|
+
/** Parse DrawOverlay's `"M x,y L x,y L x,y"` path syntax into raw points. */
|
|
160
|
+
function parsePathDataPoints(
|
|
161
|
+
pathData: string,
|
|
162
|
+
): Array<{ x: number; y: number }> {
|
|
163
|
+
const points: Array<{ x: number; y: number }> = [];
|
|
164
|
+
for (const match of pathData.matchAll(PATH_DATA_POINT_RE)) {
|
|
165
|
+
points.push({ x: Number(match[1]), y: Number(match[2]) });
|
|
166
|
+
}
|
|
167
|
+
return points;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Fetch the screenshot bytes (avoids canvas cross-origin tainting — a
|
|
171
|
+
* same-process `fetch` + `Blob` object URL is never "foreign" to the canvas,
|
|
172
|
+
* regardless of the storage provider's CORS headers) and composite the
|
|
173
|
+
* annotations on top at the exact requested pixel size. */
|
|
174
|
+
async function compositeScreenshotWithAnnotations(
|
|
175
|
+
screenshotUrl: string,
|
|
176
|
+
annotations: DrawAnnotation[],
|
|
177
|
+
size: { width: number; height: number },
|
|
178
|
+
): Promise<string | null> {
|
|
179
|
+
const response = await fetch(screenshotUrl);
|
|
180
|
+
if (!response.ok) return null;
|
|
181
|
+
const blob = await response.blob();
|
|
182
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
183
|
+
try {
|
|
184
|
+
const image = await loadImageFromUrl(objectUrl);
|
|
185
|
+
const canvas = document.createElement("canvas");
|
|
186
|
+
canvas.width = size.width;
|
|
187
|
+
canvas.height = size.height;
|
|
188
|
+
const ctx = canvas.getContext("2d");
|
|
189
|
+
if (!ctx) return null;
|
|
190
|
+
ctx.drawImage(image, 0, 0, size.width, size.height);
|
|
191
|
+
drawAnnotationsOnContext(ctx, annotations);
|
|
192
|
+
return canvas.toDataURL("image/png");
|
|
193
|
+
} finally {
|
|
194
|
+
URL.revokeObjectURL(objectUrl);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Best-effort: render the annotated screen, composite the drawing on top,
|
|
200
|
+
* and upload the result. Returns the durable image URL, or `null` on ANY
|
|
201
|
+
* failure (missing Chromium, no upload provider configured, network error,
|
|
202
|
+
* unsupported source type, timeout) — callers must treat `null` as "fall
|
|
203
|
+
* back to the text-only summary", never as a reason to drop the annotation.
|
|
204
|
+
*/
|
|
205
|
+
export async function captureAnnotatedScreenshot(
|
|
206
|
+
options: CaptureAnnotatedScreenshotOptions,
|
|
207
|
+
): Promise<string | null> {
|
|
208
|
+
const { designId, fileId, filename, sourceType, annotations, canvasSize } =
|
|
209
|
+
options;
|
|
210
|
+
|
|
211
|
+
// take-design-screenshot renders stored SQL/collab HTML content; localhost
|
|
212
|
+
// and fusion screens hold a URL, not renderable HTML, so skip straight to
|
|
213
|
+
// the text-only fallback for those instead of paying for a doomed render.
|
|
214
|
+
if (sourceType && sourceType !== "inline") return null;
|
|
215
|
+
if (!fileId && !designId) return null;
|
|
216
|
+
if (typeof document === "undefined") return null;
|
|
217
|
+
if (
|
|
218
|
+
!Number.isFinite(canvasSize.width) ||
|
|
219
|
+
!Number.isFinite(canvasSize.height) ||
|
|
220
|
+
canvasSize.width < MIN_DIMENSION_PX ||
|
|
221
|
+
canvasSize.height < MIN_DIMENSION_PX
|
|
222
|
+
) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const widthPx = Math.min(MAX_WIDTH_PX, Math.round(canvasSize.width));
|
|
227
|
+
const heightPx = Math.min(MAX_HEIGHT_PX, Math.round(canvasSize.height));
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
return await withTimeout(
|
|
231
|
+
(async () => {
|
|
232
|
+
const shot = await callAction<TakeDesignScreenshotResult>(
|
|
233
|
+
"take-design-screenshot",
|
|
234
|
+
{
|
|
235
|
+
...(fileId ? { fileId } : { designId, filename }),
|
|
236
|
+
widths: [widthPx],
|
|
237
|
+
heights: [heightPx],
|
|
238
|
+
},
|
|
239
|
+
);
|
|
240
|
+
const screenshotUrl = shot?.ok ? shot.screenshots?.[0]?.url : undefined;
|
|
241
|
+
if (!screenshotUrl) return null;
|
|
242
|
+
|
|
243
|
+
const compositeDataUrl = await compositeScreenshotWithAnnotations(
|
|
244
|
+
screenshotUrl,
|
|
245
|
+
annotations,
|
|
246
|
+
{ width: widthPx, height: heightPx },
|
|
247
|
+
);
|
|
248
|
+
if (!compositeDataUrl) return null;
|
|
249
|
+
|
|
250
|
+
const uploaded = await callAction<UploadImageResult>("upload-image", {
|
|
251
|
+
data: compositeDataUrl,
|
|
252
|
+
filename: `design-annotation-${designId ?? fileId}-${Date.now()}.png`,
|
|
253
|
+
});
|
|
254
|
+
return uploaded?.url ?? null;
|
|
255
|
+
})(),
|
|
256
|
+
CAPTURE_TIMEOUT_MS,
|
|
257
|
+
);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.warn(
|
|
260
|
+
"[DesignCanvas] annotated screenshot capture failed; falling back to text-only:",
|
|
261
|
+
error,
|
|
262
|
+
);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
interface SubmitDesignAnnotationsOptions {
|
|
2
2
|
message: string;
|
|
3
3
|
hasQueuedPins: boolean;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Deliver the message to the agent chat. Must reject (or throw) when
|
|
6
|
+
* delivery is not confirmed — e.g. `sendToAgentChatAndConfirm` resolving
|
|
7
|
+
* `delivered: false` should be turned into a thrown/rejected error here.
|
|
8
|
+
* A `send` that only fires-and-forgets (never throws on silent drops) will
|
|
9
|
+
* make this function report success even though nothing reached the agent.
|
|
10
|
+
*/
|
|
11
|
+
send: (message: string) => void | Promise<void>;
|
|
5
12
|
markQueuedPinsSubmitted: () => void;
|
|
6
13
|
exitDrawMode: () => void;
|
|
7
14
|
onError: (error: unknown) => void;
|
|
@@ -11,18 +18,22 @@ interface SubmitDesignAnnotationsOptions {
|
|
|
11
18
|
* Submit a drawing/comment batch as one atomic UI transition.
|
|
12
19
|
*
|
|
13
20
|
* The overlay and queued pins must remain intact when chat handoff fails so the
|
|
14
|
-
* user can retry without recreating their annotation work.
|
|
21
|
+
* user can retry without recreating their annotation work. `send` is awaited
|
|
22
|
+
* so a caller using an ack-confirmed delivery (e.g.
|
|
23
|
+
* `sendToAgentChatAndConfirm`) can reject when the message was silently
|
|
24
|
+
* dropped (no LLM/agent engine configured, panel never mounted, etc.) — the
|
|
25
|
+
* pins/draw-mode teardown below only runs once delivery is confirmed.
|
|
15
26
|
*/
|
|
16
|
-
export function submitDesignAnnotations({
|
|
27
|
+
export async function submitDesignAnnotations({
|
|
17
28
|
message,
|
|
18
29
|
hasQueuedPins,
|
|
19
30
|
send,
|
|
20
31
|
markQueuedPinsSubmitted,
|
|
21
32
|
exitDrawMode,
|
|
22
33
|
onError,
|
|
23
|
-
}: SubmitDesignAnnotationsOptions): boolean {
|
|
34
|
+
}: SubmitDesignAnnotationsOptions): Promise<boolean> {
|
|
24
35
|
try {
|
|
25
|
-
send(message);
|
|
36
|
+
await send(message);
|
|
26
37
|
} catch (error) {
|
|
27
38
|
onError(error);
|
|
28
39
|
return false;
|
package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Converts a viewport point into the iframe's unscaled content coordinates.
|
|
3
|
+
*
|
|
4
|
+
* `scrollOffset` is the embedded screen's own internal document scroll
|
|
5
|
+
* (`iframe.contentWindow.scrollX/scrollY`), already expressed in the iframe's
|
|
6
|
+
* own unscaled content pixels — the SAME units as `iframeContentSize` and the
|
|
7
|
+
* function's return value. It is folded in AFTER the scale division, never
|
|
8
|
+
* multiplied/divided by `scaleX`/`scaleY`: the outer `scaleX`/`scaleY` factor
|
|
9
|
+
* only undoes the *host* canvas's zoom transform (which maps `iframeRect`,
|
|
10
|
+
* a host-viewport rect, onto `iframeContentSize`, the iframe's own layout
|
|
11
|
+
* box) and has nothing to do with how far the iframe's own document has been
|
|
12
|
+
* scrolled internally. Concretely: at 50% host zoom (scaleX = 0.5) with the
|
|
13
|
+
* embedded screen scrolled 600px down, a click at the iframe's visible top
|
|
14
|
+
* edge (rendered content y = 0) must land at content y = 600 — not 1200 (a
|
|
15
|
+
* mistaken `600 / 0.5`) and not 300 (a mistaken `600 * 0.5`).
|
|
3
16
|
*/
|
|
4
17
|
export function getScreenContentPointFromClient(
|
|
5
18
|
clientX: number,
|
|
6
19
|
clientY: number,
|
|
7
20
|
iframeRect: { left: number; top: number; width: number; height: number },
|
|
8
21
|
iframeContentSize: { width: number; height: number },
|
|
22
|
+
scrollOffset: { left: number; top: number } = { left: 0, top: 0 },
|
|
9
23
|
): { x: number; y: number } {
|
|
10
24
|
const scaleX =
|
|
11
25
|
iframeContentSize.width > 0
|
|
@@ -16,8 +30,8 @@ export function getScreenContentPointFromClient(
|
|
|
16
30
|
? iframeRect.height / iframeContentSize.height
|
|
17
31
|
: 1;
|
|
18
32
|
return {
|
|
19
|
-
x: (clientX - iframeRect.left) / (scaleX || 1),
|
|
20
|
-
y: (clientY - iframeRect.top) / (scaleY || 1),
|
|
33
|
+
x: (clientX - iframeRect.left) / (scaleX || 1) + scrollOffset.left,
|
|
34
|
+
y: (clientY - iframeRect.top) / (scaleY || 1) + scrollOffset.top,
|
|
21
35
|
};
|
|
22
36
|
}
|
|
23
37
|
|
|
@@ -25,9 +25,14 @@ export function getEmbeddedIframeBackgroundColor(args: {
|
|
|
25
25
|
: (args.embeddedFrameBackground ?? "transparent");
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function
|
|
28
|
+
export function embeddedContentOffsetCss(x: number, y: number): string {
|
|
29
29
|
if (x === 0 && y === 0) return "";
|
|
30
|
-
return
|
|
30
|
+
return `body > [data-agent-native-node-id]{translate:${Math.round(x)}px ${Math.round(y)}px;}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function embeddedContentOffsetStyle(x: number, y: number): string {
|
|
34
|
+
const css = embeddedContentOffsetCss(x, y);
|
|
35
|
+
return css ? `<style data-agent-native-content-offset>${css}</style>` : "";
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
function injectEmbeddedFrameStyle(content: string, style: string): string {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ElementInfo } from "../types";
|
|
1
|
+
import type { CanvasLayerHitCandidate, ElementInfo } from "../types";
|
|
2
2
|
|
|
3
3
|
export interface IframeHotkeyPayload {
|
|
4
4
|
key: string;
|
|
@@ -15,9 +15,11 @@ export interface IframeFigmaClipboardPastePayload {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface IframeContextMenuPayload {
|
|
18
|
+
screenId?: string;
|
|
18
19
|
clientX: number;
|
|
19
20
|
clientY: number;
|
|
20
21
|
viewportClientX?: number;
|
|
21
22
|
viewportClientY?: number;
|
|
22
23
|
info?: ElementInfo | null;
|
|
24
|
+
layerCandidates?: CanvasLayerHitCandidate[];
|
|
23
25
|
}
|
|
@@ -19,6 +19,14 @@ const VOID_HTML_TAGS = new Set([
|
|
|
19
19
|
"wbr",
|
|
20
20
|
]);
|
|
21
21
|
|
|
22
|
+
const INSPECT_CODE_MAX_INLINE_TAG_LENGTH = 48;
|
|
23
|
+
|
|
24
|
+
interface ParsedOpeningTag {
|
|
25
|
+
tagName: string;
|
|
26
|
+
attributes: string[];
|
|
27
|
+
closing: ">" | "/>";
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
export function normalizedElementTagName(
|
|
23
31
|
tagName: string | null | undefined,
|
|
24
32
|
): string {
|
|
@@ -72,6 +80,58 @@ export function truncateOpeningTag(openTag: string, max = 32): string {
|
|
|
72
80
|
);
|
|
73
81
|
}
|
|
74
82
|
|
|
83
|
+
function parseInspectCodeOpeningTag(openTag: string): ParsedOpeningTag | null {
|
|
84
|
+
const tagMatch = /^<([a-zA-Z][\w:-]*)([\s\S]*?)(\/?>)$/.exec(openTag.trim());
|
|
85
|
+
if (!tagMatch?.[1] || (tagMatch[3] !== ">" && tagMatch[3] !== "/>")) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const attributes: string[] = [];
|
|
90
|
+
const attributePattern =
|
|
91
|
+
/\s+([^\s=/>]+)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'=<>`]+))?/g;
|
|
92
|
+
for (const match of (tagMatch[2] ?? "").matchAll(attributePattern)) {
|
|
93
|
+
const name = match[1];
|
|
94
|
+
if (!name) continue;
|
|
95
|
+
const normalizedName = name.toLowerCase();
|
|
96
|
+
if (
|
|
97
|
+
normalizedName === "style" ||
|
|
98
|
+
normalizedName.startsWith("data-agent-native-")
|
|
99
|
+
) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
attributes.push(`${name}${match[2] ? `=${match[2]}` : ""}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
tagName: tagMatch[1],
|
|
107
|
+
attributes,
|
|
108
|
+
closing: tagMatch[3],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Remove Design's runtime-only attributes, then format retained attributes to
|
|
114
|
+
* fit the Inspect Code popover without routine horizontal scrolling.
|
|
115
|
+
*/
|
|
116
|
+
export function formatInspectCodeOpeningTag(
|
|
117
|
+
openTag: string,
|
|
118
|
+
maxInlineLength = INSPECT_CODE_MAX_INLINE_TAG_LENGTH,
|
|
119
|
+
): string {
|
|
120
|
+
const parsed = parseInspectCodeOpeningTag(openTag);
|
|
121
|
+
if (!parsed) return openTag;
|
|
122
|
+
|
|
123
|
+
const inline = `<${parsed.tagName}${
|
|
124
|
+
parsed.attributes.length ? ` ${parsed.attributes.join(" ")}` : ""
|
|
125
|
+
}${parsed.closing}`;
|
|
126
|
+
if (!parsed.attributes.length || inline.length <= maxInlineLength) {
|
|
127
|
+
return inline;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return `<${parsed.tagName}\n ${parsed.attributes.join("\n ")}${
|
|
131
|
+
parsed.closing
|
|
132
|
+
}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
75
135
|
function tagNameFromOpeningTag(openTag: string): string | null {
|
|
76
136
|
const match = /^<\/?\s*([a-zA-Z][\w:-]*)/.exec(openTag.trim());
|
|
77
137
|
return match?.[1]?.toLowerCase() ?? null;
|
|
@@ -113,7 +173,9 @@ export function elementHtmlPreview(
|
|
|
113
173
|
data.classes?.some((item) => item.trim()),
|
|
114
174
|
);
|
|
115
175
|
if (!openingTag && !hasFallbackMetadata) return null;
|
|
116
|
-
const previewOpeningTag =
|
|
176
|
+
const previewOpeningTag = formatInspectCodeOpeningTag(
|
|
177
|
+
openingTag ?? fallbackOpeningTag(data),
|
|
178
|
+
);
|
|
117
179
|
const tagName =
|
|
118
180
|
tagNameFromOpeningTag(previewOpeningTag) ??
|
|
119
181
|
normalizedElementTagName(data.tagName);
|
|
@@ -229,20 +291,28 @@ export function parseAlpineDataObject(
|
|
|
229
291
|
|
|
230
292
|
const out: Record<string, string> = {};
|
|
231
293
|
// Split on top-level commas only (no nesting / quotes inside values here).
|
|
294
|
+
// The quoted-value alternatives allow backslash-escaped quotes (`\\.`)
|
|
295
|
+
// inside the literal — without that, a value like `'it\'s ok'` truncates
|
|
296
|
+
// at the escaped quote (matching only `'it\'`), silently dropping the rest
|
|
297
|
+
// of the string. That mismatch used to slip past `canRebuildAlpineDataLosslessly`
|
|
298
|
+
// as a false positive: the truncated value round-tripped "stably" (in the
|
|
299
|
+
// sense of parse -> serialize -> parse staying self-consistent) while still
|
|
300
|
+
// being wrong relative to the original source.
|
|
232
301
|
const pairRe =
|
|
233
|
-
/(?:^|,)\s*(?:'([^']+)'|"([^"]+)"|([A-Za-z_$][\w$]*))\s*:\s*('[^']*'|"[^"]*"|true|false|-?\d+(?:\.\d+)?)/g;
|
|
302
|
+
/(?:^|,)\s*(?:'([^']+)'|"([^"]+)"|([A-Za-z_$][\w$]*))\s*:\s*('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|true|false|-?\d+(?:\.\d+)?)/g;
|
|
234
303
|
let m: RegExpExecArray | null;
|
|
235
304
|
let matched = false;
|
|
236
305
|
while ((m = pairRe.exec(inner)) !== null) {
|
|
237
306
|
matched = true;
|
|
238
307
|
const key = m[1] ?? m[2] ?? m[3];
|
|
239
308
|
let raw = m[4]!;
|
|
240
|
-
// Unwrap quotes for string literals
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
309
|
+
// Unwrap quotes for string literals, un-escaping backslash-escaped quotes
|
|
310
|
+
// back to their literal form (the inverse of the escaping
|
|
311
|
+
// `serializeAlpineDataObject` applies); keep booleans / numbers verbatim.
|
|
312
|
+
if (raw.startsWith("'") && raw.endsWith("'")) {
|
|
313
|
+
raw = raw.slice(1, -1).replace(/\\'/g, "'");
|
|
314
|
+
} else if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
315
|
+
raw = raw.slice(1, -1).replace(/\\"/g, '"');
|
|
246
316
|
}
|
|
247
317
|
if (key) out[key] = raw;
|
|
248
318
|
}
|