@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
@@ -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>` → `&lt;p&gt;` → `&amp;lt;p&amp;gt;` escalation.
408
410
  if (
409
411
  currentMarkdown === normalizedValue ||
410
- value === lastEmittedRef.current ||
411
- // A stale-but-recent echo of our own (possibly partial) save applying
412
- // it would clobber the freshly-typed tail. External edits never match.
413
- recentEmittedRef.current.includes(value) ||
414
- recentEmittedRef.current.includes(normalizedValue) ||
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 ensureTable();
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;
@@ -579,7 +579,10 @@ class CollabDocConnection {
579
579
  this.awareness.setLocalStateField("visible", !isDocumentHidden());
580
580
  }
581
581
 
582
- private handleAwarenessChange = (): void => {
582
+ private handleAwarenessChange = (
583
+ _changes?: { added: number[]; updated: number[]; removed: number[] },
584
+ origin?: unknown,
585
+ ): void => {
583
586
  const users: CollabUser[] = [];
584
587
  let hasAgent = false;
585
588
  this.awareness.getStates().forEach((state, clientId) => {
@@ -616,12 +619,20 @@ class CollabDocConnection {
616
619
  this.setSnapshot({ activeUsers, agentPresent: hasAgent });
617
620
  }
618
621
 
619
- // Fast awareness push: whenever awareness changes (e.g. cursor moves,
620
- // setPresence() calls), schedule a throttled POST so peers receive updates
621
- // at ~150ms instead of waiting for the next poll cycle. Only active once a
622
+ // Fast awareness push: whenever OUR OWN awareness state changes (e.g.
623
+ // cursor moves, setPresence() calls), schedule a throttled POST so peers
624
+ // receive updates at ~150ms instead of waiting for the next poll cycle.
625
+ // Gated on origin === "local": this listener also fires for remote
626
+ // awareness changes (poll/SSE call `awareness.emit("change", [changes,
627
+ // "remote"])` after reconciling incoming states — see
628
+ // applyAwarenessEvent/poll above). Without the origin check, every
629
+ // peer's cursor move would also re-trigger THIS client to re-broadcast
630
+ // its own unchanged state, turning one person moving their mouse into
631
+ // O(n) redundant POSTs from every other connected client (an awareness
632
+ // storm that gets worse as more people join the doc). Only active once a
622
633
  // local user identity has been published (matches the previous per-hook
623
634
  // gating on `user`). The poll cycle remains the authoritative baseline.
624
- if (this.lastSetUser && !this.disposed) {
635
+ if (this.lastSetUser && origin === "local" && !this.disposed) {
625
636
  scheduleAwarenessPush(
626
637
  this.baseUrl,
627
638
  this.docId,
@@ -126,6 +126,10 @@ export {
126
126
  type AwarenessEntry,
127
127
  type AwarenessChangeEvent,
128
128
  } from "./awareness.js";
129
+ export {
130
+ loadAwarenessRows,
131
+ loadAwarenessRowsStrict,
132
+ } from "./awareness-store.js";
129
133
 
130
134
  // Presence kit
131
135
  export {
@@ -21,6 +21,7 @@ import {
21
21
  RECENT_EDIT_TTL_MS,
22
22
  type AttributedRecentEdit,
23
23
  type RecentEdit,
24
+ type RecentEditDescriptor,
24
25
  } from "@agent-native/toolkit/collab-ui";
25
26
  import { useEffect, useRef, useState } from "react";
26
27
 
@@ -34,16 +35,78 @@ export {
34
35
  type RecentEditDescriptor,
35
36
  } from "@agent-native/toolkit/collab-ui";
36
37
 
38
+ /**
39
+ * Hard cap on any single string carried in a recentEdits entry (quote,
40
+ * selector, path segment, label). Callers are expected to pass short
41
+ * excerpts already (existing call sites trim to 80–120 chars for a "what
42
+ * changed" snippet), but this is the ring's own size ceiling — a caller that
43
+ * forgets to trim (e.g. passing a whole paragraph/document as `quote`) must
44
+ * not blow up the awareness payload every connected client receives on the
45
+ * fast-push path, nor the `_collab_awareness` SQL row it gets mirrored into.
46
+ */
47
+ const RECENT_EDIT_STRING_MAX = 500;
48
+
49
+ function truncateString(value: string): string {
50
+ return value.length > RECENT_EDIT_STRING_MAX
51
+ ? value.slice(0, RECENT_EDIT_STRING_MAX)
52
+ : value;
53
+ }
54
+
55
+ function truncateDescriptor(
56
+ descriptor: RecentEditDescriptor,
57
+ ): RecentEditDescriptor {
58
+ // The union's last member (`{ kind: string; [key: string]: unknown }`) is an
59
+ // open-ended catch-all whose `kind` is a plain `string`, so a `switch` on
60
+ // `descriptor.kind` can't discriminate it away from the literal-kind
61
+ // members for the compiler — every property still type-checks as
62
+ // `unknown`. Read/write through an untyped view instead and lean on
63
+ // runtime checks; the return value is cast back to the real type below.
64
+ const d = descriptor as Record<string, unknown> & { kind: string };
65
+ if (d.kind === "text" && typeof d.quote === "string") {
66
+ return { ...d, quote: truncateString(d.quote) } as RecentEditDescriptor;
67
+ }
68
+ if (d.kind === "selector" && typeof d.selector === "string") {
69
+ return {
70
+ ...d,
71
+ selector: truncateString(d.selector),
72
+ } as RecentEditDescriptor;
73
+ }
74
+ if (d.kind === "paths" && Array.isArray(d.paths)) {
75
+ return {
76
+ ...d,
77
+ paths: d.paths.map((p) =>
78
+ typeof p === "string" ? truncateString(p) : p,
79
+ ),
80
+ } as RecentEditDescriptor;
81
+ }
82
+ if (d.kind === "doc") {
83
+ return descriptor;
84
+ }
85
+ // Open-ended shape — trim any string-valued fields defensively without
86
+ // knowing their names.
87
+ const trimmed: Record<string, unknown> = {};
88
+ for (const [key, value] of Object.entries(d)) {
89
+ trimmed[key] = typeof value === "string" ? truncateString(value) : value;
90
+ }
91
+ return trimmed as RecentEditDescriptor;
92
+ }
93
+
37
94
  /**
38
95
  * Append an edit to a recentEdits ring, keeping the newest
39
- * {@link RECENT_EDITS_MAX} entries. Pure — returns a new array.
96
+ * {@link RECENT_EDITS_MAX} entries. Pure — returns a new array. Descriptor
97
+ * strings and the label are truncated to {@link RECENT_EDIT_STRING_MAX}
98
+ * characters as a defensive cap on the awareness payload size.
40
99
  */
41
100
  export function appendRecentEdit(
42
101
  existing: RecentEdit[] | undefined,
43
102
  edit: RecentEdit,
44
103
  ): RecentEdit[] {
45
104
  const ring = Array.isArray(existing) ? existing.slice() : [];
46
- ring.push(edit);
105
+ ring.push({
106
+ ...edit,
107
+ descriptor: truncateDescriptor(edit.descriptor),
108
+ label: edit.label ? truncateString(edit.label) : edit.label,
109
+ });
47
110
  if (ring.length > RECENT_EDITS_MAX) {
48
111
  ring.splice(0, ring.length - RECENT_EDITS_MAX);
49
112
  }
@@ -10,6 +10,7 @@ export {
10
10
  refreshAgentChatContext,
11
11
  removeAgentChatContextItem,
12
12
  sendToAgentChat,
13
+ sendToAgentChatAndConfirm,
13
14
  setAgentChatContextItem,
14
15
  setContextToAgentChat,
15
16
  isEmbedMcpChatBridgeActive,
@@ -8561,10 +8561,34 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
8561
8561
  // covers the initial dispatch (a connected client is polling the claim),
8562
8562
  // but a server-chained CONTINUATION handoff has no foreground watching
8563
8563
  // it: if the dispatch is lost after the successor row was inserted, the
8564
- // row would sit at dispatch_mode='background' forever and the turn hangs
8565
- // silently. This sweep reaps such rows into a loud, attributable error
8566
- // (`background_worker_never_started`) that the client renders, instead
8567
- // of an idle spinner. Cheap: one indexed-ish query per 2-min window.
8564
+ // row would otherwise sit at dispatch_mode='background' forever and the
8565
+ // turn hangs silently. `chainServerDrivenContinuation` (production-agent.ts)
8566
+ // leaves exactly such a row behind — status='running', dispatch_mode=
8567
+ // 'background', `dispatch_payload` intact when it exhausts its own
8568
+ // dispatch retry budget, instead of erroring it immediately. This sweep
8569
+ // gives that row a real chance to RECOVER: within
8570
+ // `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS` of its original
8571
+ // `started_at` it redispatches the handoff (same `_process-run`
8572
+ // processor, same persisted payload); past that bound it falls back to
8573
+ // the existing loud reap (`background_worker_never_started`) so a
8574
+ // genuinely dead handoff still fails loud, never silently. A
8575
+ // redispatch is always safe to attempt — even a duplicate or
8576
+ // late-arriving one — because the worker's `claimBackgroundRun` atomic
8577
+ // CAS (status='running' AND dispatch_mode='background' -> 'background-
8578
+ // processing') is the sole gate on actual execution; a row that was
8579
+ // already claimed or already reaped by a concurrent path just loses the
8580
+ // CAS and no-ops. Cheap: one indexed-ish query per 2-min window.
8581
+ //
8582
+ // THREE-SITE INVARIANT (keep in lockstep): this sweep only ever sees the
8583
+ // deferred successor because the ~1s client poll in
8584
+ // `getActiveRunForThreadAsync` (run-manager.ts) skips its own
8585
+ // `reapUnclaimedBackgroundRun` while the row is within the redispatch
8586
+ // bound (`shouldRedispatchUnclaimedBackgroundRun`). If a future change
8587
+ // makes that client poll reap deferred successors at the 25s grace
8588
+ // again, this sweep will almost never win the race for connected clients.
8589
+ // Do not edit one site without the others (producer:
8590
+ // chainServerDrivenContinuation in production-agent.ts; guard:
8591
+ // run-manager.ts; recovery actor: here).
8568
8592
  (() => {
8569
8593
  let lastSweep = 0;
8570
8594
  const SWEEP_INTERVAL_MS = 2 * 60 * 1000;
@@ -8577,22 +8601,85 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
8577
8601
 
8578
8602
  (async () => {
8579
8603
  const {
8580
- listUnclaimedBackgroundRunIds,
8604
+ listUnclaimedBackgroundRunRows,
8581
8605
  reapUnclaimedBackgroundRun,
8606
+ updateRunHeartbeat,
8607
+ shouldRedispatchUnclaimedBackgroundRun,
8582
8608
  } = await import("../agent/run-store.js");
8583
- let runIds: string[];
8609
+ const { resolveAgentChatProcessRunDispatchPath } =
8610
+ await import("../agent/durable-background.js");
8611
+ const { fireInternalDispatch } =
8612
+ await import("./self-dispatch.js");
8613
+ let rows: { id: string; startedAt: number }[];
8584
8614
  try {
8585
- runIds = await listUnclaimedBackgroundRunIds();
8615
+ rows = await listUnclaimedBackgroundRunRows();
8586
8616
  } catch {
8587
8617
  return; // Table may not exist yet on first boot
8588
8618
  }
8589
- for (const staleRunId of runIds) {
8619
+ for (const row of rows) {
8590
8620
  try {
8591
- const reaped = await reapUnclaimedBackgroundRun(staleRunId);
8621
+ if (shouldRedispatchUnclaimedBackgroundRun(row)) {
8622
+ // Bump liveness BEFORE attempting the redispatch so the
8623
+ // row doesn't look freshly-stale again the instant this
8624
+ // tick returns — best-effort, the CAS is what actually
8625
+ // matters for correctness, not this timing.
8626
+ await updateRunHeartbeat(row.id).catch(() => {});
8627
+ try {
8628
+ // DELIBERATE: this marker omits `continuationCount`.
8629
+ // `chainServerDrivenContinuation` (production-agent.ts)
8630
+ // reads `backgroundRunMarker.continuationCount` to
8631
+ // compute `backgroundContinuationCount`, defaulting to 0
8632
+ // when absent — so a chunk recovered here always starts
8633
+ // a fresh nested-dispatch segment at depth 0, regardless
8634
+ // of how deep the chain was before this sweep picked it
8635
+ // up. This is what makes the sweep a genuine CHAIN
8636
+ // BREAK, not just a retry: this redispatch fires from an
8637
+ // unrelated, timer-driven invocation rather than from
8638
+ // inside the prior chain's own live execution, so
8639
+ // starting its nested-depth count over at 0 here is
8640
+ // correct — see `MAX_NESTED_SELF_DISPATCH_DEPTH` in
8641
+ // production-agent.ts for why nested depth is bounded
8642
+ // and how this reset keeps a long turn progressing past
8643
+ // Netlify's undocumented self-invocation loop-protection
8644
+ // limit instead of dying at it. Do not "fix" this by
8645
+ // adding `continuationCount` back without re-reading
8646
+ // that constant's doc comment.
8647
+ await fireInternalDispatch({
8648
+ path: resolveAgentChatProcessRunDispatchPath(),
8649
+ taskId: row.id,
8650
+ body: {
8651
+ internalContinuation: true,
8652
+ [AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
8653
+ runId: row.id,
8654
+ payloadRef: true,
8655
+ },
8656
+ },
8657
+ awaitResponse: true,
8658
+ responseTimeoutMs: 15_000,
8659
+ });
8660
+ console.error(
8661
+ "[agent-chat] redispatched unclaimed background run (handoff recovery):",
8662
+ row.id,
8663
+ );
8664
+ } catch (redispatchErr) {
8665
+ console.error(
8666
+ "[agent-chat] unclaimed background run redispatch attempt failed (retrying until the redispatch bound, then reaping):",
8667
+ row.id,
8668
+ redispatchErr instanceof Error
8669
+ ? redispatchErr.message
8670
+ : redispatchErr,
8671
+ );
8672
+ }
8673
+ continue;
8674
+ }
8675
+ // Redispatch bound exceeded — this handoff is not
8676
+ // recovering. Fall back to the pre-existing loud reap so
8677
+ // the turn fails loud instead of retrying forever.
8678
+ const reaped = await reapUnclaimedBackgroundRun(row.id);
8592
8679
  if (reaped) {
8593
8680
  console.error(
8594
- "[agent-chat] swept unclaimed background run (handoff lost):",
8595
- staleRunId,
8681
+ "[agent-chat] swept unclaimed background run (handoff lost, redispatch bound exceeded):",
8682
+ row.id,
8596
8683
  );
8597
8684
  }
8598
8685
  } catch {
@@ -16,6 +16,21 @@ export interface BuilderDesignSystemCodeFileInput {
16
16
  filename: string;
17
17
  content: string;
18
18
  mimeType?: string;
19
+ /**
20
+ * How `content` is encoded. Defaults to `"utf8"` (existing behavior,
21
+ * unchanged for every current text-file caller). Pass `"base64"` for
22
+ * binary files -- most importantly `.fig` (a zip/kiwi binary container,
23
+ * never valid UTF-8 text). Without this, a `.fig` upload silently
24
+ * corrupts: `mimeTypeForBuilderDesignSystemFilename` already special-cases
25
+ * `.fig` as `application/octet-stream`, but the actual byte pipeline ran
26
+ * every file through `TextEncoder().encode()` regardless, which mangles
27
+ * any byte >= 0x80 in a binary-as-string payload (or, if the caller
28
+ * base64-encoded first with no decode step here, stores the literal
29
+ * base64 text instead of the decoded binary). Callers sending `.fig`/PDF/
30
+ * other binary bytes must base64-encode `content` and set this to
31
+ * `"base64"`.
32
+ */
33
+ encoding?: "utf8" | "base64";
19
34
  }
20
35
 
21
36
  export interface BuildBuilderDesignSystemIndexFilesOptions {
@@ -184,9 +199,20 @@ export function buildBuilderDesignSystemIndexFiles({
184
199
  const files: BuilderDesignSystemIndexFile[] = [];
185
200
  let totalBytes = 0;
186
201
 
187
- function pushTextFile(filename: string, content: string, mimeType?: string) {
202
+ function pushFile(
203
+ filename: string,
204
+ content: string,
205
+ mimeType?: string,
206
+ encoding?: "utf8" | "base64",
207
+ ) {
188
208
  const normalizedName = filename.replace(/^\/+/, "") || "code.txt";
189
- const data = encoder.encode(content);
209
+ // `.fig`/PDF/other binary payloads must round-trip through base64, not
210
+ // UTF-8 -- TextEncoder().encode() on a binary-as-string payload mangles
211
+ // any byte >= 0x80. See BuilderDesignSystemCodeFileInput.encoding.
212
+ const data =
213
+ encoding === "base64"
214
+ ? new Uint8Array(Buffer.from(content, "base64"))
215
+ : encoder.encode(content);
190
216
  if (data.byteLength === 0) return;
191
217
  if (totalBytes + data.byteLength > maxTotalCodeBytes) return;
192
218
  totalBytes += data.byteLength;
@@ -201,7 +227,7 @@ export function buildBuilderDesignSystemIndexFiles({
201
227
  }
202
228
 
203
229
  if (designMd?.trim()) {
204
- pushTextFile(
230
+ pushFile(
205
231
  designMdFilename?.trim() || "design.md",
206
232
  designMd,
207
233
  "text/markdown",
@@ -209,7 +235,7 @@ export function buildBuilderDesignSystemIndexFiles({
209
235
  }
210
236
 
211
237
  for (const file of (codeFiles ?? []).slice(0, maxCodeFiles)) {
212
- pushTextFile(file.filename, file.content, file.mimeType);
238
+ pushFile(file.filename, file.content, file.mimeType, file.encoding);
213
239
  }
214
240
 
215
241
  return files;
@@ -126,7 +126,7 @@ Transcription takes an audio file and returns text + segments. That's not a prom
126
126
  **Provider priority:**
127
127
 
128
128
  1. **Native (highest priority).** The browser's Web Speech API, desktop local Whisper/macOS SFSpeech when available, and desktop Web Speech fallback on non-mac run during recording and save results via `save-browser-transcript`. This gives an instant transcript with no API key when the local/browser recognizer is available. When `request-transcript` runs afterward, it preserves the ready native transcript and only falls back to a cloud provider if native text is missing.
129
- 2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments.
129
+ 2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments. Retry a failed transcript with `force: true`; pass `regenerate: true` to replace an existing ready transcript from the stored recording media. Regeneration keeps the prior ready transcript available if the new provider attempt fails.
130
130
  3. **Cloud fallback — Groq Whisper.** `GROQ_API_KEY` → `https://api.groq.com/openai/v1/audio/transcriptions`, model `whisper-large-v3-turbo`. Fast (~$0.04/hour of audio) Whisper-compatible speech-to-text used when Builder is unavailable.
131
131
 
132
132
  Clips never routes recording/meeting audio to OpenAI for transcription. (Groq's endpoint is OpenAI-_compatible_ in request shape only — the audio goes to Groq, not OpenAI.)
@@ -14,6 +14,12 @@ description: >-
14
14
 
15
15
  Recording sharing uses the framework `sharing` system — not a custom share table. Recordings are registered via `registerShareableResource({ type: "recording", ... })` in `server/db/index.ts`. The `share-resource`, `unshare-resource`, `list-resource-shares`, and `set-resource-visibility` actions are auto-mounted and handle per-user grants, per-org grants, and the three visibility levels (`private` / `org` / `public`).
16
16
 
17
+ Unlike the framework-wide private default, normal Clips recordings and uploaded
18
+ videos default to **public** so their copied share links work immediately.
19
+ Embedded bug-report recordings are the exception and default to organization
20
+ visibility. Callers can still explicitly create a private or organization-only
21
+ recording, and owners/admins can change visibility from the Share dialog.
22
+
17
23
  Clips **adds two things** on top of the framework system:
18
24
 
19
25
  1. **Password** — an optional bcrypt'd string on the `recordings` row. When set, all non-owner viewers must enter it to play the recording.
@@ -62,7 +68,7 @@ import { ShareDialog } from "@agent-native/core/client";
62
68
  </>
63
69
  }
64
70
  embedTabContent={<EmbedSnippetAndOptions recordingId={recording.id} />}
65
- />
71
+ />;
66
72
  ```
67
73
 
68
74
  - `shareUrl` / `embedUrl` — the copy-link and embed URLs the framework renders in its tabs.
@@ -163,11 +169,11 @@ Required Slack app setup:
163
169
  Recordings can expose URLs meant for external agents without handing over raw
164
170
  video bytes:
165
171
 
166
- | Endpoint | Meaning |
167
- | -------- | ------- |
168
- | `/api/agent-context.json?id=<recordingId>` | Clip metadata, transcript summary, recommended frames, and API discovery links |
169
- | `/api/agent-transcript.json?id=<recordingId>` | Timestamped transcript segments with `startMs`, `endMs`, `timestamp`, `range`, `text`, and optional `source` |
170
- | `/api/agent-frame.jpg?id=<recordingId>&atMs=<ms>` | JPEG frame extracted from the video at the requested original-video timestamp |
172
+ | Endpoint | Meaning |
173
+ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
174
+ | `/api/agent-context.json?id=<recordingId>` | Clip metadata, transcript summary, recommended frames, and API discovery links |
175
+ | `/api/agent-transcript.json?id=<recordingId>` | Timestamped transcript segments with `startMs`, `endMs`, `timestamp`, `range`, `text`, and optional `source` |
176
+ | `/api/agent-frame.jpg?id=<recordingId>&atMs=<ms>` | JPEG frame extracted from the video at the requested original-video timestamp |
171
177
 
172
178
  These endpoints follow the same access model as `/api/public-recording`, plus a
173
179
  temporary agent-link path:
@@ -34,6 +34,10 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
34
34
  download the original from Loom and use "Upload video".
35
35
  - Native transcript first. Cleanup and title generation can run in the
36
36
  background; do not hide a usable native transcript behind a failed cleanup.
37
+ - Use `request-transcript --recordingId=<id> --force=true` to retry a failed
38
+ transcript. Pass `--regenerate=true` to replace an existing ready transcript
39
+ from the stored recording media; if regeneration fails, keep the prior ready
40
+ transcript available.
37
41
  - Dictation cleanup, Clip title/cleanup, and meeting summaries should pass
38
42
  bounded `voiceContext` to the shared cleanup/transcription path when active
39
43
  app context, learned vocabulary, user notes, or AGENTS.md preferences are
@@ -24,6 +24,7 @@ import {
24
24
  } from "../server/lib/recordings.js";
25
25
  import { setResumableSession } from "../server/lib/resumable-session.js";
26
26
  import { shouldEnableStreamingUpload } from "../server/lib/streaming-upload-mode.js";
27
+ import { allowsSqlRecordingChunkScratch } from "../server/lib/video-storage.js";
27
28
  import { createRecordingSchema } from "./lib/create-recording-schema.js";
28
29
  import { DEFAULT_RECORDING_TITLE } from "./lib/title-source.js";
29
30
 
@@ -92,6 +93,7 @@ export default defineAction({
92
93
  shouldEnableStreamingUpload({
93
94
  client: args.streamingUploadClient,
94
95
  mimeType: args.mimeType,
96
+ bufferedFallbackAvailable: allowsSqlRecordingChunkScratch(),
95
97
  }) &&
96
98
  uploadProvider?.resumable
97
99
  ) {
@@ -62,8 +62,10 @@ export const createRecordingSchema = z.object({
62
62
  .describe("Height of the recording in pixels (may be 0 until finalized)"),
63
63
  visibility: z
64
64
  .enum(["private", "org", "public"])
65
- .optional()
66
- .describe("Initial share visibility for the recording"),
65
+ .default("public")
66
+ .describe(
67
+ "Initial share visibility for the recording (defaults to public)",
68
+ ),
67
69
  mimeType: z
68
70
  .string()
69
71
  .optional()
@@ -74,7 +76,7 @@ export const createRecordingSchema = z.object({
74
76
  .boolean()
75
77
  .optional()
76
78
  .describe(
77
- "Request the resumable streaming upload path. Deployments must also set CLIPS_ENABLE_STREAMING_UPLOAD; otherwise recordings use the buffered fallback.",
79
+ "Request the resumable streaming upload path. Hosted deployments use it automatically because SQL chunk buffering is unavailable; local deployments can opt in with CLIPS_ENABLE_STREAMING_UPLOAD.",
78
80
  ),
79
81
  streamingUploadClient: z
80
82
  .enum(["desktop-native"])