@agent-native/core 0.92.10 → 0.92.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +214 -17
  5. package/corpus/core/src/agent/run-manager.ts +72 -14
  6. package/corpus/core/src/agent/run-store.ts +152 -27
  7. package/corpus/core/src/cli/design-connect.ts +433 -151
  8. package/corpus/core/src/cli/skills.ts +14 -0
  9. package/corpus/core/src/client/AssistantChat.tsx +25 -0
  10. package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
  11. package/corpus/core/src/client/agent-chat-adapter.ts +56 -12
  12. package/corpus/core/src/client/agent-chat.ts +165 -1
  13. package/corpus/core/src/client/chat/index.ts +9 -1
  14. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
  15. package/corpus/core/src/client/index.ts +5 -0
  16. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
  17. package/corpus/core/src/collab/awareness-store.ts +23 -12
  18. package/corpus/core/src/collab/client.ts +16 -5
  19. package/corpus/core/src/collab/index.ts +4 -0
  20. package/corpus/core/src/collab/recent-edits.ts +65 -2
  21. package/corpus/core/src/index.browser.ts +1 -0
  22. package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
  23. package/corpus/core/src/server/builder-design-systems.ts +30 -4
  24. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
  25. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
  26. package/corpus/templates/clips/AGENTS.md +4 -0
  27. package/corpus/templates/clips/actions/create-recording.ts +2 -0
  28. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
  29. package/corpus/templates/clips/actions/request-transcript.ts +102 -33
  30. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
  31. package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
  32. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +75 -9
  33. package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
  34. package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
  35. package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
  36. package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
  37. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  38. package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
  39. package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
  40. package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
  41. package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
  42. package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
  43. package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
  44. package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
  45. package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
  46. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
  47. package/corpus/templates/clips/app/routes/record.tsx +17 -4
  48. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
  49. package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
  52. package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
  53. package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
  54. package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
  55. package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
  56. package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
  57. package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
  58. package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
  59. package/corpus/templates/clips/desktop/src/app.tsx +12 -2
  60. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
  61. package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
  62. package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
  63. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
  64. package/corpus/templates/clips/desktop/src/styles.css +6 -3
  65. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
  66. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
  67. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
  68. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
  69. package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
  70. package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
  71. package/corpus/templates/clips/shared/recording-core.ts +12 -0
  72. package/corpus/templates/content/AGENTS.md +7 -6
  73. package/corpus/templates/content/actions/_builder-cms-read-client.ts +82 -7
  74. package/corpus/templates/content/actions/_database-source-utils.ts +149 -30
  75. package/corpus/templates/content/actions/_document-flush.ts +132 -17
  76. package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
  77. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +4 -7
  78. package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
  79. package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
  80. package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
  81. package/corpus/templates/content/actions/link-notion-page.ts +2 -0
  82. package/corpus/templates/content/actions/pull-document.ts +5 -7
  83. package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
  84. package/corpus/templates/content/actions/push-notion-page.ts +10 -0
  85. package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
  86. package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
  87. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
  88. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
  89. package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
  90. package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
  91. package/corpus/templates/content/app/i18n-data.ts +18 -0
  92. package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
  93. package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
  94. package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
  95. package/corpus/templates/content/shared/api.ts +1 -0
  96. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
  97. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
  98. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
  99. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
  100. package/corpus/templates/design/AGENTS.md +45 -10
  101. package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
  102. package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
  103. package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
  104. package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
  105. package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
  106. package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
  107. package/corpus/templates/design/actions/generate-design.ts +79 -12
  108. package/corpus/templates/design/actions/generate-screens.ts +57 -12
  109. package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
  110. package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
  111. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
  112. package/corpus/templates/design/actions/import-design-source.ts +4 -31
  113. package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
  114. package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
  115. package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
  116. package/corpus/templates/design/actions/list-design-components.ts +104 -0
  117. package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
  118. package/corpus/templates/design/actions/open-component-source.ts +2 -4
  119. package/corpus/templates/design/actions/present-design-variants.ts +412 -16
  120. package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
  121. package/corpus/templates/design/actions/run-design-audit.ts +25 -3
  122. package/corpus/templates/design/actions/show-design-questions.ts +10 -0
  123. package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
  124. package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
  125. package/corpus/templates/design/actions/write-local-file.ts +25 -1
  126. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
  127. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
  128. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
  129. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
  130. package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
  131. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
  132. package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
  133. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
  134. package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
  135. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
  136. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
  137. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
  138. package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
  139. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
  140. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
  141. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
  142. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
  143. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
  144. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
  145. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
  146. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
  147. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
  148. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
  149. package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
  150. package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
  151. package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
  152. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
  153. package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
  154. package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
  155. package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
  156. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
  157. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
  158. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
  159. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
  160. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
  161. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
  162. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
  163. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
  164. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
  165. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
  166. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
  167. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
  168. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
  169. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
  170. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
  171. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
  172. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
  173. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
  174. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
  175. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
  176. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
  177. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
  178. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
  179. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
  180. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
  181. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
  182. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
  183. package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
  184. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
  185. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
  186. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
  187. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
  188. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
  189. package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
  190. package/corpus/templates/design/app/components/design/types.ts +33 -0
  191. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
  192. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
  193. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
  194. package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
  195. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
  196. package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
  197. package/corpus/templates/design/app/i18n-data.ts +1217 -10
  198. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
  199. package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
  200. package/corpus/templates/design/app/lib/design-import.ts +24 -0
  201. package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
  202. package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
  203. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
  204. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
  205. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
  206. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
  207. package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
  208. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
  209. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
  210. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
  211. package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
  212. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
  213. package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
  239. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
  240. package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
  241. package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
  242. package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
  243. package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
  244. package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
  245. package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
  246. package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
  247. package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
  249. package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
  250. package/corpus/templates/design/e2e/global-setup.ts +3 -6
  251. package/corpus/templates/design/e2e/helpers.ts +27 -6
  252. package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
  253. package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
  254. package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
  255. package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
  256. package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
  257. package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
  258. package/corpus/templates/design/server/plugins/db.ts +41 -0
  259. package/corpus/templates/design/server/source-workspace.ts +64 -0
  260. package/corpus/templates/design/shared/board-file.ts +13 -2
  261. package/corpus/templates/design/shared/canvas-math.ts +231 -33
  262. package/corpus/templates/design/shared/code-layer.ts +122 -8
  263. package/corpus/templates/design/shared/component-library.ts +161 -0
  264. package/corpus/templates/design/shared/db-conflict.ts +27 -0
  265. package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
  266. package/corpus/templates/design/shared/figma-url.ts +149 -0
  267. package/corpus/templates/design/shared/pen-path.ts +16 -7
  268. package/corpus/templates/design/shared/source-mode.ts +1 -0
  269. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
  270. package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
  271. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
  272. package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
  273. package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
  274. package/dist/agent/production-agent.d.ts +82 -7
  275. package/dist/agent/production-agent.d.ts.map +1 -1
  276. package/dist/agent/production-agent.js +180 -17
  277. package/dist/agent/production-agent.js.map +1 -1
  278. package/dist/agent/run-manager.d.ts.map +1 -1
  279. package/dist/agent/run-manager.js +63 -14
  280. package/dist/agent/run-manager.js.map +1 -1
  281. package/dist/agent/run-store.d.ts +46 -0
  282. package/dist/agent/run-store.d.ts.map +1 -1
  283. package/dist/agent/run-store.js +129 -22
  284. package/dist/agent/run-store.js.map +1 -1
  285. package/dist/cli/design-connect.d.ts +6 -0
  286. package/dist/cli/design-connect.d.ts.map +1 -1
  287. package/dist/cli/design-connect.js +336 -139
  288. package/dist/cli/design-connect.js.map +1 -1
  289. package/dist/cli/skills.d.ts.map +1 -1
  290. package/dist/cli/skills.js +14 -0
  291. package/dist/cli/skills.js.map +1 -1
  292. package/dist/client/AssistantChat.d.ts +2 -0
  293. package/dist/client/AssistantChat.d.ts.map +1 -1
  294. package/dist/client/AssistantChat.js +19 -3
  295. package/dist/client/AssistantChat.js.map +1 -1
  296. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  297. package/dist/client/MultiTabAssistantChat.js +38 -18
  298. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  299. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  300. package/dist/client/agent-chat-adapter.js +48 -12
  301. package/dist/client/agent-chat-adapter.js.map +1 -1
  302. package/dist/client/agent-chat.d.ts +60 -0
  303. package/dist/client/agent-chat.d.ts.map +1 -1
  304. package/dist/client/agent-chat.js +122 -1
  305. package/dist/client/agent-chat.js.map +1 -1
  306. package/dist/client/chat/index.d.ts +1 -1
  307. package/dist/client/chat/index.d.ts.map +1 -1
  308. package/dist/client/chat/index.js +1 -1
  309. package/dist/client/chat/index.js.map +1 -1
  310. package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
  311. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  312. package/dist/client/extensions/EmbeddedExtension.js +36 -2
  313. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  314. package/dist/client/index.d.ts +1 -1
  315. package/dist/client/index.d.ts.map +1 -1
  316. package/dist/client/index.js +1 -1
  317. package/dist/client/index.js.map +1 -1
  318. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  319. package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
  320. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  321. package/dist/collab/awareness-store.d.ts +5 -0
  322. package/dist/collab/awareness-store.d.ts.map +1 -1
  323. package/dist/collab/awareness-store.js +19 -12
  324. package/dist/collab/awareness-store.js.map +1 -1
  325. package/dist/collab/awareness.d.ts +2 -2
  326. package/dist/collab/awareness.d.ts.map +1 -1
  327. package/dist/collab/client.d.ts.map +1 -1
  328. package/dist/collab/client.js +13 -5
  329. package/dist/collab/client.js.map +1 -1
  330. package/dist/collab/index.d.ts +1 -0
  331. package/dist/collab/index.d.ts.map +1 -1
  332. package/dist/collab/index.js +1 -0
  333. package/dist/collab/index.js.map +1 -1
  334. package/dist/collab/recent-edits.d.ts +3 -1
  335. package/dist/collab/recent-edits.d.ts.map +1 -1
  336. package/dist/collab/recent-edits.js +57 -2
  337. package/dist/collab/recent-edits.js.map +1 -1
  338. package/dist/collab/struct-routes.d.ts +1 -1
  339. package/dist/index.browser.d.ts +1 -1
  340. package/dist/index.browser.d.ts.map +1 -1
  341. package/dist/index.browser.js +1 -1
  342. package/dist/index.browser.js.map +1 -1
  343. package/dist/observability/routes.d.ts +5 -5
  344. package/dist/progress/routes.d.ts +1 -1
  345. package/dist/resources/handlers.d.ts +3 -3
  346. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  347. package/dist/server/agent-chat-plugin.js +87 -10
  348. package/dist/server/agent-chat-plugin.js.map +1 -1
  349. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  350. package/dist/server/builder-design-systems.d.ts +15 -0
  351. package/dist/server/builder-design-systems.d.ts.map +1 -1
  352. package/dist/server/builder-design-systems.js +9 -4
  353. package/dist/server/builder-design-systems.js.map +1 -1
  354. 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) return;
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).then((newId) => {
1830
- if (newId) {
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) {
@@ -1,6 +1,10 @@
1
1
  import type { ChatModelAdapter, ChatModelRunResult } from "@assistant-ui/react";
2
2
 
3
3
  import { actionPreparationContinuationNote } from "../agent/action-continuation-guidance.js";
4
+ import {
5
+ LLM_MISSING_CREDENTIALS_ERROR_CODE,
6
+ LLM_MISSING_CREDENTIALS_MESSAGE,
7
+ } from "../agent/engine/credential-errors.js";
4
8
  import type {
5
9
  AgentChatStructuredContentPart,
6
10
  AgentChatStructuredMessage,
@@ -157,7 +161,9 @@ const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 150_000;
157
161
  * (`agent_runs.terminal_reason`, surfaced by /runs/active). These runs died in
158
162
  * server-side handoff machinery where no richer error event may exist, so the
159
163
  * client owns the message. Keys are matched after stripping an optional
160
- * `error:` prefix (`terminalReasonForEvent` records `error:<code>`).
164
+ * `error:` prefix (`terminalReasonForEvent` records `error:<code>`). Keep this
165
+ * map scoped to terminal failures, including reasons that must override a
166
+ * mistakenly completed row.
161
167
  */
162
168
  const BACKGROUND_TERMINAL_REASON_MESSAGES: Record<string, string> = {
163
169
  background_worker_never_started:
@@ -166,6 +172,8 @@ const BACKGROUND_TERMINAL_REASON_MESSAGES: Record<string, string> = {
166
172
  "The agent's background worker could not hand off the next step of this run. Retry to continue from the preserved context.",
167
173
  dispatch_payload_missing:
168
174
  "The agent's background run lost its saved request data and could not continue. Retry to start a fresh run.",
175
+ missing_api_key: LLM_MISSING_CREDENTIALS_MESSAGE,
176
+ missing_credentials: LLM_MISSING_CREDENTIALS_MESSAGE,
169
177
  turn_continuation_budget_exhausted:
170
178
  "This request needed more automatic continuations than allowed and was stopped. Try breaking it into smaller steps.",
171
179
  };
@@ -1761,6 +1769,11 @@ export function createAgentChatAdapter(
1761
1769
  nextRunId: string,
1762
1770
  previousRunId: string | null,
1763
1771
  ) => {
1772
+ if (previousRunId !== nextRunId) {
1773
+ lastAutoContinueReason = null;
1774
+ lastRecoverableRunError = null;
1775
+ lastActivityTrail = [];
1776
+ }
1764
1777
  const rememberedSeq = seenRunSeqs.get(nextRunId);
1765
1778
  if (rememberedSeq !== undefined) {
1766
1779
  lastSeq = rememberedSeq;
@@ -2132,6 +2145,9 @@ export function createAgentChatAdapter(
2132
2145
  ...(runId ? { runId } : {}),
2133
2146
  };
2134
2147
  if (typeof window !== "undefined") {
2148
+ if (args.errorCode === LLM_MISSING_CREDENTIALS_ERROR_CODE) {
2149
+ dispatchMissingApiKey();
2150
+ }
2135
2151
  window.dispatchEvent(
2136
2152
  new CustomEvent("agent-chat:run-error", {
2137
2153
  detail: { ...runError, tabId },
@@ -2169,7 +2185,46 @@ export function createAgentChatAdapter(
2169
2185
  : "";
2170
2186
  // terminal_reason is either a bare reason ("dispatch_payload_missing")
2171
2187
  // or "error:<errorCode>" when derived from a terminal error event.
2188
+ const hasErrorTerminalReason = rawTerminalReason.startsWith("error:");
2172
2189
  const terminalReason = rawTerminalReason.replace(/^error:/, "");
2190
+ const mappedMessage = terminalReason
2191
+ ? BACKGROUND_TERMINAL_REASON_MESSAGES[terminalReason]
2192
+ : undefined;
2193
+ const mappedErrorCode =
2194
+ terminalReason === "missing_api_key" ||
2195
+ terminalReason === LLM_MISSING_CREDENTIALS_ERROR_CODE
2196
+ ? LLM_MISSING_CREDENTIALS_ERROR_CODE
2197
+ : terminalReason;
2198
+
2199
+ if (mappedMessage) {
2200
+ yield* emitBackgroundTerminalError({
2201
+ message: mappedMessage,
2202
+ errorCode: mappedErrorCode,
2203
+ details: `terminal_reason: ${rawTerminalReason}`,
2204
+ });
2205
+ return;
2206
+ }
2207
+
2208
+ if (hasErrorTerminalReason) {
2209
+ if (lastRecoverableRunError) {
2210
+ yield* emitBackgroundTerminalError({
2211
+ message: lastRecoverableRunError.message,
2212
+ errorCode:
2213
+ lastRecoverableRunError.errorCode ||
2214
+ mappedErrorCode ||
2215
+ "background_run_failed",
2216
+ details: lastRecoverableRunError.details,
2217
+ });
2218
+ return;
2219
+ }
2220
+ yield* emitBackgroundTerminalError({
2221
+ message:
2222
+ "The agent's background run failed before its final response could be recovered. You can retry from the preserved chat context.",
2223
+ errorCode: mappedErrorCode || "background_run_failed",
2224
+ details: `terminal_reason: ${rawTerminalReason}`,
2225
+ });
2226
+ return;
2227
+ }
2173
2228
 
2174
2229
  if (status === "completed") {
2175
2230
  // The turn finished server-side; the events we managed to fold are
@@ -2186,17 +2241,6 @@ export function createAgentChatAdapter(
2186
2241
  return;
2187
2242
  }
2188
2243
 
2189
- const mappedMessage = terminalReason
2190
- ? BACKGROUND_TERMINAL_REASON_MESSAGES[terminalReason]
2191
- : undefined;
2192
- if (mappedMessage) {
2193
- yield* emitBackgroundTerminalError({
2194
- message: mappedMessage,
2195
- errorCode: terminalReason,
2196
- details: `terminal_reason: ${rawTerminalReason}`,
2197
- });
2198
- return;
2199
- }
2200
2244
  if (lastRecoverableRunError) {
2201
2245
  // A replayed terminal error event already carried the real
2202
2246
  // message (recoverable errors replay as auto-continue signals
@@ -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 { sendToAgentChat, type AgentChatMessage } from "../agent-chat.js";
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
- { type: "agent-native-slot-context", context: context ?? {} },
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
- { type: "agent-native-slot-context", context: context ?? {} },
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,