@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
|
@@ -579,7 +579,10 @@ class CollabDocConnection {
|
|
|
579
579
|
this.awareness.setLocalStateField("visible", !isDocumentHidden());
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
-
private handleAwarenessChange = (
|
|
582
|
+
private handleAwarenessChange = (
|
|
583
|
+
_changes?: { added: number[]; updated: number[]; removed: number[] },
|
|
584
|
+
origin?: unknown,
|
|
585
|
+
): void => {
|
|
583
586
|
const users: CollabUser[] = [];
|
|
584
587
|
let hasAgent = false;
|
|
585
588
|
this.awareness.getStates().forEach((state, clientId) => {
|
|
@@ -616,12 +619,20 @@ class CollabDocConnection {
|
|
|
616
619
|
this.setSnapshot({ activeUsers, agentPresent: hasAgent });
|
|
617
620
|
}
|
|
618
621
|
|
|
619
|
-
// Fast awareness push: whenever awareness changes (e.g.
|
|
620
|
-
// setPresence() calls), schedule a throttled POST so peers
|
|
621
|
-
// at ~150ms instead of waiting for the next poll cycle.
|
|
622
|
+
// Fast awareness push: whenever OUR OWN awareness state changes (e.g.
|
|
623
|
+
// cursor moves, setPresence() calls), schedule a throttled POST so peers
|
|
624
|
+
// receive updates at ~150ms instead of waiting for the next poll cycle.
|
|
625
|
+
// Gated on origin === "local": this listener also fires for remote
|
|
626
|
+
// awareness changes (poll/SSE call `awareness.emit("change", [changes,
|
|
627
|
+
// "remote"])` after reconciling incoming states — see
|
|
628
|
+
// applyAwarenessEvent/poll above). Without the origin check, every
|
|
629
|
+
// peer's cursor move would also re-trigger THIS client to re-broadcast
|
|
630
|
+
// its own unchanged state, turning one person moving their mouse into
|
|
631
|
+
// O(n) redundant POSTs from every other connected client (an awareness
|
|
632
|
+
// storm that gets worse as more people join the doc). Only active once a
|
|
622
633
|
// local user identity has been published (matches the previous per-hook
|
|
623
634
|
// gating on `user`). The poll cycle remains the authoritative baseline.
|
|
624
|
-
if (this.lastSetUser && !this.disposed) {
|
|
635
|
+
if (this.lastSetUser && origin === "local" && !this.disposed) {
|
|
625
636
|
scheduleAwarenessPush(
|
|
626
637
|
this.baseUrl,
|
|
627
638
|
this.docId,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
RECENT_EDIT_TTL_MS,
|
|
22
22
|
type AttributedRecentEdit,
|
|
23
23
|
type RecentEdit,
|
|
24
|
+
type RecentEditDescriptor,
|
|
24
25
|
} from "@agent-native/toolkit/collab-ui";
|
|
25
26
|
import { useEffect, useRef, useState } from "react";
|
|
26
27
|
|
|
@@ -34,16 +35,78 @@ export {
|
|
|
34
35
|
type RecentEditDescriptor,
|
|
35
36
|
} from "@agent-native/toolkit/collab-ui";
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Hard cap on any single string carried in a recentEdits entry (quote,
|
|
40
|
+
* selector, path segment, label). Callers are expected to pass short
|
|
41
|
+
* excerpts already (existing call sites trim to 80–120 chars for a "what
|
|
42
|
+
* changed" snippet), but this is the ring's own size ceiling — a caller that
|
|
43
|
+
* forgets to trim (e.g. passing a whole paragraph/document as `quote`) must
|
|
44
|
+
* not blow up the awareness payload every connected client receives on the
|
|
45
|
+
* fast-push path, nor the `_collab_awareness` SQL row it gets mirrored into.
|
|
46
|
+
*/
|
|
47
|
+
const RECENT_EDIT_STRING_MAX = 500;
|
|
48
|
+
|
|
49
|
+
function truncateString(value: string): string {
|
|
50
|
+
return value.length > RECENT_EDIT_STRING_MAX
|
|
51
|
+
? value.slice(0, RECENT_EDIT_STRING_MAX)
|
|
52
|
+
: value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function truncateDescriptor(
|
|
56
|
+
descriptor: RecentEditDescriptor,
|
|
57
|
+
): RecentEditDescriptor {
|
|
58
|
+
// The union's last member (`{ kind: string; [key: string]: unknown }`) is an
|
|
59
|
+
// open-ended catch-all whose `kind` is a plain `string`, so a `switch` on
|
|
60
|
+
// `descriptor.kind` can't discriminate it away from the literal-kind
|
|
61
|
+
// members for the compiler — every property still type-checks as
|
|
62
|
+
// `unknown`. Read/write through an untyped view instead and lean on
|
|
63
|
+
// runtime checks; the return value is cast back to the real type below.
|
|
64
|
+
const d = descriptor as Record<string, unknown> & { kind: string };
|
|
65
|
+
if (d.kind === "text" && typeof d.quote === "string") {
|
|
66
|
+
return { ...d, quote: truncateString(d.quote) } as RecentEditDescriptor;
|
|
67
|
+
}
|
|
68
|
+
if (d.kind === "selector" && typeof d.selector === "string") {
|
|
69
|
+
return {
|
|
70
|
+
...d,
|
|
71
|
+
selector: truncateString(d.selector),
|
|
72
|
+
} as RecentEditDescriptor;
|
|
73
|
+
}
|
|
74
|
+
if (d.kind === "paths" && Array.isArray(d.paths)) {
|
|
75
|
+
return {
|
|
76
|
+
...d,
|
|
77
|
+
paths: d.paths.map((p) =>
|
|
78
|
+
typeof p === "string" ? truncateString(p) : p,
|
|
79
|
+
),
|
|
80
|
+
} as RecentEditDescriptor;
|
|
81
|
+
}
|
|
82
|
+
if (d.kind === "doc") {
|
|
83
|
+
return descriptor;
|
|
84
|
+
}
|
|
85
|
+
// Open-ended shape — trim any string-valued fields defensively without
|
|
86
|
+
// knowing their names.
|
|
87
|
+
const trimmed: Record<string, unknown> = {};
|
|
88
|
+
for (const [key, value] of Object.entries(d)) {
|
|
89
|
+
trimmed[key] = typeof value === "string" ? truncateString(value) : value;
|
|
90
|
+
}
|
|
91
|
+
return trimmed as RecentEditDescriptor;
|
|
92
|
+
}
|
|
93
|
+
|
|
37
94
|
/**
|
|
38
95
|
* Append an edit to a recentEdits ring, keeping the newest
|
|
39
|
-
* {@link RECENT_EDITS_MAX} entries. Pure — returns a new array.
|
|
96
|
+
* {@link RECENT_EDITS_MAX} entries. Pure — returns a new array. Descriptor
|
|
97
|
+
* strings and the label are truncated to {@link RECENT_EDIT_STRING_MAX}
|
|
98
|
+
* characters as a defensive cap on the awareness payload size.
|
|
40
99
|
*/
|
|
41
100
|
export function appendRecentEdit(
|
|
42
101
|
existing: RecentEdit[] | undefined,
|
|
43
102
|
edit: RecentEdit,
|
|
44
103
|
): RecentEdit[] {
|
|
45
104
|
const ring = Array.isArray(existing) ? existing.slice() : [];
|
|
46
|
-
ring.push(
|
|
105
|
+
ring.push({
|
|
106
|
+
...edit,
|
|
107
|
+
descriptor: truncateDescriptor(edit.descriptor),
|
|
108
|
+
label: edit.label ? truncateString(edit.label) : edit.label,
|
|
109
|
+
});
|
|
47
110
|
if (ring.length > RECENT_EDITS_MAX) {
|
|
48
111
|
ring.splice(0, ring.length - RECENT_EDITS_MAX);
|
|
49
112
|
}
|
|
@@ -2437,6 +2437,90 @@ export const config = {
|
|
|
2437
2437
|
const NETLIFY_DEFAULT_FUNCTION_URL_REDIRECT =
|
|
2438
2438
|
"/* /.netlify/functions/server 200";
|
|
2439
2439
|
|
|
2440
|
+
function hasBareYjsRuntimeImport(source: string): boolean {
|
|
2441
|
+
return /\b(?:from\s*|import\s*\(\s*|import\s*)["']yjs(?:\/[^"']*)?["']/.test(
|
|
2442
|
+
source,
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
function hasUnsupportedYjsSubpathImport(source: string): boolean {
|
|
2447
|
+
return /\b(?:from\s*|import\s*\(\s*|import\s*)["']yjs\/[^"']*["']/.test(
|
|
2448
|
+
source,
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
function walkServerJavaScriptFiles(
|
|
2453
|
+
dir: string,
|
|
2454
|
+
onFile: (filePath: string) => void,
|
|
2455
|
+
): void {
|
|
2456
|
+
if (!fs.existsSync(dir)) return;
|
|
2457
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
2458
|
+
const entryPath = path.join(dir, entry.name);
|
|
2459
|
+
if (entry.isDirectory()) {
|
|
2460
|
+
walkServerJavaScriptFiles(entryPath, onFile);
|
|
2461
|
+
continue;
|
|
2462
|
+
}
|
|
2463
|
+
if (/\.(?:[cm]?js)$/.test(entry.name)) onFile(entryPath);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
/**
|
|
2468
|
+
* Nitro can preserve Vite's `yjs` external in a split server chunk even when
|
|
2469
|
+
* its own server build has emitted `_libs/yjs.mjs`. Netlify does not install
|
|
2470
|
+
* that bare package at runtime, so make every emitted server chunk use the
|
|
2471
|
+
* bundled copy before its function is packaged.
|
|
2472
|
+
*/
|
|
2473
|
+
export function rewriteBareYjsImportsForServerlessOutput(
|
|
2474
|
+
serverDir: string,
|
|
2475
|
+
): string[] {
|
|
2476
|
+
const bareImports: string[] = [];
|
|
2477
|
+
const unsupportedSubpathImports: string[] = [];
|
|
2478
|
+
const bundledYjsPath = path.join(serverDir, "_libs", "yjs.mjs");
|
|
2479
|
+
|
|
2480
|
+
walkServerJavaScriptFiles(serverDir, (filePath) => {
|
|
2481
|
+
const source = fs.readFileSync(filePath, "utf-8");
|
|
2482
|
+
if (!hasBareYjsRuntimeImport(source)) return;
|
|
2483
|
+
if (hasUnsupportedYjsSubpathImport(source)) {
|
|
2484
|
+
unsupportedSubpathImports.push(filePath);
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
bareImports.push(filePath);
|
|
2488
|
+
});
|
|
2489
|
+
|
|
2490
|
+
if (unsupportedSubpathImports.length > 0) {
|
|
2491
|
+
throw new Error(
|
|
2492
|
+
`[deploy] Serverless output left unsupported yjs subpath imports in ${unsupportedSubpathImports.join(", ")}`,
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
if (bareImports.length === 0) return [];
|
|
2496
|
+
if (!fs.existsSync(bundledYjsPath)) {
|
|
2497
|
+
throw new Error(
|
|
2498
|
+
`[deploy] Serverless output left yjs as a runtime import but did not emit ${bundledYjsPath}`,
|
|
2499
|
+
);
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
for (const filePath of bareImports) {
|
|
2503
|
+
const bundledImport = path
|
|
2504
|
+
.relative(path.dirname(filePath), bundledYjsPath)
|
|
2505
|
+
.split(path.sep)
|
|
2506
|
+
.join("/");
|
|
2507
|
+
const relativeBundledImport = bundledImport.startsWith(".")
|
|
2508
|
+
? bundledImport
|
|
2509
|
+
: `./${bundledImport}`;
|
|
2510
|
+
const source = fs.readFileSync(filePath, "utf-8");
|
|
2511
|
+
fs.writeFileSync(
|
|
2512
|
+
filePath,
|
|
2513
|
+
source.replace(
|
|
2514
|
+
/(\b(?:from\s*|import\s*\(\s*|import\s*))(["'])yjs\2/g,
|
|
2515
|
+
(_match, importPrefix: string, quote: string) =>
|
|
2516
|
+
`${importPrefix}${quote}${relativeBundledImport}${quote}`,
|
|
2517
|
+
),
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
return bareImports;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2440
2524
|
export function assertSingleTemplateNetlifyBuildOutput(
|
|
2441
2525
|
projectCwd: string,
|
|
2442
2526
|
): void {
|
|
@@ -2519,6 +2603,23 @@ export function assertSingleTemplateNetlifyBuildOutput(
|
|
|
2519
2603
|
}
|
|
2520
2604
|
}
|
|
2521
2605
|
|
|
2606
|
+
// Netlify's function packager does not install arbitrary runtime package
|
|
2607
|
+
// imports left in Nitro chunks. A bare Yjs import here would deploy
|
|
2608
|
+
// successfully but fail on the first SSR request with ERR_MODULE_NOT_FOUND.
|
|
2609
|
+
// Keep this check adjacent to the output guard so both local builds and CI
|
|
2610
|
+
// reject that artifact before it reaches Netlify.
|
|
2611
|
+
const bareYjsImports: string[] = [];
|
|
2612
|
+
walkServerJavaScriptFiles(serverDir, (filePath) => {
|
|
2613
|
+
if (hasBareYjsRuntimeImport(fs.readFileSync(filePath, "utf-8"))) {
|
|
2614
|
+
bareYjsImports.push(path.relative(projectCwd, filePath));
|
|
2615
|
+
}
|
|
2616
|
+
});
|
|
2617
|
+
if (bareYjsImports.length > 0) {
|
|
2618
|
+
failures.push(
|
|
2619
|
+
`Netlify server bundle leaves yjs as a runtime import: ${bareYjsImports.join(", ")}`,
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2522
2623
|
if (isDurableBackgroundDeployEnabled()) {
|
|
2523
2624
|
const backgroundDir = path.join(
|
|
2524
2625
|
internalDir,
|
|
@@ -2969,6 +3070,32 @@ const BROWSER_ONLY_SERVER_LIBS = [
|
|
|
2969
3070
|
"mermaid",
|
|
2970
3071
|
];
|
|
2971
3072
|
|
|
3073
|
+
/**
|
|
3074
|
+
* Dependencies that must be bundled into every Nitro server output instead of
|
|
3075
|
+
* being left as runtime package imports.
|
|
3076
|
+
*
|
|
3077
|
+
* `yjs` is a direct core dependency, but it is deliberately externalized from
|
|
3078
|
+
* the intermediate Vite SSR graph so that Vite and Nitro do not create two
|
|
3079
|
+
* incompatible Yjs constructors. On file-traced serverless presets, leaving it
|
|
3080
|
+
* external at Nitro's final build can emit `import "yjs"` into a function
|
|
3081
|
+
* chunk without placing the package in that function's `node_modules`. Bundle
|
|
3082
|
+
* it in Nitro's final output so every template receives the one portable copy.
|
|
3083
|
+
*/
|
|
3084
|
+
export const NITRO_SERVER_RUNTIME_BUNDLED_DEPS = ["yjs"] as const;
|
|
3085
|
+
|
|
3086
|
+
/**
|
|
3087
|
+
* Edge runtimes have no node_modules, while Node/serverless outputs only need
|
|
3088
|
+
* the small set above bundled to keep their package manifests traceable.
|
|
3089
|
+
*/
|
|
3090
|
+
export function nitroNoExternalsForPreset(
|
|
3091
|
+
targetPreset: string,
|
|
3092
|
+
): true | readonly string[] {
|
|
3093
|
+
return targetPreset.startsWith("cloudflare") ||
|
|
3094
|
+
targetPreset.startsWith("deno")
|
|
3095
|
+
? true
|
|
3096
|
+
: NITRO_SERVER_RUNTIME_BUNDLED_DEPS;
|
|
3097
|
+
}
|
|
3098
|
+
|
|
2972
3099
|
/**
|
|
2973
3100
|
* Rolldown plugin for the Nitro server bundle that replaces the browser-only
|
|
2974
3101
|
* renderers above with an inert proxy module.
|
|
@@ -3124,11 +3251,11 @@ export default bundle;
|
|
|
3124
3251
|
? { plugins: [providedPluginsNitroPlugin] }
|
|
3125
3252
|
: {}),
|
|
3126
3253
|
routeRules: mcpEmbedStaticAssetRouteRules(appBasePath),
|
|
3127
|
-
//
|
|
3128
|
-
//
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3254
|
+
// Edge presets (cloudflare, deno) bundle all deps because node_modules are
|
|
3255
|
+
// unavailable at runtime. Node/serverless presets also bundle Yjs: Nitro's
|
|
3256
|
+
// file tracer otherwise leaves a bare import that Netlify function bundles
|
|
3257
|
+
// cannot resolve under pnpm.
|
|
3258
|
+
noExternals: nitroNoExternalsForPreset(preset),
|
|
3132
3259
|
} as any);
|
|
3133
3260
|
|
|
3134
3261
|
await runNitroBuildPipeline({
|
|
@@ -3145,6 +3272,7 @@ export default bundle;
|
|
|
3145
3272
|
copyInstalledResvgPackages(nitro.options.output.serverDir);
|
|
3146
3273
|
copyInstalledFfmpegStaticPackage(nitro.options.output.serverDir);
|
|
3147
3274
|
sanitizeServerlessFunctionPackageManifest(nitro.options.output.serverDir);
|
|
3275
|
+
rewriteBareYjsImportsForServerlessOutput(nitro.options.output.serverDir);
|
|
3148
3276
|
}
|
|
3149
3277
|
|
|
3150
3278
|
// Durable background agent runs (default-OFF / opt-in; enable with a truthy
|
|
@@ -8561,10 +8561,34 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
8561
8561
|
// covers the initial dispatch (a connected client is polling the claim),
|
|
8562
8562
|
// but a server-chained CONTINUATION handoff has no foreground watching
|
|
8563
8563
|
// it: if the dispatch is lost after the successor row was inserted, the
|
|
8564
|
-
// row would sit at dispatch_mode='background' forever and the
|
|
8565
|
-
// silently.
|
|
8566
|
-
//
|
|
8567
|
-
//
|
|
8564
|
+
// row would otherwise sit at dispatch_mode='background' forever and the
|
|
8565
|
+
// turn hangs silently. `chainServerDrivenContinuation` (production-agent.ts)
|
|
8566
|
+
// leaves exactly such a row behind — status='running', dispatch_mode=
|
|
8567
|
+
// 'background', `dispatch_payload` intact — when it exhausts its own
|
|
8568
|
+
// dispatch retry budget, instead of erroring it immediately. This sweep
|
|
8569
|
+
// gives that row a real chance to RECOVER: within
|
|
8570
|
+
// `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS` of its original
|
|
8571
|
+
// `started_at` it redispatches the handoff (same `_process-run`
|
|
8572
|
+
// processor, same persisted payload); past that bound it falls back to
|
|
8573
|
+
// the existing loud reap (`background_worker_never_started`) so a
|
|
8574
|
+
// genuinely dead handoff still fails loud, never silently. A
|
|
8575
|
+
// redispatch is always safe to attempt — even a duplicate or
|
|
8576
|
+
// late-arriving one — because the worker's `claimBackgroundRun` atomic
|
|
8577
|
+
// CAS (status='running' AND dispatch_mode='background' -> 'background-
|
|
8578
|
+
// processing') is the sole gate on actual execution; a row that was
|
|
8579
|
+
// already claimed or already reaped by a concurrent path just loses the
|
|
8580
|
+
// CAS and no-ops. Cheap: one indexed-ish query per 2-min window.
|
|
8581
|
+
//
|
|
8582
|
+
// THREE-SITE INVARIANT (keep in lockstep): this sweep only ever sees the
|
|
8583
|
+
// deferred successor because the ~1s client poll in
|
|
8584
|
+
// `getActiveRunForThreadAsync` (run-manager.ts) skips its own
|
|
8585
|
+
// `reapUnclaimedBackgroundRun` while the row is within the redispatch
|
|
8586
|
+
// bound (`shouldRedispatchUnclaimedBackgroundRun`). If a future change
|
|
8587
|
+
// makes that client poll reap deferred successors at the 25s grace
|
|
8588
|
+
// again, this sweep will almost never win the race for connected clients.
|
|
8589
|
+
// Do not edit one site without the others (producer:
|
|
8590
|
+
// chainServerDrivenContinuation in production-agent.ts; guard:
|
|
8591
|
+
// run-manager.ts; recovery actor: here).
|
|
8568
8592
|
(() => {
|
|
8569
8593
|
let lastSweep = 0;
|
|
8570
8594
|
const SWEEP_INTERVAL_MS = 2 * 60 * 1000;
|
|
@@ -8577,22 +8601,85 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
8577
8601
|
|
|
8578
8602
|
(async () => {
|
|
8579
8603
|
const {
|
|
8580
|
-
|
|
8604
|
+
listUnclaimedBackgroundRunRows,
|
|
8581
8605
|
reapUnclaimedBackgroundRun,
|
|
8606
|
+
updateRunHeartbeat,
|
|
8607
|
+
shouldRedispatchUnclaimedBackgroundRun,
|
|
8582
8608
|
} = await import("../agent/run-store.js");
|
|
8583
|
-
|
|
8609
|
+
const { resolveAgentChatProcessRunDispatchPath } =
|
|
8610
|
+
await import("../agent/durable-background.js");
|
|
8611
|
+
const { fireInternalDispatch } =
|
|
8612
|
+
await import("./self-dispatch.js");
|
|
8613
|
+
let rows: { id: string; startedAt: number }[];
|
|
8584
8614
|
try {
|
|
8585
|
-
|
|
8615
|
+
rows = await listUnclaimedBackgroundRunRows();
|
|
8586
8616
|
} catch {
|
|
8587
8617
|
return; // Table may not exist yet on first boot
|
|
8588
8618
|
}
|
|
8589
|
-
for (const
|
|
8619
|
+
for (const row of rows) {
|
|
8590
8620
|
try {
|
|
8591
|
-
|
|
8621
|
+
if (shouldRedispatchUnclaimedBackgroundRun(row)) {
|
|
8622
|
+
// Bump liveness BEFORE attempting the redispatch so the
|
|
8623
|
+
// row doesn't look freshly-stale again the instant this
|
|
8624
|
+
// tick returns — best-effort, the CAS is what actually
|
|
8625
|
+
// matters for correctness, not this timing.
|
|
8626
|
+
await updateRunHeartbeat(row.id).catch(() => {});
|
|
8627
|
+
try {
|
|
8628
|
+
// DELIBERATE: this marker omits `continuationCount`.
|
|
8629
|
+
// `chainServerDrivenContinuation` (production-agent.ts)
|
|
8630
|
+
// reads `backgroundRunMarker.continuationCount` to
|
|
8631
|
+
// compute `backgroundContinuationCount`, defaulting to 0
|
|
8632
|
+
// when absent — so a chunk recovered here always starts
|
|
8633
|
+
// a fresh nested-dispatch segment at depth 0, regardless
|
|
8634
|
+
// of how deep the chain was before this sweep picked it
|
|
8635
|
+
// up. This is what makes the sweep a genuine CHAIN
|
|
8636
|
+
// BREAK, not just a retry: this redispatch fires from an
|
|
8637
|
+
// unrelated, timer-driven invocation rather than from
|
|
8638
|
+
// inside the prior chain's own live execution, so
|
|
8639
|
+
// starting its nested-depth count over at 0 here is
|
|
8640
|
+
// correct — see `MAX_NESTED_SELF_DISPATCH_DEPTH` in
|
|
8641
|
+
// production-agent.ts for why nested depth is bounded
|
|
8642
|
+
// and how this reset keeps a long turn progressing past
|
|
8643
|
+
// Netlify's undocumented self-invocation loop-protection
|
|
8644
|
+
// limit instead of dying at it. Do not "fix" this by
|
|
8645
|
+
// adding `continuationCount` back without re-reading
|
|
8646
|
+
// that constant's doc comment.
|
|
8647
|
+
await fireInternalDispatch({
|
|
8648
|
+
path: resolveAgentChatProcessRunDispatchPath(),
|
|
8649
|
+
taskId: row.id,
|
|
8650
|
+
body: {
|
|
8651
|
+
internalContinuation: true,
|
|
8652
|
+
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
|
|
8653
|
+
runId: row.id,
|
|
8654
|
+
payloadRef: true,
|
|
8655
|
+
},
|
|
8656
|
+
},
|
|
8657
|
+
awaitResponse: true,
|
|
8658
|
+
responseTimeoutMs: 15_000,
|
|
8659
|
+
});
|
|
8660
|
+
console.error(
|
|
8661
|
+
"[agent-chat] redispatched unclaimed background run (handoff recovery):",
|
|
8662
|
+
row.id,
|
|
8663
|
+
);
|
|
8664
|
+
} catch (redispatchErr) {
|
|
8665
|
+
console.error(
|
|
8666
|
+
"[agent-chat] unclaimed background run redispatch attempt failed (retrying until the redispatch bound, then reaping):",
|
|
8667
|
+
row.id,
|
|
8668
|
+
redispatchErr instanceof Error
|
|
8669
|
+
? redispatchErr.message
|
|
8670
|
+
: redispatchErr,
|
|
8671
|
+
);
|
|
8672
|
+
}
|
|
8673
|
+
continue;
|
|
8674
|
+
}
|
|
8675
|
+
// Redispatch bound exceeded — this handoff is not
|
|
8676
|
+
// recovering. Fall back to the pre-existing loud reap so
|
|
8677
|
+
// the turn fails loud instead of retrying forever.
|
|
8678
|
+
const reaped = await reapUnclaimedBackgroundRun(row.id);
|
|
8592
8679
|
if (reaped) {
|
|
8593
8680
|
console.error(
|
|
8594
|
-
"[agent-chat] swept unclaimed background run (handoff lost):",
|
|
8595
|
-
|
|
8681
|
+
"[agent-chat] swept unclaimed background run (handoff lost, redispatch bound exceeded):",
|
|
8682
|
+
row.id,
|
|
8596
8683
|
);
|
|
8597
8684
|
}
|
|
8598
8685
|
} catch {
|
|
@@ -16,6 +16,21 @@ export interface BuilderDesignSystemCodeFileInput {
|
|
|
16
16
|
filename: string;
|
|
17
17
|
content: string;
|
|
18
18
|
mimeType?: string;
|
|
19
|
+
/**
|
|
20
|
+
* How `content` is encoded. Defaults to `"utf8"` (existing behavior,
|
|
21
|
+
* unchanged for every current text-file caller). Pass `"base64"` for
|
|
22
|
+
* binary files -- most importantly `.fig` (a zip/kiwi binary container,
|
|
23
|
+
* never valid UTF-8 text). Without this, a `.fig` upload silently
|
|
24
|
+
* corrupts: `mimeTypeForBuilderDesignSystemFilename` already special-cases
|
|
25
|
+
* `.fig` as `application/octet-stream`, but the actual byte pipeline ran
|
|
26
|
+
* every file through `TextEncoder().encode()` regardless, which mangles
|
|
27
|
+
* any byte >= 0x80 in a binary-as-string payload (or, if the caller
|
|
28
|
+
* base64-encoded first with no decode step here, stores the literal
|
|
29
|
+
* base64 text instead of the decoded binary). Callers sending `.fig`/PDF/
|
|
30
|
+
* other binary bytes must base64-encode `content` and set this to
|
|
31
|
+
* `"base64"`.
|
|
32
|
+
*/
|
|
33
|
+
encoding?: "utf8" | "base64";
|
|
19
34
|
}
|
|
20
35
|
|
|
21
36
|
export interface BuildBuilderDesignSystemIndexFilesOptions {
|
|
@@ -184,9 +199,20 @@ export function buildBuilderDesignSystemIndexFiles({
|
|
|
184
199
|
const files: BuilderDesignSystemIndexFile[] = [];
|
|
185
200
|
let totalBytes = 0;
|
|
186
201
|
|
|
187
|
-
function
|
|
202
|
+
function pushFile(
|
|
203
|
+
filename: string,
|
|
204
|
+
content: string,
|
|
205
|
+
mimeType?: string,
|
|
206
|
+
encoding?: "utf8" | "base64",
|
|
207
|
+
) {
|
|
188
208
|
const normalizedName = filename.replace(/^\/+/, "") || "code.txt";
|
|
189
|
-
|
|
209
|
+
// `.fig`/PDF/other binary payloads must round-trip through base64, not
|
|
210
|
+
// UTF-8 -- TextEncoder().encode() on a binary-as-string payload mangles
|
|
211
|
+
// any byte >= 0x80. See BuilderDesignSystemCodeFileInput.encoding.
|
|
212
|
+
const data =
|
|
213
|
+
encoding === "base64"
|
|
214
|
+
? new Uint8Array(Buffer.from(content, "base64"))
|
|
215
|
+
: encoder.encode(content);
|
|
190
216
|
if (data.byteLength === 0) return;
|
|
191
217
|
if (totalBytes + data.byteLength > maxTotalCodeBytes) return;
|
|
192
218
|
totalBytes += data.byteLength;
|
|
@@ -201,7 +227,7 @@ export function buildBuilderDesignSystemIndexFiles({
|
|
|
201
227
|
}
|
|
202
228
|
|
|
203
229
|
if (designMd?.trim()) {
|
|
204
|
-
|
|
230
|
+
pushFile(
|
|
205
231
|
designMdFilename?.trim() || "design.md",
|
|
206
232
|
designMd,
|
|
207
233
|
"text/markdown",
|
|
@@ -209,7 +235,7 @@ export function buildBuilderDesignSystemIndexFiles({
|
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
for (const file of (codeFiles ?? []).slice(0, maxCodeFiles)) {
|
|
212
|
-
|
|
238
|
+
pushFile(file.filename, file.content, file.mimeType, file.encoding);
|
|
213
239
|
}
|
|
214
240
|
|
|
215
241
|
return files;
|
|
@@ -126,7 +126,7 @@ Transcription takes an audio file and returns text + segments. That's not a prom
|
|
|
126
126
|
**Provider priority:**
|
|
127
127
|
|
|
128
128
|
1. **Native (highest priority).** The browser's Web Speech API, desktop local Whisper/macOS SFSpeech when available, and desktop Web Speech fallback on non-mac run during recording and save results via `save-browser-transcript`. This gives an instant transcript with no API key when the local/browser recognizer is available. When `request-transcript` runs afterward, it preserves the ready native transcript and only falls back to a cloud provider if native text is missing.
|
|
129
|
-
2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments.
|
|
129
|
+
2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments. Retry a failed transcript with `force: true`; pass `regenerate: true` to replace an existing ready transcript from the stored recording media. Regeneration keeps the prior ready transcript available if the new provider attempt fails.
|
|
130
130
|
3. **Cloud fallback — Groq Whisper.** `GROQ_API_KEY` → `https://api.groq.com/openai/v1/audio/transcriptions`, model `whisper-large-v3-turbo`. Fast (~$0.04/hour of audio) Whisper-compatible speech-to-text used when Builder is unavailable.
|
|
131
131
|
|
|
132
132
|
Clips never routes recording/meeting audio to OpenAI for transcription. (Groq's endpoint is OpenAI-_compatible_ in request shape only — the audio goes to Groq, not OpenAI.)
|
|
@@ -14,6 +14,12 @@ description: >-
|
|
|
14
14
|
|
|
15
15
|
Recording sharing uses the framework `sharing` system — not a custom share table. Recordings are registered via `registerShareableResource({ type: "recording", ... })` in `server/db/index.ts`. The `share-resource`, `unshare-resource`, `list-resource-shares`, and `set-resource-visibility` actions are auto-mounted and handle per-user grants, per-org grants, and the three visibility levels (`private` / `org` / `public`).
|
|
16
16
|
|
|
17
|
+
Unlike the framework-wide private default, normal Clips recordings and uploaded
|
|
18
|
+
videos default to **public** so their copied share links work immediately.
|
|
19
|
+
Embedded bug-report recordings are the exception and default to organization
|
|
20
|
+
visibility. Callers can still explicitly create a private or organization-only
|
|
21
|
+
recording, and owners/admins can change visibility from the Share dialog.
|
|
22
|
+
|
|
17
23
|
Clips **adds two things** on top of the framework system:
|
|
18
24
|
|
|
19
25
|
1. **Password** — an optional bcrypt'd string on the `recordings` row. When set, all non-owner viewers must enter it to play the recording.
|
|
@@ -62,7 +68,7 @@ import { ShareDialog } from "@agent-native/core/client";
|
|
|
62
68
|
</>
|
|
63
69
|
}
|
|
64
70
|
embedTabContent={<EmbedSnippetAndOptions recordingId={recording.id} />}
|
|
65
|
-
|
|
71
|
+
/>;
|
|
66
72
|
```
|
|
67
73
|
|
|
68
74
|
- `shareUrl` / `embedUrl` — the copy-link and embed URLs the framework renders in its tabs.
|
|
@@ -163,11 +169,11 @@ Required Slack app setup:
|
|
|
163
169
|
Recordings can expose URLs meant for external agents without handing over raw
|
|
164
170
|
video bytes:
|
|
165
171
|
|
|
166
|
-
| Endpoint
|
|
167
|
-
|
|
|
168
|
-
| `/api/agent-context.json?id=<recordingId>`
|
|
169
|
-
| `/api/agent-transcript.json?id=<recordingId>`
|
|
170
|
-
| `/api/agent-frame.jpg?id=<recordingId>&atMs=<ms>` | JPEG frame extracted from the video at the requested original-video timestamp
|
|
172
|
+
| Endpoint | Meaning |
|
|
173
|
+
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
174
|
+
| `/api/agent-context.json?id=<recordingId>` | Clip metadata, transcript summary, recommended frames, and API discovery links |
|
|
175
|
+
| `/api/agent-transcript.json?id=<recordingId>` | Timestamped transcript segments with `startMs`, `endMs`, `timestamp`, `range`, `text`, and optional `source` |
|
|
176
|
+
| `/api/agent-frame.jpg?id=<recordingId>&atMs=<ms>` | JPEG frame extracted from the video at the requested original-video timestamp |
|
|
171
177
|
|
|
172
178
|
These endpoints follow the same access model as `/api/public-recording`, plus a
|
|
173
179
|
temporary agent-link path:
|
|
@@ -34,6 +34,10 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
|
|
|
34
34
|
download the original from Loom and use "Upload video".
|
|
35
35
|
- Native transcript first. Cleanup and title generation can run in the
|
|
36
36
|
background; do not hide a usable native transcript behind a failed cleanup.
|
|
37
|
+
- Use `request-transcript --recordingId=<id> --force=true` to retry a failed
|
|
38
|
+
transcript. Pass `--regenerate=true` to replace an existing ready transcript
|
|
39
|
+
from the stored recording media; if regeneration fails, keep the prior ready
|
|
40
|
+
transcript available.
|
|
37
41
|
- Dictation cleanup, Clip title/cleanup, and meeting summaries should pass
|
|
38
42
|
bounded `voiceContext` to the shared cleanup/transcription path when active
|
|
39
43
|
app context, learned vocabulary, user notes, or AGENTS.md preferences are
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from "../server/lib/recordings.js";
|
|
25
25
|
import { setResumableSession } from "../server/lib/resumable-session.js";
|
|
26
26
|
import { shouldEnableStreamingUpload } from "../server/lib/streaming-upload-mode.js";
|
|
27
|
+
import { allowsSqlRecordingChunkScratch } from "../server/lib/video-storage.js";
|
|
27
28
|
import { createRecordingSchema } from "./lib/create-recording-schema.js";
|
|
28
29
|
import { DEFAULT_RECORDING_TITLE } from "./lib/title-source.js";
|
|
29
30
|
|
|
@@ -92,6 +93,7 @@ export default defineAction({
|
|
|
92
93
|
shouldEnableStreamingUpload({
|
|
93
94
|
client: args.streamingUploadClient,
|
|
94
95
|
mimeType: args.mimeType,
|
|
96
|
+
bufferedFallbackAvailable: allowsSqlRecordingChunkScratch(),
|
|
95
97
|
}) &&
|
|
96
98
|
uploadProvider?.resumable
|
|
97
99
|
) {
|
|
@@ -62,8 +62,10 @@ export const createRecordingSchema = z.object({
|
|
|
62
62
|
.describe("Height of the recording in pixels (may be 0 until finalized)"),
|
|
63
63
|
visibility: z
|
|
64
64
|
.enum(["private", "org", "public"])
|
|
65
|
-
.
|
|
66
|
-
.describe(
|
|
65
|
+
.default("public")
|
|
66
|
+
.describe(
|
|
67
|
+
"Initial share visibility for the recording (defaults to public)",
|
|
68
|
+
),
|
|
67
69
|
mimeType: z
|
|
68
70
|
.string()
|
|
69
71
|
.optional()
|
|
@@ -74,7 +76,7 @@ export const createRecordingSchema = z.object({
|
|
|
74
76
|
.boolean()
|
|
75
77
|
.optional()
|
|
76
78
|
.describe(
|
|
77
|
-
"Request the resumable streaming upload path.
|
|
79
|
+
"Request the resumable streaming upload path. Hosted deployments use it automatically because SQL chunk buffering is unavailable; local deployments can opt in with CLIPS_ENABLE_STREAMING_UPLOAD.",
|
|
78
80
|
),
|
|
79
81
|
streamingUploadClient: z
|
|
80
82
|
.enum(["desktop-native"])
|