@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
|
@@ -631,6 +631,20 @@ replace them with copied \`srcdoc\` HTML unless the user explicitly asks for a
|
|
|
631
631
|
frozen snapshot. To change a state, rerun \`add-localhost-screens\` with the new
|
|
632
632
|
path/query or duplicate the screen and update the copy's URL metadata.
|
|
633
633
|
|
|
634
|
+
## React Source Writeback
|
|
635
|
+
|
|
636
|
+
- Use compiler/debug provenance (project-relative file, line, column,
|
|
637
|
+
component, and runtime multiplicity) to locate React/TSX source. Treat it as
|
|
638
|
+
evidence, not as permission for a generic AST structural transform.
|
|
639
|
+
- Reparenting, grouping/ungrouping, wrappers, dynamic expressions, repeated
|
|
640
|
+
\`.map()\` instances, shared components, and cross-file changes go through the
|
|
641
|
+
coding agent with exact subject/target anchors and their runtime
|
|
642
|
+
relationship.
|
|
643
|
+
- Before each write, read the file and pass its exact \`versionHash\` to
|
|
644
|
+
\`write-local-file\` with \`requireExpectedVersionHash: true\`; on conflict,
|
|
645
|
+
re-read and re-plan. Keep the optimistic preview until HMR/runtime confirms
|
|
646
|
+
the result. Human write consent remains mandatory and agents cannot grant it.
|
|
647
|
+
|
|
634
648
|
## Verification
|
|
635
649
|
|
|
636
650
|
- \`list-localhost-connections\` returns the expected connection and routes.
|
|
@@ -55,9 +55,11 @@ import {
|
|
|
55
55
|
appendAgentChatContextToMessage,
|
|
56
56
|
formatAgentChatContextItemsForPrompt,
|
|
57
57
|
getAgentChatContextState,
|
|
58
|
+
isAgentChatSubmitCancelled,
|
|
58
59
|
normalizeAgentChatContextItem,
|
|
59
60
|
publishAgentChatContextItems,
|
|
60
61
|
refreshAgentChatContext,
|
|
62
|
+
reportAgentChatSubmitResult,
|
|
61
63
|
subscribeAgentChatContext,
|
|
62
64
|
type AgentChatContextItem,
|
|
63
65
|
} from "./agent-chat.js";
|
|
@@ -197,6 +199,8 @@ export type AgentRecoveryAction = "continue" | "retry";
|
|
|
197
199
|
export interface AssistantChatSendOptions {
|
|
198
200
|
trackInRunsTray?: boolean;
|
|
199
201
|
requestMode?: AgentRequestMode;
|
|
202
|
+
/** Correlates with `AGENT_CHAT_SUBMIT_RESULT_EVENT` — see agent-chat.ts. */
|
|
203
|
+
submitMessageId?: string;
|
|
200
204
|
}
|
|
201
205
|
|
|
202
206
|
function createUserMessageRunConfig(
|
|
@@ -3651,9 +3655,12 @@ const AssistantChatInner = forwardRef<
|
|
|
3651
3655
|
trackInRunsTray = false,
|
|
3652
3656
|
preserveReconnectAutoRecoveryBudget = false,
|
|
3653
3657
|
hideUserMessage = false,
|
|
3658
|
+
submitMessageId?: string,
|
|
3654
3659
|
) => {
|
|
3660
|
+
if (isAgentChatSubmitCancelled(submitMessageId)) return;
|
|
3655
3661
|
if (agentEngineConfigured.state === "missing") {
|
|
3656
3662
|
void ensureAgentEngineReadyForSubmit();
|
|
3663
|
+
reportAgentChatSubmitResult(submitMessageId, false, "missing-engine");
|
|
3657
3664
|
return;
|
|
3658
3665
|
}
|
|
3659
3666
|
if (!preserveReconnectAutoRecoveryBudget) {
|
|
@@ -3687,8 +3694,10 @@ const AssistantChatInner = forwardRef<
|
|
|
3687
3694
|
? err.message
|
|
3688
3695
|
: "Attachment could not be processed.";
|
|
3689
3696
|
setComposerError(msg);
|
|
3697
|
+
reportAgentChatSubmitResult(submitMessageId, false, "attachment-error");
|
|
3690
3698
|
return;
|
|
3691
3699
|
}
|
|
3700
|
+
if (isAgentChatSubmitCancelled(submitMessageId)) return;
|
|
3692
3701
|
const imageAttachments = createAgentImageAttachments(images);
|
|
3693
3702
|
const allAttachments = [
|
|
3694
3703
|
...(queuedAttachments ?? []),
|
|
@@ -3782,6 +3791,11 @@ const AssistantChatInner = forwardRef<
|
|
|
3782
3791
|
setComposerError(
|
|
3783
3792
|
`"${rejected.name}" makes the message too large to send (combined attachments must be under ${Math.round(MAX_ESTIMATED_BODY_BYTES / 1024 / 1024)} MB). Remove it or use a smaller image.`,
|
|
3784
3793
|
);
|
|
3794
|
+
reportAgentChatSubmitResult(
|
|
3795
|
+
submitMessageId,
|
|
3796
|
+
false,
|
|
3797
|
+
"attachment-too-large",
|
|
3798
|
+
);
|
|
3785
3799
|
return;
|
|
3786
3800
|
}
|
|
3787
3801
|
}
|
|
@@ -3789,6 +3803,7 @@ const AssistantChatInner = forwardRef<
|
|
|
3789
3803
|
}
|
|
3790
3804
|
}
|
|
3791
3805
|
// ── End body-size guard ──────────────────────────────────────────
|
|
3806
|
+
if (isAgentChatSubmitCancelled(submitMessageId)) return;
|
|
3792
3807
|
// Snapshot the exec mode at enqueue time when the caller didn't
|
|
3793
3808
|
// pass an explicit override. Without this, a plan-mode message that
|
|
3794
3809
|
// sits in the queue runs as 'act' if the user flips the global toggle
|
|
@@ -3863,9 +3878,16 @@ const AssistantChatInner = forwardRef<
|
|
|
3863
3878
|
} as Parameters<typeof threadRuntime.append>[0]);
|
|
3864
3879
|
} catch (error) {
|
|
3865
3880
|
setOptimisticRunning(false);
|
|
3881
|
+
reportAgentChatSubmitResult(submitMessageId, false, "append-failed");
|
|
3866
3882
|
throw error;
|
|
3867
3883
|
}
|
|
3868
3884
|
}
|
|
3885
|
+
// The turn is now either queued behind the active run or already a
|
|
3886
|
+
// visible message — either way it has reached the chat. This is
|
|
3887
|
+
// intentionally reported before the agent's response resolves: a
|
|
3888
|
+
// caller like sendToAgentChatAndConfirm only needs to know the submit
|
|
3889
|
+
// wasn't silently dropped, not whether the run itself later succeeds.
|
|
3890
|
+
reportAgentChatSubmitResult(submitMessageId, true);
|
|
3869
3891
|
if (submitted.includesContext) {
|
|
3870
3892
|
updateComposerContextItems(() => []);
|
|
3871
3893
|
}
|
|
@@ -3927,6 +3949,9 @@ const AssistantChatInner = forwardRef<
|
|
|
3927
3949
|
undefined,
|
|
3928
3950
|
false,
|
|
3929
3951
|
options?.trackInRunsTray === true,
|
|
3952
|
+
false,
|
|
3953
|
+
false,
|
|
3954
|
+
options?.submitMessageId,
|
|
3930
3955
|
);
|
|
3931
3956
|
},
|
|
3932
3957
|
prefillMessage(text: string) {
|
|
@@ -30,8 +30,10 @@ import {
|
|
|
30
30
|
claimAgentChatSubmit,
|
|
31
31
|
drainBufferedAgentChatOpenRequests,
|
|
32
32
|
drainBufferedAgentChatSubmits,
|
|
33
|
+
isAgentChatSubmitCancelled,
|
|
33
34
|
normalizeAgentChatContextItem,
|
|
34
35
|
parseSubmitChatMessage,
|
|
36
|
+
reportAgentChatSubmitResult,
|
|
35
37
|
type AgentChatContextItem,
|
|
36
38
|
} from "./agent-chat.js";
|
|
37
39
|
import { agentNativePath, appPath } from "./api-path.js";
|
|
@@ -79,6 +81,8 @@ interface PendingSend {
|
|
|
79
81
|
submit: boolean;
|
|
80
82
|
trackInRunsTray?: boolean;
|
|
81
83
|
requestMode?: "act" | "plan";
|
|
84
|
+
/** Correlates with `AGENT_CHAT_SUBMIT_RESULT_EVENT` — see agent-chat.ts. */
|
|
85
|
+
submitMessageId?: string;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
/**
|
|
@@ -93,14 +97,18 @@ interface PendingDelivery {
|
|
|
93
97
|
|
|
94
98
|
/** The single path that hands a queued send to a mounted chat ref. */
|
|
95
99
|
function deliverPendingSend(ref: AssistantChatHandle, send: PendingSend): void {
|
|
100
|
+
if (isAgentChatSubmitCancelled(send.submitMessageId)) return;
|
|
96
101
|
if (!send.submit) {
|
|
97
102
|
ref.prefillMessage(send.message);
|
|
98
103
|
return;
|
|
99
104
|
}
|
|
100
|
-
if (send.trackInRunsTray || send.requestMode) {
|
|
105
|
+
if (send.trackInRunsTray || send.requestMode || send.submitMessageId) {
|
|
101
106
|
ref.sendMessage(send.message, send.images, {
|
|
102
107
|
...(send.trackInRunsTray ? { trackInRunsTray: true } : {}),
|
|
103
108
|
...(send.requestMode ? { requestMode: send.requestMode } : {}),
|
|
109
|
+
...(send.submitMessageId
|
|
110
|
+
? { submitMessageId: send.submitMessageId }
|
|
111
|
+
: {}),
|
|
104
112
|
});
|
|
105
113
|
} else {
|
|
106
114
|
ref.sendMessage(send.message, send.images);
|
|
@@ -1767,6 +1775,7 @@ export function MultiTabAssistantChat({
|
|
|
1767
1775
|
background,
|
|
1768
1776
|
submit,
|
|
1769
1777
|
images,
|
|
1778
|
+
submitMessageId,
|
|
1770
1779
|
} = parsed;
|
|
1771
1780
|
const requestedTabId = parsed.tabId;
|
|
1772
1781
|
const requestMode =
|
|
@@ -1777,7 +1786,14 @@ export function MultiTabAssistantChat({
|
|
|
1777
1786
|
if (openSidebar !== false && !background) {
|
|
1778
1787
|
window.dispatchEvent(new CustomEvent("agent-panel:open"));
|
|
1779
1788
|
}
|
|
1780
|
-
if (postMessageSubmissionsDisabled)
|
|
1789
|
+
if (postMessageSubmissionsDisabled) {
|
|
1790
|
+
reportAgentChatSubmitResult(
|
|
1791
|
+
submitMessageId,
|
|
1792
|
+
false,
|
|
1793
|
+
"composer-disabled",
|
|
1794
|
+
);
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1781
1797
|
|
|
1782
1798
|
// Plan mode is sent as request metadata by the chat adapter. Keep the
|
|
1783
1799
|
// user-visible message clean so mode instructions never enter history.
|
|
@@ -1791,9 +1807,11 @@ export function MultiTabAssistantChat({
|
|
|
1791
1807
|
submit,
|
|
1792
1808
|
...(background ? { trackInRunsTray: true } : {}),
|
|
1793
1809
|
...(requestMode ? { requestMode } : {}),
|
|
1810
|
+
...(submitMessageId ? { submitMessageId } : {}),
|
|
1794
1811
|
};
|
|
1795
1812
|
|
|
1796
1813
|
const sendToTab = (threadId: string) => {
|
|
1814
|
+
if (isAgentChatSubmitCancelled(submitMessageId)) return;
|
|
1797
1815
|
// If a model override was specified, apply it only if we recognize it
|
|
1798
1816
|
if (model) {
|
|
1799
1817
|
const matchedGroup = availableModels.find((g) =>
|
|
@@ -1826,8 +1844,17 @@ export function MultiTabAssistantChat({
|
|
|
1826
1844
|
|
|
1827
1845
|
if (newTab) {
|
|
1828
1846
|
const previousTabId = activeThreadIdRef.current;
|
|
1829
|
-
createThread(requestedTabId)
|
|
1830
|
-
|
|
1847
|
+
createThread(requestedTabId)
|
|
1848
|
+
.then((newId) => {
|
|
1849
|
+
if (isAgentChatSubmitCancelled(submitMessageId)) return;
|
|
1850
|
+
if (!newId) {
|
|
1851
|
+
reportAgentChatSubmitResult(
|
|
1852
|
+
submitMessageId,
|
|
1853
|
+
false,
|
|
1854
|
+
"thread-create-failed",
|
|
1855
|
+
);
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1831
1858
|
newThreadIds.current.add(newId);
|
|
1832
1859
|
if (background) {
|
|
1833
1860
|
mountedTabsRef.current.add(newId);
|
|
@@ -1842,8 +1869,14 @@ export function MultiTabAssistantChat({
|
|
|
1842
1869
|
if (background && previousTabId) {
|
|
1843
1870
|
switchThreadState(previousTabId);
|
|
1844
1871
|
}
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1872
|
+
})
|
|
1873
|
+
.catch(() => {
|
|
1874
|
+
reportAgentChatSubmitResult(
|
|
1875
|
+
submitMessageId,
|
|
1876
|
+
false,
|
|
1877
|
+
"thread-create-failed",
|
|
1878
|
+
);
|
|
1879
|
+
});
|
|
1847
1880
|
} else {
|
|
1848
1881
|
const currentTabId = activeThreadIdRef.current;
|
|
1849
1882
|
if (currentTabId) {
|
|
@@ -1901,6 +1934,7 @@ export function MultiTabAssistantChat({
|
|
|
1901
1934
|
const active = activeThreadIdRef.current;
|
|
1902
1935
|
const remaining: PendingDelivery[] = [];
|
|
1903
1936
|
for (const delivery of pendingDeliveries.current) {
|
|
1937
|
+
if (isAgentChatSubmitCancelled(delivery.send.submitMessageId)) continue;
|
|
1904
1938
|
const threadId = delivery.threadId ?? active ?? null;
|
|
1905
1939
|
const ref = threadId ? chatRefs.current.get(threadId) : null;
|
|
1906
1940
|
if (threadId && ref) {
|
|
@@ -96,6 +96,11 @@ export interface AgentChatMessage {
|
|
|
96
96
|
* focusing it or opening the sidebar. The message runs silently.
|
|
97
97
|
*/
|
|
98
98
|
background?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Stable id used to deduplicate a submit and correlate it with
|
|
101
|
+
* {@link AGENT_CHAT_SUBMIT_RESULT_EVENT}. Auto-generated if omitted.
|
|
102
|
+
*/
|
|
103
|
+
submitMessageId?: string;
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
export interface AgentChatContextItem {
|
|
@@ -210,6 +215,45 @@ export const AGENT_CHAT_INSERT_REFERENCE_EVENT =
|
|
|
210
215
|
"agentNative:insert-composer-reference";
|
|
211
216
|
const AGENT_PANEL_PREPARE_EVENT = "agent-panel:prepare";
|
|
212
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Fired once a submitted turn's fate is known: `delivered: true` once the
|
|
220
|
+
* receiving AssistantChat has actually committed the turn (added it to the
|
|
221
|
+
* visible thread, independent of whether the agent's response later
|
|
222
|
+
* succeeds), or `delivered: false` when it was rejected before ever
|
|
223
|
+
* appearing — e.g. no LLM/agent engine configured. Callers that must know
|
|
224
|
+
* whether their submit truly landed (rather than fire-and-forget) should use
|
|
225
|
+
* {@link sendToAgentChatAndConfirm} instead of listening for this directly.
|
|
226
|
+
*/
|
|
227
|
+
export const AGENT_CHAT_SUBMIT_RESULT_EVENT = "agentNative.chatSubmitResult";
|
|
228
|
+
|
|
229
|
+
export interface AgentChatSubmitResult {
|
|
230
|
+
submitMessageId: string;
|
|
231
|
+
delivered: boolean;
|
|
232
|
+
reason?: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Report a submit's definitive outcome so `sendToAgentChatAndConfirm` (or any
|
|
236
|
+
* other correlated listener) can resolve. No-ops without a submitMessageId or
|
|
237
|
+
* a window (SSR). */
|
|
238
|
+
export function reportAgentChatSubmitResult(
|
|
239
|
+
submitMessageId: string | undefined,
|
|
240
|
+
delivered: boolean,
|
|
241
|
+
reason?: string,
|
|
242
|
+
): void {
|
|
243
|
+
if (
|
|
244
|
+
!submitMessageId ||
|
|
245
|
+
cancelledSubmitIds.has(submitMessageId) ||
|
|
246
|
+
typeof window === "undefined"
|
|
247
|
+
) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
window.dispatchEvent(
|
|
251
|
+
new CustomEvent<AgentChatSubmitResult>(AGENT_CHAT_SUBMIT_RESULT_EVENT, {
|
|
252
|
+
detail: { submitMessageId, delivered, reason },
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
213
257
|
let agentChatContextState: AgentChatContextState = {
|
|
214
258
|
items: [],
|
|
215
259
|
updatedAt: 0,
|
|
@@ -262,6 +306,7 @@ interface BufferedSelfSubmit {
|
|
|
262
306
|
const SELF_SUBMIT_BUFFER_TTL_MS = 8000;
|
|
263
307
|
const bufferedSelfSubmits: BufferedSelfSubmit[] = [];
|
|
264
308
|
const claimedSubmitIds = new Set<string>();
|
|
309
|
+
const cancelledSubmitIds = new Set<string>();
|
|
265
310
|
|
|
266
311
|
interface BufferedOpenRequest extends BufferedAgentChatOpenRequest {
|
|
267
312
|
at: number;
|
|
@@ -289,6 +334,28 @@ function bufferSelfSubmit(data: Record<string, unknown>): void {
|
|
|
289
334
|
bufferedSelfSubmits.push({ id, data, at: now });
|
|
290
335
|
}
|
|
291
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Permanently tombstone a submit for this page lifetime and remove its
|
|
339
|
+
* cold-start replay. A confirmation timeout must be terminal: callers may
|
|
340
|
+
* retry while preserving their own state, so the original submit cannot be
|
|
341
|
+
* allowed to appear later when a lazy panel or thread ref finally mounts.
|
|
342
|
+
*/
|
|
343
|
+
export function cancelAgentChatSubmit(id: string | undefined): void {
|
|
344
|
+
if (!id) return;
|
|
345
|
+
cancelledSubmitIds.add(id);
|
|
346
|
+
claimedSubmitIds.add(id);
|
|
347
|
+
for (let index = bufferedSelfSubmits.length - 1; index >= 0; index -= 1) {
|
|
348
|
+
if (bufferedSelfSubmits[index]?.id === id) {
|
|
349
|
+
bufferedSelfSubmits.splice(index, 1);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** Whether a confirmed-submit timeout has made this delivery terminal. */
|
|
355
|
+
export function isAgentChatSubmitCancelled(id: string | undefined): boolean {
|
|
356
|
+
return Boolean(id && cancelledSubmitIds.has(id));
|
|
357
|
+
}
|
|
358
|
+
|
|
292
359
|
function pruneOpenRequestBuffer(now: number): void {
|
|
293
360
|
for (let i = bufferedOpenRequests.length - 1; i >= 0; i -= 1) {
|
|
294
361
|
if (now - bufferedOpenRequests[i].at > OPEN_REQUEST_BUFFER_TTL_MS) {
|
|
@@ -328,6 +395,7 @@ export function drainBufferedAgentChatSubmits(): Array<
|
|
|
328
395
|
/** Claim a submit; false if already handled. Idless submits always pass. */
|
|
329
396
|
export function claimAgentChatSubmit(id: string | undefined): boolean {
|
|
330
397
|
if (!id) return true;
|
|
398
|
+
if (cancelledSubmitIds.has(id)) return false;
|
|
331
399
|
if (claimedSubmitIds.has(id)) return false;
|
|
332
400
|
claimedSubmitIds.add(id);
|
|
333
401
|
return true;
|
|
@@ -353,6 +421,7 @@ export function claimAgentChatOpenRequest(id: unknown): boolean {
|
|
|
353
421
|
export function _resetAgentChatSubmitBufferForTests(): void {
|
|
354
422
|
bufferedSelfSubmits.length = 0;
|
|
355
423
|
claimedSubmitIds.clear();
|
|
424
|
+
cancelledSubmitIds.clear();
|
|
356
425
|
bufferedOpenRequests.length = 0;
|
|
357
426
|
claimedOpenRequestIds.clear();
|
|
358
427
|
}
|
|
@@ -896,7 +965,7 @@ export function sendToAgentChat(opts: AgentChatMessage): string {
|
|
|
896
965
|
return tabId;
|
|
897
966
|
}
|
|
898
967
|
|
|
899
|
-
const submitMessageId = generateSubmitMessageId();
|
|
968
|
+
const submitMessageId = opts.submitMessageId ?? generateSubmitMessageId();
|
|
900
969
|
const payload = {
|
|
901
970
|
type: AGENT_CHAT_MESSAGE_TYPE,
|
|
902
971
|
data: {
|
|
@@ -977,6 +1046,101 @@ export function sendToAgentChat(opts: AgentChatMessage): string {
|
|
|
977
1046
|
return tabId;
|
|
978
1047
|
}
|
|
979
1048
|
|
|
1049
|
+
// Must exceed SELF_SUBMIT_BUFFER_TTL_MS. Otherwise confirmation can time out
|
|
1050
|
+
// while its replay is still eligible to mount and deliver later.
|
|
1051
|
+
const DEFAULT_SUBMIT_CONFIRM_TIMEOUT_MS = SELF_SUBMIT_BUFFER_TTL_MS + 2000;
|
|
1052
|
+
|
|
1053
|
+
export interface SendToAgentChatAndConfirmResult {
|
|
1054
|
+
tabId: string;
|
|
1055
|
+
/** True once the message actually became a visible turn in the chat. */
|
|
1056
|
+
delivered: boolean;
|
|
1057
|
+
/** Set when `delivered` is false: "missing-engine", "timeout", etc. */
|
|
1058
|
+
reason?: string;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Like {@link sendToAgentChat}, but resolves once the submit's fate is known
|
|
1063
|
+
* instead of firing and forgetting. Use this whenever the caller must decide
|
|
1064
|
+
* whether to keep/restore its own state on failure (e.g. a draw/annotate
|
|
1065
|
+
* overlay that should not discard the user's work unless the message actually
|
|
1066
|
+
* reached the chat) — see the `AGENT_CHAT_SUBMIT_RESULT_EVENT` contract.
|
|
1067
|
+
* This acknowledgement is intentionally limited to submitted, non-code
|
|
1068
|
+
* messages with `chatTarget: "local"`; parent-frame and MCP host chats use
|
|
1069
|
+
* different delivery protocols and return `unsupported-target` here.
|
|
1070
|
+
*
|
|
1071
|
+
* Resolves `delivered: false` if the receiving chat explicitly rejects the
|
|
1072
|
+
* submit (e.g. no LLM/agent engine configured) OR if no result arrives within
|
|
1073
|
+
* `timeoutMs` — a silently-stuck submit (panel never mounts, thread never
|
|
1074
|
+
* gets a ref, message type not handled by this build) must fail the same way
|
|
1075
|
+
* an explicit rejection does, since the caller cannot otherwise tell the
|
|
1076
|
+
* difference between "still in flight" and "dropped."
|
|
1077
|
+
*/
|
|
1078
|
+
export function sendToAgentChatAndConfirm(
|
|
1079
|
+
opts: Omit<AgentChatMessage, "submitMessageId">,
|
|
1080
|
+
options?: { timeoutMs?: number },
|
|
1081
|
+
): Promise<SendToAgentChatAndConfirmResult> {
|
|
1082
|
+
const tabId = opts.tabId ?? generateTabId();
|
|
1083
|
+
if (typeof window === "undefined") {
|
|
1084
|
+
return Promise.resolve({ tabId, delivered: false, reason: "no-window" });
|
|
1085
|
+
}
|
|
1086
|
+
// Confirmation is deliberately a same-window/local-chat contract. Parent
|
|
1087
|
+
// frames, Builder code chat, and MCP host relays have independent protocols
|
|
1088
|
+
// and cannot answer this window-local CustomEvent acknowledgement.
|
|
1089
|
+
if (
|
|
1090
|
+
opts.chatTarget !== "local" ||
|
|
1091
|
+
opts.type === "code" ||
|
|
1092
|
+
opts.requiresCode === true ||
|
|
1093
|
+
opts.submit === false
|
|
1094
|
+
) {
|
|
1095
|
+
return Promise.resolve({
|
|
1096
|
+
tabId,
|
|
1097
|
+
delivered: false,
|
|
1098
|
+
reason: "unsupported-target",
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
const submitMessageId = generateSubmitMessageId();
|
|
1103
|
+
const timeoutMs = Math.max(
|
|
1104
|
+
0,
|
|
1105
|
+
options?.timeoutMs ?? DEFAULT_SUBMIT_CONFIRM_TIMEOUT_MS,
|
|
1106
|
+
);
|
|
1107
|
+
|
|
1108
|
+
return new Promise<SendToAgentChatAndConfirmResult>((resolve) => {
|
|
1109
|
+
let settled = false;
|
|
1110
|
+
let timer: number | undefined;
|
|
1111
|
+
const cleanup = () => {
|
|
1112
|
+
window.removeEventListener(
|
|
1113
|
+
AGENT_CHAT_SUBMIT_RESULT_EVENT,
|
|
1114
|
+
onResult as EventListener,
|
|
1115
|
+
);
|
|
1116
|
+
if (timer !== undefined) window.clearTimeout(timer);
|
|
1117
|
+
};
|
|
1118
|
+
const finish = (delivered: boolean, reason?: string, cancel = false) => {
|
|
1119
|
+
if (settled) return;
|
|
1120
|
+
settled = true;
|
|
1121
|
+
if (cancel) cancelAgentChatSubmit(submitMessageId);
|
|
1122
|
+
cleanup();
|
|
1123
|
+
resolve({ tabId, delivered, reason });
|
|
1124
|
+
};
|
|
1125
|
+
const onResult = (event: Event) => {
|
|
1126
|
+
const detail = (event as CustomEvent<AgentChatSubmitResult>).detail;
|
|
1127
|
+
if (!detail || detail.submitMessageId !== submitMessageId) return;
|
|
1128
|
+
finish(detail.delivered, detail.reason);
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
window.addEventListener(
|
|
1132
|
+
AGENT_CHAT_SUBMIT_RESULT_EVENT,
|
|
1133
|
+
onResult as EventListener,
|
|
1134
|
+
);
|
|
1135
|
+
timer = window.setTimeout(() => finish(false, "timeout", true), timeoutMs);
|
|
1136
|
+
try {
|
|
1137
|
+
sendToAgentChat({ ...opts, tabId, submitMessageId });
|
|
1138
|
+
} catch {
|
|
1139
|
+
finish(false, "send-failed", true);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
|
|
980
1144
|
/**
|
|
981
1145
|
* Add or replace a keyed context nugget in the active agent chat composer.
|
|
982
1146
|
* The context is not submitted until the user sends the prompt.
|
|
@@ -59,7 +59,15 @@ export {
|
|
|
59
59
|
} from "../code-agent-chat-adapter.js";
|
|
60
60
|
export * from "./connectors.js";
|
|
61
61
|
export * from "./runtime.js";
|
|
62
|
-
export {
|
|
62
|
+
export {
|
|
63
|
+
sendToAgentChat,
|
|
64
|
+
sendToAgentChatAndConfirm,
|
|
65
|
+
reportAgentChatSubmitResult,
|
|
66
|
+
AGENT_CHAT_SUBMIT_RESULT_EVENT,
|
|
67
|
+
type AgentChatMessage,
|
|
68
|
+
type AgentChatSubmitResult,
|
|
69
|
+
type SendToAgentChatAndConfirmResult,
|
|
70
|
+
} from "../agent-chat.js";
|
|
63
71
|
export { useAgentChatGenerating } from "../use-agent-chat.js";
|
|
64
72
|
export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
|
|
65
73
|
export {
|
|
@@ -85,6 +85,31 @@ function serializeChatValue(value: unknown): string | undefined {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Slot contexts (e.g. Design's `DesignExtensionSlotContext`) commonly carry
|
|
90
|
+
* live callback functions alongside plain data — the host component uses
|
|
91
|
+
* those callbacks itself, but `window.postMessage` uses the structured clone
|
|
92
|
+
* algorithm, which throws a `DataCloneError` on any function-valued property
|
|
93
|
+
* (see MDN's postMessage docs). Round-tripping through JSON drops functions
|
|
94
|
+
* (and other non-cloneable values like symbols) the same way
|
|
95
|
+
* `JSON.stringify` already silently omits them, producing a payload that's
|
|
96
|
+
* safe to post. Exported so a test can verify functions never reach the
|
|
97
|
+
* iframe instead of only reading the code.
|
|
98
|
+
*/
|
|
99
|
+
export function sanitizeSlotContextForPostMessage(
|
|
100
|
+
context: Record<string, unknown> | null | undefined,
|
|
101
|
+
): Record<string, unknown> {
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(JSON.stringify(context ?? {}));
|
|
104
|
+
} catch {
|
|
105
|
+
// Circular reference or other non-serializable shape — fail safe to an
|
|
106
|
+
// empty context rather than letting postMessage throw and skip every
|
|
107
|
+
// other message this handler sends in the same tick (theme update,
|
|
108
|
+
// ready signal).
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
88
113
|
export interface EmbeddedExtensionProps {
|
|
89
114
|
extensionId: string;
|
|
90
115
|
/** Slot identifier passed via the iframe URL so the extension runtime knows it's
|
|
@@ -243,8 +268,16 @@ export function EmbeddedExtension({
|
|
|
243
268
|
useEffect(() => {
|
|
244
269
|
const win = iframeRef.current?.contentWindow;
|
|
245
270
|
if (!win) return;
|
|
271
|
+
// Post the JSON-round-tripped context, not the raw `context` object —
|
|
272
|
+
// slot contexts (e.g. Design's DesignExtensionSlotContext) carry live
|
|
273
|
+
// callback functions the host uses internally, and postMessage's
|
|
274
|
+
// structured clone throws a DataCloneError on any function-valued
|
|
275
|
+
// property. See sanitizeSlotContextForPostMessage's docblock.
|
|
246
276
|
win.postMessage(
|
|
247
|
-
{
|
|
277
|
+
{
|
|
278
|
+
type: "agent-native-slot-context",
|
|
279
|
+
context: sanitizeSlotContextForPostMessage(context),
|
|
280
|
+
},
|
|
248
281
|
"*",
|
|
249
282
|
);
|
|
250
283
|
}, [contextJson]);
|
|
@@ -400,7 +433,10 @@ export function EmbeddedExtension({
|
|
|
400
433
|
style={{ width: "100%", border: 0, height, display: "block" }}
|
|
401
434
|
onLoad={() => {
|
|
402
435
|
iframeRef.current?.contentWindow?.postMessage(
|
|
403
|
-
{
|
|
436
|
+
{
|
|
437
|
+
type: "agent-native-slot-context",
|
|
438
|
+
context: sanitizeSlotContextForPostMessage(context),
|
|
439
|
+
},
|
|
404
440
|
"*",
|
|
405
441
|
);
|
|
406
442
|
// Re-assert theme once the iframe document is live. The src bakes in
|
|
@@ -19,6 +19,9 @@ export {
|
|
|
19
19
|
requestAgentChatThreadOpen,
|
|
20
20
|
requestAgentTaskOpen,
|
|
21
21
|
sendToAgentChat,
|
|
22
|
+
sendToAgentChatAndConfirm,
|
|
23
|
+
reportAgentChatSubmitResult,
|
|
24
|
+
AGENT_CHAT_SUBMIT_RESULT_EVENT,
|
|
22
25
|
parseSubmitChatMessage,
|
|
23
26
|
setAgentChatContextItem,
|
|
24
27
|
setContextToAgentChat,
|
|
@@ -33,6 +36,8 @@ export {
|
|
|
33
36
|
type AgentChatContextSetOptions,
|
|
34
37
|
type AgentChatContextState,
|
|
35
38
|
type AgentChatMessage,
|
|
39
|
+
type AgentChatSubmitResult,
|
|
40
|
+
type SendToAgentChatAndConfirmResult,
|
|
36
41
|
type AgentComposerReference,
|
|
37
42
|
type AgentComposerReferenceInsertOptions,
|
|
38
43
|
type AgentComposerReferenceInsertPayload,
|
|
@@ -385,6 +385,8 @@ export function useCollabReconcile({
|
|
|
385
385
|
const editorUnchangedSinceApply =
|
|
386
386
|
lastAppliedSerializedRef.current !== null &&
|
|
387
387
|
currentMarkdown === lastAppliedSerializedRef.current;
|
|
388
|
+
const typingRecently =
|
|
389
|
+
editor.isFocused && Date.now() - lastTypedAtRef.current < 1500;
|
|
388
390
|
|
|
389
391
|
// Doc-equivalence skip. Never re-apply content the editor already
|
|
390
392
|
// represents — comparing by DOC EQUIVALENCE, not raw strings/timestamps:
|
|
@@ -407,11 +409,15 @@ export function useCollabReconcile({
|
|
|
407
409
|
// `<p>` → `<p>` → `&lt;p&gt;` escalation.
|
|
408
410
|
if (
|
|
409
411
|
currentMarkdown === normalizedValue ||
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
412
|
+
(typingRecently &&
|
|
413
|
+
// A stale echo of our own (possibly partial) save while the user is
|
|
414
|
+
// actively typing would clobber the fresh tail. Outside active
|
|
415
|
+
// typing, the same bytes can be a deliberate newer external revert
|
|
416
|
+
// (history restore / provider conflict choice) and must be allowed
|
|
417
|
+
// through even if mount-time normalization emitted them.
|
|
418
|
+
(value === lastEmittedRef.current ||
|
|
419
|
+
recentEmittedRef.current.includes(value) ||
|
|
420
|
+
recentEmittedRef.current.includes(normalizedValue))) ||
|
|
415
421
|
(editorUnchangedSinceApply &&
|
|
416
422
|
(value === lastAppliedValueRef.current ||
|
|
417
423
|
normalizedValue === lastAppliedSerializedRef.current))
|
|
@@ -442,8 +448,6 @@ export function useCollabReconcile({
|
|
|
442
448
|
// for non-idempotent input, fight every keystroke. Newer external content
|
|
443
449
|
// retries so it still lands once they pause; older-or-equal content is a
|
|
444
450
|
// stale poll and is dropped outright while focused.
|
|
445
|
-
const typingRecently =
|
|
446
|
-
editor.isFocused && Date.now() - lastTypedAtRef.current < 1500;
|
|
447
451
|
if (typingRecently) {
|
|
448
452
|
if (externalNewer) {
|
|
449
453
|
retry = setTimeout(() => apply(deferred), 700);
|
|
@@ -549,6 +553,13 @@ export function useCollabReconcile({
|
|
|
549
553
|
|
|
550
554
|
const shouldIgnoreUpdate = (transaction: Transaction): boolean => {
|
|
551
555
|
if (!editable || isSettingContentRef.current) return true;
|
|
556
|
+
// Collaboration can emit schema/default-paragraph transactions while the
|
|
557
|
+
// persisted Y.Doc is still loading and before the authoritative value has
|
|
558
|
+
// seeded/reconciled. Never let those transient pre-seed updates reach an
|
|
559
|
+
// app's local mirror or autosave path (Content serializes an empty paragraph
|
|
560
|
+
// as `<empty-block/>`, which is non-empty text and bypasses the generic
|
|
561
|
+
// registerEmitted empty-string guard).
|
|
562
|
+
if (collab && !seededRef.current) return true;
|
|
552
563
|
if (transaction.getMeta(RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION)) {
|
|
553
564
|
return true;
|
|
554
565
|
}
|
|
@@ -149,23 +149,34 @@ export async function loadAwarenessRows(
|
|
|
149
149
|
now: number = Date.now(),
|
|
150
150
|
): Promise<AwarenessEntry[]> {
|
|
151
151
|
try {
|
|
152
|
-
await
|
|
153
|
-
const client = getDbExec();
|
|
154
|
-
const { rows } = await client.execute({
|
|
155
|
-
sql: `SELECT client_id, state, last_seen FROM _collab_awareness
|
|
156
|
-
WHERE doc_id = ? AND last_seen >= ?`,
|
|
157
|
-
args: [docId, now - ROW_TTL_MS],
|
|
158
|
-
});
|
|
159
|
-
return rows.map((row: any) => ({
|
|
160
|
-
clientId: Number(row.client_id),
|
|
161
|
-
state: String(row.state),
|
|
162
|
-
lastSeen: Number(row.last_seen),
|
|
163
|
-
}));
|
|
152
|
+
return await loadAwarenessRowsStrict(docId, now);
|
|
164
153
|
} catch {
|
|
165
154
|
return [];
|
|
166
155
|
}
|
|
167
156
|
}
|
|
168
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Strict awareness read for safety-critical callers that must distinguish
|
|
160
|
+
* "no active participants" from "presence storage could not be read."
|
|
161
|
+
*/
|
|
162
|
+
export async function loadAwarenessRowsStrict(
|
|
163
|
+
docId: string,
|
|
164
|
+
now: number = Date.now(),
|
|
165
|
+
): Promise<AwarenessEntry[]> {
|
|
166
|
+
await ensureTable();
|
|
167
|
+
const client = getDbExec();
|
|
168
|
+
const { rows } = await client.execute({
|
|
169
|
+
sql: `SELECT client_id, state, last_seen FROM _collab_awareness
|
|
170
|
+
WHERE doc_id = ? AND last_seen >= ?`,
|
|
171
|
+
args: [docId, now - ROW_TTL_MS],
|
|
172
|
+
});
|
|
173
|
+
return rows.map((row: any) => ({
|
|
174
|
+
clientId: Number(row.client_id),
|
|
175
|
+
state: String(row.state),
|
|
176
|
+
lastSeen: Number(row.last_seen),
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
|
|
169
180
|
async function maybePurge(docId: string, now: number): Promise<void> {
|
|
170
181
|
const last = _lastPurges.get(docId) ?? 0;
|
|
171
182
|
if (now - last < PURGE_INTERVAL_MS) return;
|