@agent-native/core 0.92.9 → 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 +29 -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/deploy/build.ts +133 -5
- 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/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/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +24 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +102 -5
- package/dist/deploy/build.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/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +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
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
getCredentialContext,
|
|
46
46
|
} from "@agent-native/core/server/request-context";
|
|
47
47
|
import { getSetting, getUserSetting } from "@agent-native/core/settings";
|
|
48
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
48
49
|
import { transcribeWithBuilder } from "@agent-native/core/transcription/builder";
|
|
49
50
|
import { and, eq } from "drizzle-orm";
|
|
50
51
|
import { z } from "zod";
|
|
@@ -110,6 +111,7 @@ type TranscriptionProvider = {
|
|
|
110
111
|
type RecordingMediaRow = {
|
|
111
112
|
videoUrl: string | null;
|
|
112
113
|
videoFormat?: "webm" | "mp4" | null;
|
|
114
|
+
videoSizeBytes?: number | null;
|
|
113
115
|
hasAudio?: boolean | null;
|
|
114
116
|
sourceAppName?: string | null;
|
|
115
117
|
sourceWindowTitle?: string | null;
|
|
@@ -127,6 +129,11 @@ const BUILDER_TRANSCRIPTION_MIN_TIMEOUT_MS = 45_000;
|
|
|
127
129
|
const BUILDER_TRANSCRIPTION_MAX_TIMEOUT_MS = 65_000;
|
|
128
130
|
const BUILDER_TRANSCRIPTION_BASE_TIMEOUT_MS = 30_000;
|
|
129
131
|
const BUILDER_TRANSCRIPTION_PER_MINUTE_MS = 3_000;
|
|
132
|
+
const MEDIA_FETCH_MIN_TIMEOUT_MS = 45_000;
|
|
133
|
+
const MEDIA_FETCH_MAX_TIMEOUT_MS = 120_000;
|
|
134
|
+
const MEDIA_FETCH_BASE_TIMEOUT_MS = 30_000;
|
|
135
|
+
const MEDIA_FETCH_PER_50MB_MS = 10_000;
|
|
136
|
+
const ESTIMATED_VIDEO_BYTES_PER_MINUTE = 5 * 1024 * 1024;
|
|
130
137
|
|
|
131
138
|
function clampTimeoutMs(value: number): number {
|
|
132
139
|
return Math.max(
|
|
@@ -154,6 +161,38 @@ export function builderTranscriptionTimeoutMs(
|
|
|
154
161
|
);
|
|
155
162
|
}
|
|
156
163
|
|
|
164
|
+
export function recordingMediaFetchTimeoutMs(
|
|
165
|
+
videoSizeBytes: number | null | undefined,
|
|
166
|
+
durationMs: number | null | undefined,
|
|
167
|
+
): number {
|
|
168
|
+
const override = Number(
|
|
169
|
+
process.env.CLIPS_TRANSCRIPTION_MEDIA_FETCH_TIMEOUT_MS,
|
|
170
|
+
);
|
|
171
|
+
if (Number.isFinite(override) && override > 0) {
|
|
172
|
+
return Math.max(
|
|
173
|
+
MEDIA_FETCH_MIN_TIMEOUT_MS,
|
|
174
|
+
Math.min(MEDIA_FETCH_MAX_TIMEOUT_MS, Math.floor(override)),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const estimatedBytes =
|
|
179
|
+
videoSizeBytes && Number.isFinite(videoSizeBytes) && videoSizeBytes > 0
|
|
180
|
+
? videoSizeBytes
|
|
181
|
+
: durationMs && Number.isFinite(durationMs) && durationMs > 0
|
|
182
|
+
? Math.ceil(durationMs / 60_000) * ESTIMATED_VIDEO_BYTES_PER_MINUTE
|
|
183
|
+
: 0;
|
|
184
|
+
if (!estimatedBytes) return MEDIA_FETCH_MIN_TIMEOUT_MS;
|
|
185
|
+
|
|
186
|
+
const fiftyMbUnits = Math.ceil(estimatedBytes / (50 * 1024 * 1024));
|
|
187
|
+
return Math.max(
|
|
188
|
+
MEDIA_FETCH_MIN_TIMEOUT_MS,
|
|
189
|
+
Math.min(
|
|
190
|
+
MEDIA_FETCH_MAX_TIMEOUT_MS,
|
|
191
|
+
MEDIA_FETCH_BASE_TIMEOUT_MS + fiftyMbUnits * MEDIA_FETCH_PER_50MB_MS,
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
157
196
|
// Bounded automatic retry for transient failures (ffmpeg timeout, transient
|
|
158
197
|
// provider network/5xx errors) — NOT for permanent failures like "no audio
|
|
159
198
|
// track" or a missing/rejected API key. Mirrors the fire-and-forget
|
|
@@ -301,10 +340,12 @@ async function loadRecordingMediaBlob({
|
|
|
301
340
|
recordingId,
|
|
302
341
|
videoUrl,
|
|
303
342
|
fallbackMimeType,
|
|
343
|
+
timeoutMs,
|
|
304
344
|
}: {
|
|
305
345
|
recordingId: string;
|
|
306
346
|
videoUrl: string;
|
|
307
347
|
fallbackMimeType: string;
|
|
348
|
+
timeoutMs: number;
|
|
308
349
|
}): Promise<{ blob: Blob; sourceMimeType: string }> {
|
|
309
350
|
const isLocalBlob =
|
|
310
351
|
videoUrl.startsWith("/api/video/") ||
|
|
@@ -334,10 +375,10 @@ async function loadRecordingMediaBlob({
|
|
|
334
375
|
resolvedVideoUrl = `${origin}${resolvedVideoUrl}`;
|
|
335
376
|
}
|
|
336
377
|
const vidRes = isAppRelativeUrl
|
|
337
|
-
? await fetch(resolvedVideoUrl, { signal: AbortSignal.timeout(
|
|
378
|
+
? await fetch(resolvedVideoUrl, { signal: AbortSignal.timeout(timeoutMs) })
|
|
338
379
|
: await ssrfSafeFetch(
|
|
339
380
|
resolvedVideoUrl,
|
|
340
|
-
{ signal: AbortSignal.timeout(
|
|
381
|
+
{ signal: AbortSignal.timeout(timeoutMs) },
|
|
341
382
|
{ maxRedirects: 3 },
|
|
342
383
|
);
|
|
343
384
|
if (!vidRes.ok) {
|
|
@@ -899,7 +940,7 @@ async function pickProvider(
|
|
|
899
940
|
|
|
900
941
|
const requestTranscriptAction = defineAction({
|
|
901
942
|
description:
|
|
902
|
-
"Ensure a recording has a transcript. Preserves native Web Speech/macOS Speech transcripts
|
|
943
|
+
"Ensure a recording has a transcript, or explicitly regenerate it from the recording media. Preserves native Web Speech/macOS Speech transcripts unless regenerate is true, then uses Builder.io managed transcription or the configured Groq fallback.",
|
|
903
944
|
schema: z.object({
|
|
904
945
|
recordingId: z.string().describe("Recording ID"),
|
|
905
946
|
force: z
|
|
@@ -908,6 +949,12 @@ const requestTranscriptAction = defineAction({
|
|
|
908
949
|
.describe(
|
|
909
950
|
"Bypass the recent pending guard for explicit retries or the finalize-recording background worker.",
|
|
910
951
|
),
|
|
952
|
+
regenerate: z
|
|
953
|
+
.boolean()
|
|
954
|
+
.optional()
|
|
955
|
+
.describe(
|
|
956
|
+
"Generate a fresh transcript from the recording media even when a ready transcript already exists. The existing ready transcript is kept if regeneration fails.",
|
|
957
|
+
),
|
|
911
958
|
retryAttempt: z
|
|
912
959
|
.number()
|
|
913
960
|
.int()
|
|
@@ -918,6 +965,8 @@ const requestTranscriptAction = defineAction({
|
|
|
918
965
|
),
|
|
919
966
|
}),
|
|
920
967
|
run: async (args) => {
|
|
968
|
+
await assertAccess("recording", args.recordingId, "editor");
|
|
969
|
+
|
|
921
970
|
const db = getDb();
|
|
922
971
|
const ownerEmail = getCurrentOwnerEmail();
|
|
923
972
|
const now = new Date().toISOString();
|
|
@@ -944,6 +993,10 @@ const requestTranscriptAction = defineAction({
|
|
|
944
993
|
recordingId: args.recordingId,
|
|
945
994
|
videoUrl,
|
|
946
995
|
fallbackMimeType,
|
|
996
|
+
timeoutMs: recordingMediaFetchTimeoutMs(
|
|
997
|
+
rec.videoSizeBytes,
|
|
998
|
+
rec.durationMs,
|
|
999
|
+
),
|
|
947
1000
|
});
|
|
948
1001
|
return prepareAudioOnlyTranscriptionMedia({
|
|
949
1002
|
blob: media.blob,
|
|
@@ -980,6 +1033,11 @@ const requestTranscriptAction = defineAction({
|
|
|
980
1033
|
// manual retry can still top the budget back up for one more bounded
|
|
981
1034
|
// automatic pass if it fails transiently again.
|
|
982
1035
|
const currentRetryCount = existingNativeTranscript?.retryCount ?? 0;
|
|
1036
|
+
const regeneratingReadyTranscript = Boolean(
|
|
1037
|
+
args.regenerate &&
|
|
1038
|
+
existingNativeTranscript?.status === "ready" &&
|
|
1039
|
+
existingNativeTranscript.fullText?.trim(),
|
|
1040
|
+
);
|
|
983
1041
|
if (args.retryAttempt !== undefined) {
|
|
984
1042
|
console.log(
|
|
985
1043
|
`[clips] auto-retry transcription attempt ${args.retryAttempt} for ${args.recordingId}`,
|
|
@@ -987,6 +1045,7 @@ const requestTranscriptAction = defineAction({
|
|
|
987
1045
|
}
|
|
988
1046
|
|
|
989
1047
|
if (
|
|
1048
|
+
!args.regenerate &&
|
|
990
1049
|
existingNativeTranscript?.status === "ready" &&
|
|
991
1050
|
existingNativeTranscript.fullText?.trim()
|
|
992
1051
|
) {
|
|
@@ -1032,19 +1091,22 @@ const requestTranscriptAction = defineAction({
|
|
|
1032
1091
|
// is set at the deployment level. Use the per-user-aware resolver so
|
|
1033
1092
|
// a sidebar OAuth connection actually wires through to transcription.
|
|
1034
1093
|
if (await resolveHasBuilderPrivateKey()) {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1094
|
+
if (!regeneratingReadyTranscript) {
|
|
1095
|
+
await upsertTranscriptRow(db, {
|
|
1096
|
+
recordingId: args.recordingId,
|
|
1097
|
+
ownerEmail,
|
|
1098
|
+
status: "pending",
|
|
1099
|
+
failureReason: null,
|
|
1100
|
+
now,
|
|
1101
|
+
});
|
|
1102
|
+
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
1103
|
+
}
|
|
1043
1104
|
|
|
1044
1105
|
const [rec] = await db
|
|
1045
1106
|
.select({
|
|
1046
1107
|
videoUrl: schema.recordings.videoUrl,
|
|
1047
1108
|
videoFormat: schema.recordings.videoFormat,
|
|
1109
|
+
videoSizeBytes: schema.recordings.videoSizeBytes,
|
|
1048
1110
|
hasAudio: schema.recordings.hasAudio,
|
|
1049
1111
|
sourceAppName: schema.recordings.sourceAppName,
|
|
1050
1112
|
sourceWindowTitle: schema.recordings.sourceWindowTitle,
|
|
@@ -1121,13 +1183,15 @@ const requestTranscriptAction = defineAction({
|
|
|
1121
1183
|
);
|
|
1122
1184
|
const fullText = normalizedTranscript.fullText;
|
|
1123
1185
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1186
|
+
if (!regeneratingReadyTranscript) {
|
|
1187
|
+
const preserved = await preserveReadyTranscriptIfAvailable({
|
|
1188
|
+
db,
|
|
1189
|
+
recordingId: args.recordingId,
|
|
1190
|
+
ownerEmail,
|
|
1191
|
+
allowLikelyLanguageMismatch: false,
|
|
1192
|
+
});
|
|
1193
|
+
if (preserved) return preserved;
|
|
1194
|
+
}
|
|
1131
1195
|
|
|
1132
1196
|
if (!fullText) {
|
|
1133
1197
|
return failEmptyProviderTranscript({
|
|
@@ -1251,15 +1315,17 @@ const requestTranscriptAction = defineAction({
|
|
|
1251
1315
|
}
|
|
1252
1316
|
|
|
1253
1317
|
// Upsert a pending row so the UI can show "Transcribing…".
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1318
|
+
if (!regeneratingReadyTranscript) {
|
|
1319
|
+
await upsertTranscriptRow(db, {
|
|
1320
|
+
recordingId: args.recordingId,
|
|
1321
|
+
ownerEmail,
|
|
1322
|
+
status: "pending",
|
|
1323
|
+
failureReason: null,
|
|
1324
|
+
now,
|
|
1325
|
+
});
|
|
1261
1326
|
|
|
1262
|
-
|
|
1327
|
+
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
1328
|
+
}
|
|
1263
1329
|
|
|
1264
1330
|
// Load the recording's media URL and prepare audio-only bytes. We never
|
|
1265
1331
|
// send video frames to a transcription provider; screen-only recordings
|
|
@@ -1269,6 +1335,7 @@ const requestTranscriptAction = defineAction({
|
|
|
1269
1335
|
.select({
|
|
1270
1336
|
videoUrl: schema.recordings.videoUrl,
|
|
1271
1337
|
videoFormat: schema.recordings.videoFormat,
|
|
1338
|
+
videoSizeBytes: schema.recordings.videoSizeBytes,
|
|
1272
1339
|
hasAudio: schema.recordings.hasAudio,
|
|
1273
1340
|
sourceAppName: schema.recordings.sourceAppName,
|
|
1274
1341
|
sourceWindowTitle: schema.recordings.sourceWindowTitle,
|
|
@@ -1369,13 +1436,15 @@ const requestTranscriptAction = defineAction({
|
|
|
1369
1436
|
);
|
|
1370
1437
|
const fullText = normalizedTranscript.fullText;
|
|
1371
1438
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1439
|
+
if (!regeneratingReadyTranscript) {
|
|
1440
|
+
const preserved = await preserveReadyTranscriptIfAvailable({
|
|
1441
|
+
db,
|
|
1442
|
+
recordingId: args.recordingId,
|
|
1443
|
+
ownerEmail,
|
|
1444
|
+
allowLikelyLanguageMismatch: false,
|
|
1445
|
+
});
|
|
1446
|
+
if (preserved) return preserved;
|
|
1447
|
+
}
|
|
1379
1448
|
|
|
1380
1449
|
if (!fullText) {
|
|
1381
1450
|
return failEmptyProviderTranscript({
|
|
@@ -253,6 +253,7 @@ export function LibraryGrid({
|
|
|
253
253
|
<ShareRecordingDialog
|
|
254
254
|
recordingId={sharingRec.id}
|
|
255
255
|
recordingTitle={sharingRec.title}
|
|
256
|
+
initialVisibility={sharingRec.visibility}
|
|
256
257
|
open={!!sharingRec}
|
|
257
258
|
onOpenChange={(open) => {
|
|
258
259
|
if (!open) setSharingRec(null);
|
|
@@ -62,6 +62,8 @@ function absoluteAppUrl(path: string): string {
|
|
|
62
62
|
export interface ShareRecordingPopoverProps {
|
|
63
63
|
recordingId: string;
|
|
64
64
|
recordingTitle?: string;
|
|
65
|
+
initialVisibility?: Visibility | null;
|
|
66
|
+
initialRole?: "owner" | "admin" | "editor" | "viewer";
|
|
65
67
|
videoUrl?: string | null;
|
|
66
68
|
animatedThumbnailUrl?: string | null;
|
|
67
69
|
isLoomRecording?: boolean;
|
|
@@ -90,6 +92,8 @@ type ShareRecordingDialogProps = Omit<
|
|
|
90
92
|
export function ShareRecordingPopover({
|
|
91
93
|
recordingId,
|
|
92
94
|
recordingTitle,
|
|
95
|
+
initialVisibility,
|
|
96
|
+
initialRole,
|
|
93
97
|
videoUrl,
|
|
94
98
|
animatedThumbnailUrl,
|
|
95
99
|
isLoomRecording = false,
|
|
@@ -108,6 +112,8 @@ export function ShareRecordingPopover({
|
|
|
108
112
|
<ShareRecordingContent
|
|
109
113
|
recordingId={recordingId}
|
|
110
114
|
recordingTitle={recordingTitle}
|
|
115
|
+
initialVisibility={initialVisibility}
|
|
116
|
+
initialRole={initialRole}
|
|
111
117
|
videoUrl={videoUrl}
|
|
112
118
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
113
119
|
isLoomRecording={isLoomRecording}
|
|
@@ -125,6 +131,8 @@ export function ShareRecordingPopover({
|
|
|
125
131
|
export function ShareRecordingDialog({
|
|
126
132
|
recordingId,
|
|
127
133
|
recordingTitle,
|
|
134
|
+
initialVisibility,
|
|
135
|
+
initialRole,
|
|
128
136
|
videoUrl,
|
|
129
137
|
animatedThumbnailUrl,
|
|
130
138
|
isLoomRecording = false,
|
|
@@ -143,6 +151,8 @@ export function ShareRecordingDialog({
|
|
|
143
151
|
<ShareRecordingContent
|
|
144
152
|
recordingId={recordingId}
|
|
145
153
|
recordingTitle={recordingTitle}
|
|
154
|
+
initialVisibility={initialVisibility}
|
|
155
|
+
initialRole={initialRole}
|
|
146
156
|
videoUrl={videoUrl}
|
|
147
157
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
148
158
|
isLoomRecording={isLoomRecording}
|
|
@@ -156,6 +166,8 @@ export function ShareRecordingDialog({
|
|
|
156
166
|
function ShareRecordingContent({
|
|
157
167
|
recordingId,
|
|
158
168
|
recordingTitle,
|
|
169
|
+
initialVisibility,
|
|
170
|
+
initialRole,
|
|
159
171
|
videoUrl,
|
|
160
172
|
animatedThumbnailUrl,
|
|
161
173
|
isLoomRecording = false,
|
|
@@ -163,6 +175,8 @@ function ShareRecordingContent({
|
|
|
163
175
|
}: {
|
|
164
176
|
recordingId: string;
|
|
165
177
|
recordingTitle?: string;
|
|
178
|
+
initialVisibility?: Visibility | null;
|
|
179
|
+
initialRole?: "owner" | "admin" | "editor" | "viewer";
|
|
166
180
|
videoUrl?: string | null;
|
|
167
181
|
animatedThumbnailUrl?: string | null;
|
|
168
182
|
isLoomRecording?: boolean;
|
|
@@ -175,7 +189,12 @@ function ShareRecordingContent({
|
|
|
175
189
|
});
|
|
176
190
|
|
|
177
191
|
const data = sharesQuery.data;
|
|
178
|
-
const
|
|
192
|
+
const role = data?.role ?? initialRole;
|
|
193
|
+
const canManage = role === "owner" || role === "admin";
|
|
194
|
+
const visibility =
|
|
195
|
+
(data?.visibility as Visibility | null | undefined) ??
|
|
196
|
+
initialVisibility ??
|
|
197
|
+
null;
|
|
179
198
|
|
|
180
199
|
// Attribution `via` must be a stable non-PII id, never an email. The only
|
|
181
200
|
// owner id available client-side is the *current* session's userId, which is
|
|
@@ -226,6 +245,7 @@ function ShareRecordingContent({
|
|
|
226
245
|
recordingId={recordingId}
|
|
227
246
|
shareUrl={shareUrl}
|
|
228
247
|
sharesQuery={sharesQuery}
|
|
248
|
+
visibility={visibility}
|
|
229
249
|
canManage={canManage}
|
|
230
250
|
videoUrl={videoUrl}
|
|
231
251
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
@@ -247,6 +267,7 @@ function ShareRecordingContent({
|
|
|
247
267
|
<ClipsEmbedConfigurator
|
|
248
268
|
recordingId={recordingId}
|
|
249
269
|
sharesQuery={sharesQuery}
|
|
270
|
+
visibility={visibility}
|
|
250
271
|
canManage={canManage}
|
|
251
272
|
ownerViaId={ownerViaId}
|
|
252
273
|
/>
|
|
@@ -264,6 +285,7 @@ function LinkTab({
|
|
|
264
285
|
recordingId,
|
|
265
286
|
shareUrl,
|
|
266
287
|
sharesQuery,
|
|
288
|
+
visibility,
|
|
267
289
|
canManage,
|
|
268
290
|
videoUrl,
|
|
269
291
|
animatedThumbnailUrl,
|
|
@@ -272,6 +294,7 @@ function LinkTab({
|
|
|
272
294
|
recordingId: string;
|
|
273
295
|
shareUrl: string;
|
|
274
296
|
sharesQuery: SharesQuery;
|
|
297
|
+
visibility: Visibility | null;
|
|
275
298
|
canManage: boolean;
|
|
276
299
|
videoUrl?: string | null;
|
|
277
300
|
animatedThumbnailUrl?: string | null;
|
|
@@ -283,11 +306,9 @@ function LinkTab({
|
|
|
283
306
|
recordingId,
|
|
284
307
|
sharesQuery,
|
|
285
308
|
);
|
|
286
|
-
const data = sharesQuery.data;
|
|
287
|
-
const visibility: Visibility =
|
|
288
|
-
(data?.visibility as Visibility | null) ?? "private";
|
|
289
309
|
const isPublic = visibility === "public";
|
|
290
|
-
const sharesLoaded =
|
|
310
|
+
const sharesLoaded = visibility !== null;
|
|
311
|
+
const visibilityPending = isPending || sharesQuery.isLoading;
|
|
291
312
|
const isLoomRecording = isLoomRecordingProp || isLoomEmbedUrl(videoUrl);
|
|
292
313
|
const createAgentLink = useActionMutation(
|
|
293
314
|
"create-recording-agent-link" as any,
|
|
@@ -355,25 +376,34 @@ function LinkTab({
|
|
|
355
376
|
|
|
356
377
|
return (
|
|
357
378
|
<div className="space-y-4">
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
379
|
+
{visibility ? (
|
|
380
|
+
<GeneralAccessSelect
|
|
381
|
+
visibility={visibility}
|
|
382
|
+
canManage={canManage}
|
|
383
|
+
isPending={visibilityPending}
|
|
384
|
+
onChange={(next) => setResourceVisibility(next)}
|
|
385
|
+
publicDescription={t("shareDialog.publicDescription")}
|
|
386
|
+
/>
|
|
387
|
+
) : (
|
|
388
|
+
<div className="space-y-2" aria-hidden>
|
|
389
|
+
<div className="h-3 w-24 animate-pulse rounded bg-muted" />
|
|
390
|
+
<div className="h-12 w-full animate-pulse rounded bg-muted" />
|
|
391
|
+
</div>
|
|
392
|
+
)}
|
|
365
393
|
|
|
366
394
|
<CopyField
|
|
367
395
|
label={t("shareDialog.shareLink")}
|
|
368
396
|
value={shareUrl}
|
|
369
|
-
disabled={
|
|
397
|
+
disabled={
|
|
398
|
+
visibilityPending || !sharesLoaded || (!isPublic && canManage)
|
|
399
|
+
}
|
|
370
400
|
/>
|
|
371
401
|
|
|
372
402
|
{/* Public links unfurl into a playable video in Slack; surface that here
|
|
373
403
|
(and a connect link) instead of leaving it buried in Settings. */}
|
|
374
404
|
{isPublic ? <SlackShareHint canManage={canManage} /> : null}
|
|
375
405
|
|
|
376
|
-
{!isPublic ? (
|
|
406
|
+
{sharesLoaded && !isPublic ? (
|
|
377
407
|
<Collapsible open={agentShareOpen} onOpenChange={setAgentShareOpen}>
|
|
378
408
|
<CollapsibleTrigger asChild>
|
|
379
409
|
<Button
|
|
@@ -431,7 +461,7 @@ function LinkTab({
|
|
|
431
461
|
</Collapsible>
|
|
432
462
|
) : null}
|
|
433
463
|
|
|
434
|
-
{!isPublic && canManage ? (
|
|
464
|
+
{sharesLoaded && !isPublic && canManage ? (
|
|
435
465
|
<MakePublicCard
|
|
436
466
|
isPending={isPending}
|
|
437
467
|
onMakePublic={() =>
|
|
@@ -485,11 +515,13 @@ function LinkTab({
|
|
|
485
515
|
function ClipsEmbedConfigurator({
|
|
486
516
|
recordingId,
|
|
487
517
|
sharesQuery,
|
|
518
|
+
visibility,
|
|
488
519
|
canManage,
|
|
489
520
|
ownerViaId,
|
|
490
521
|
}: {
|
|
491
522
|
recordingId: string;
|
|
492
523
|
sharesQuery: SharesQuery;
|
|
524
|
+
visibility: Visibility | null;
|
|
493
525
|
canManage: boolean;
|
|
494
526
|
ownerViaId?: string;
|
|
495
527
|
}) {
|
|
@@ -500,11 +532,10 @@ function ClipsEmbedConfigurator({
|
|
|
500
532
|
const [width, setWidth] = useState(640);
|
|
501
533
|
const [height, setHeight] = useState(360);
|
|
502
534
|
|
|
503
|
-
const data = sharesQuery.data;
|
|
504
|
-
const visibility: Visibility =
|
|
505
|
-
(data?.visibility as Visibility | null) ?? "private";
|
|
506
535
|
const isPublic = visibility === "public";
|
|
507
|
-
const visibilityLabel =
|
|
536
|
+
const visibilityLabel = visibility
|
|
537
|
+
? t(`shareUi.visibility.${visibility}.label`)
|
|
538
|
+
: "";
|
|
508
539
|
const { setResourceVisibility, isPending } = useResourceVisibilityMutation(
|
|
509
540
|
"recording",
|
|
510
541
|
recordingId,
|
|
@@ -529,6 +560,15 @@ function ClipsEmbedConfigurator({
|
|
|
529
560
|
? `<div style="position:relative;padding-bottom:56.25%;height:0;background:#000;overflow:hidden"><iframe src="${src}" title="${t("shareDialog.embedIframeTitle")}" frameborder="0" scrolling="no" allowfullscreen allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;inset:0;width:100%;height:100%;border:0;background:#000;overflow:hidden"></iframe></div>`
|
|
530
561
|
: `<iframe src="${src}" title="${t("shareDialog.embedIframeTitle")}" width="${width}" height="${height}" frameborder="0" scrolling="no" allowfullscreen allow="autoplay; fullscreen; picture-in-picture" style="display:block;max-width:100%;border:0;background:#000;overflow:hidden"></iframe>`;
|
|
531
562
|
|
|
563
|
+
if (!visibility) {
|
|
564
|
+
return (
|
|
565
|
+
<div className="space-y-2" aria-hidden>
|
|
566
|
+
<div className="h-16 w-full animate-pulse rounded bg-muted" />
|
|
567
|
+
<div className="h-24 w-full animate-pulse rounded bg-muted" />
|
|
568
|
+
</div>
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
532
572
|
return (
|
|
533
573
|
<div className="space-y-3">
|
|
534
574
|
{!isPublic ? (
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
IconBolt,
|
|
20
20
|
IconChevronDown,
|
|
21
21
|
IconChevronUp,
|
|
22
|
+
IconRefresh,
|
|
22
23
|
} from "@tabler/icons-react";
|
|
23
24
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
24
25
|
|
|
@@ -56,6 +57,9 @@ export interface TranscriptPanelProps {
|
|
|
56
57
|
recordingTitle?: string;
|
|
57
58
|
/** Called when the user asks us to retry transcription after fixing an error. */
|
|
58
59
|
onRetry?: () => void;
|
|
60
|
+
/** Called when the user asks for a fresh transcript from the recording media. */
|
|
61
|
+
onRegenerate?: () => void;
|
|
62
|
+
isRegenerating?: boolean;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
export function TranscriptPanel(props: TranscriptPanelProps) {
|
|
@@ -71,6 +75,8 @@ export function TranscriptPanel(props: TranscriptPanelProps) {
|
|
|
71
75
|
cleanup,
|
|
72
76
|
recordingTitle,
|
|
73
77
|
onRetry,
|
|
78
|
+
onRegenerate,
|
|
79
|
+
isRegenerating = false,
|
|
74
80
|
} = props;
|
|
75
81
|
const [query, setQuery] = useState("");
|
|
76
82
|
const [copied, setCopied] = useState(false);
|
|
@@ -170,8 +176,18 @@ export function TranscriptPanel(props: TranscriptPanelProps) {
|
|
|
170
176
|
</p>
|
|
171
177
|
</div>
|
|
172
178
|
{onRetry ? (
|
|
173
|
-
<Button
|
|
174
|
-
|
|
179
|
+
<Button
|
|
180
|
+
size="sm"
|
|
181
|
+
variant="outline"
|
|
182
|
+
onClick={onRetry}
|
|
183
|
+
disabled={isRegenerating}
|
|
184
|
+
>
|
|
185
|
+
{isRegenerating ? (
|
|
186
|
+
<IconLoader2 className="size-4 animate-spin" />
|
|
187
|
+
) : null}
|
|
188
|
+
{isRegenerating
|
|
189
|
+
? t("transcriptPanel.transcribing")
|
|
190
|
+
: t("transcriptPanel.regenerate")}
|
|
175
191
|
</Button>
|
|
176
192
|
) : null}
|
|
177
193
|
</div>
|
|
@@ -188,8 +204,18 @@ export function TranscriptPanel(props: TranscriptPanelProps) {
|
|
|
188
204
|
</div>
|
|
189
205
|
<div className="flex items-center gap-2">
|
|
190
206
|
{onRetry ? (
|
|
191
|
-
<Button
|
|
192
|
-
|
|
207
|
+
<Button
|
|
208
|
+
size="sm"
|
|
209
|
+
variant="outline"
|
|
210
|
+
onClick={onRetry}
|
|
211
|
+
disabled={isRegenerating}
|
|
212
|
+
>
|
|
213
|
+
{isRegenerating ? (
|
|
214
|
+
<IconLoader2 className="size-4 animate-spin" />
|
|
215
|
+
) : null}
|
|
216
|
+
{isRegenerating
|
|
217
|
+
? t("transcriptPanel.transcribing")
|
|
218
|
+
: t("transcriptPanel.regenerate")}
|
|
193
219
|
</Button>
|
|
194
220
|
) : null}
|
|
195
221
|
</div>
|
|
@@ -229,6 +255,24 @@ export function TranscriptPanel(props: TranscriptPanelProps) {
|
|
|
229
255
|
</TooltipTrigger>
|
|
230
256
|
<TooltipContent>{t("transcriptPanel.downloadSrt")}</TooltipContent>
|
|
231
257
|
</Tooltip>
|
|
258
|
+
{onRegenerate ? (
|
|
259
|
+
<Tooltip>
|
|
260
|
+
<TooltipTrigger asChild>
|
|
261
|
+
<Button
|
|
262
|
+
variant="ghost"
|
|
263
|
+
size="icon"
|
|
264
|
+
onClick={onRegenerate}
|
|
265
|
+
disabled={isRegenerating}
|
|
266
|
+
aria-label={t("transcriptPanel.regenerate")}
|
|
267
|
+
>
|
|
268
|
+
<IconRefresh
|
|
269
|
+
className={cn("h-4 w-4", isRegenerating && "animate-spin")}
|
|
270
|
+
/>
|
|
271
|
+
</Button>
|
|
272
|
+
</TooltipTrigger>
|
|
273
|
+
<TooltipContent>{t("transcriptPanel.regenerate")}</TooltipContent>
|
|
274
|
+
</Tooltip>
|
|
275
|
+
) : null}
|
|
232
276
|
</div>
|
|
233
277
|
|
|
234
278
|
{cleanup?.status === "running" ? (
|
|
@@ -563,16 +563,21 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
563
563
|
requestPlay();
|
|
564
564
|
}, [isPlaying, pauseVideo, requestPlay]);
|
|
565
565
|
|
|
566
|
-
const activateVideoSurface = useCallback(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
566
|
+
const activateVideoSurface = useCallback(
|
|
567
|
+
(input: "mouse" | "touch") => {
|
|
568
|
+
// Match native mobile players: touching the video reveals the controls
|
|
569
|
+
// without unexpectedly pausing or resuming it. Embeds that explicitly
|
|
570
|
+
// hide their chrome keep surface-tap playback so they remain usable.
|
|
571
|
+
if (input === "touch" && !hideChrome) {
|
|
572
|
+
bumpControls();
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
togglePlayback();
|
|
577
|
+
bumpControls();
|
|
578
|
+
},
|
|
579
|
+
[bumpControls, hideChrome, togglePlayback],
|
|
580
|
+
);
|
|
576
581
|
|
|
577
582
|
const handlePlayerPointerDown = useCallback(
|
|
578
583
|
(e: React.PointerEvent<HTMLDivElement>) => {
|
|
@@ -610,7 +615,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
610
615
|
|
|
611
616
|
e.preventDefault();
|
|
612
617
|
suppressNextClickRef.current = true;
|
|
613
|
-
activateVideoSurface();
|
|
618
|
+
activateVideoSurface("touch");
|
|
614
619
|
},
|
|
615
620
|
[activateVideoSurface, isLoomEmbed],
|
|
616
621
|
);
|
|
@@ -1115,7 +1120,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1115
1120
|
// keep their own behavior.
|
|
1116
1121
|
if (isPlayerUiTarget(e.target)) return;
|
|
1117
1122
|
if (isLoomEmbed) return;
|
|
1118
|
-
activateVideoSurface();
|
|
1123
|
+
activateVideoSurface("mouse");
|
|
1119
1124
|
}}
|
|
1120
1125
|
>
|
|
1121
1126
|
{isLoomEmbed && loomIframeSrc ? (
|
|
@@ -379,6 +379,7 @@ const messages = {
|
|
|
379
379
|
searchPlaceholder: "نص البحث",
|
|
380
380
|
copyTranscript: "نسخ النص",
|
|
381
381
|
downloadSrt: "تحميل .srt",
|
|
382
|
+
regenerate: "إعادة إنشاء النص",
|
|
382
383
|
cleanupRunning: "تنظيف النص في الخلفية.",
|
|
383
384
|
noMatches: "لا توجد مباريات.",
|
|
384
385
|
noTranscript: "لا يوجد نسخة بعد.",
|
|
@@ -388,6 +388,7 @@ const messages = {
|
|
|
388
388
|
searchPlaceholder: "Transkript durchsuchen",
|
|
389
389
|
copyTranscript: "Transkript kopieren",
|
|
390
390
|
downloadSrt: "Laden Sie .srt herunter",
|
|
391
|
+
regenerate: "Transkript neu erstellen",
|
|
391
392
|
cleanupRunning: "Bereinigen des Transkripts im Hintergrund.",
|
|
392
393
|
noMatches: "Keine Übereinstimmungen.",
|
|
393
394
|
noTranscript: "Noch kein Transkript.",
|
|
@@ -373,6 +373,7 @@ const messages = {
|
|
|
373
373
|
searchPlaceholder: "Search transcript",
|
|
374
374
|
copyTranscript: "Copy transcript",
|
|
375
375
|
downloadSrt: "Download .srt",
|
|
376
|
+
regenerate: "Regenerate transcript",
|
|
376
377
|
cleanupRunning: "Cleaning up transcript in the background.",
|
|
377
378
|
noMatches: "No matches.",
|
|
378
379
|
noTranscript: "No transcript yet.",
|
|
@@ -386,6 +386,7 @@ const messages = {
|
|
|
386
386
|
searchPlaceholder: "Transcripción de búsqueda",
|
|
387
387
|
copyTranscript: "Copiar transcripción",
|
|
388
388
|
downloadSrt: "Descargar .srt",
|
|
389
|
+
regenerate: "Regenerar transcripción",
|
|
389
390
|
cleanupRunning: "Limpiando la transcripción en segundo plano.",
|
|
390
391
|
noMatches: "Sin coincidencias.",
|
|
391
392
|
noTranscript: "Aún no hay transcripción.",
|
|
@@ -386,6 +386,7 @@ const messages = {
|
|
|
386
386
|
searchPlaceholder: "Rechercher la transcription",
|
|
387
387
|
copyTranscript: "Copier la transcription",
|
|
388
388
|
downloadSrt: "Télécharger .srt",
|
|
389
|
+
regenerate: "Régénérer la transcription",
|
|
389
390
|
cleanupRunning: "Nettoyage de la transcription en arrière-plan.",
|
|
390
391
|
noMatches: "Aucun match.",
|
|
391
392
|
noTranscript: "Pas encore de transcription.",
|