@agent-native/core 0.92.10 → 0.92.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +23 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +181 -15
  5. package/corpus/core/src/agent/run-manager.ts +31 -4
  6. package/corpus/core/src/agent/run-store.ts +80 -0
  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.ts +165 -1
  12. package/corpus/core/src/client/chat/index.ts +9 -1
  13. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
  14. package/corpus/core/src/client/index.ts +5 -0
  15. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
  16. package/corpus/core/src/collab/awareness-store.ts +23 -12
  17. package/corpus/core/src/collab/client.ts +16 -5
  18. package/corpus/core/src/collab/index.ts +4 -0
  19. package/corpus/core/src/collab/recent-edits.ts +65 -2
  20. package/corpus/core/src/index.browser.ts +1 -0
  21. package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
  22. package/corpus/core/src/server/builder-design-systems.ts +30 -4
  23. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
  24. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
  25. package/corpus/templates/clips/AGENTS.md +4 -0
  26. package/corpus/templates/clips/actions/create-recording.ts +2 -0
  27. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
  28. package/corpus/templates/clips/actions/request-transcript.ts +102 -33
  29. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
  30. package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
  31. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +48 -4
  32. package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
  33. package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
  34. package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
  35. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  36. package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
  37. package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
  38. package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
  39. package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
  40. package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
  41. package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
  42. package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
  43. package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
  44. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
  45. package/corpus/templates/clips/app/routes/record.tsx +17 -4
  46. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
  47. package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
  52. package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
  53. package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
  54. package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
  55. package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
  56. package/corpus/templates/clips/desktop/src/app.tsx +12 -2
  57. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
  58. package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
  59. package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
  60. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
  61. package/corpus/templates/clips/desktop/src/styles.css +6 -3
  62. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
  63. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
  64. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
  65. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
  66. package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
  67. package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
  68. package/corpus/templates/clips/shared/recording-core.ts +12 -0
  69. package/corpus/templates/content/AGENTS.md +7 -6
  70. package/corpus/templates/content/actions/_document-flush.ts +132 -17
  71. package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
  72. package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
  73. package/corpus/templates/content/actions/link-notion-page.ts +2 -0
  74. package/corpus/templates/content/actions/pull-document.ts +5 -7
  75. package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
  76. package/corpus/templates/content/actions/push-notion-page.ts +10 -0
  77. package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
  78. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
  79. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
  80. package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
  81. package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
  82. package/corpus/templates/content/app/i18n-data.ts +18 -0
  83. package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
  84. package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
  85. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
  86. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
  87. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
  88. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
  89. package/corpus/templates/design/AGENTS.md +45 -10
  90. package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
  91. package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
  92. package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
  93. package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
  94. package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
  95. package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
  96. package/corpus/templates/design/actions/generate-design.ts +79 -12
  97. package/corpus/templates/design/actions/generate-screens.ts +57 -12
  98. package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
  99. package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
  100. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
  101. package/corpus/templates/design/actions/import-design-source.ts +4 -31
  102. package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
  103. package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
  104. package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
  105. package/corpus/templates/design/actions/list-design-components.ts +104 -0
  106. package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
  107. package/corpus/templates/design/actions/open-component-source.ts +2 -4
  108. package/corpus/templates/design/actions/present-design-variants.ts +412 -16
  109. package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
  110. package/corpus/templates/design/actions/run-design-audit.ts +25 -3
  111. package/corpus/templates/design/actions/show-design-questions.ts +10 -0
  112. package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
  113. package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
  114. package/corpus/templates/design/actions/write-local-file.ts +25 -1
  115. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
  116. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
  117. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
  118. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
  119. package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
  120. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
  121. package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
  122. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
  123. package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
  124. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
  125. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
  126. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
  127. package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
  129. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
  130. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
  131. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
  132. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
  133. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
  134. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
  135. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
  136. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
  137. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
  138. package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
  139. package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
  140. package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
  141. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
  142. package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
  143. package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
  144. package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
  145. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
  146. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
  147. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
  148. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
  149. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
  150. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
  151. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
  152. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
  153. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
  154. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
  155. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
  156. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
  157. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
  158. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
  159. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
  160. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
  161. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
  162. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
  163. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
  164. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
  165. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
  166. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
  167. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
  168. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
  169. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
  170. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
  171. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
  172. package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
  173. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
  174. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
  175. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
  176. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
  177. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
  178. package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
  179. package/corpus/templates/design/app/components/design/types.ts +33 -0
  180. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
  181. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
  182. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
  183. package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
  184. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
  185. package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
  186. package/corpus/templates/design/app/i18n-data.ts +1217 -10
  187. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
  188. package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
  189. package/corpus/templates/design/app/lib/design-import.ts +24 -0
  190. package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
  191. package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
  192. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
  193. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
  194. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
  195. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
  196. package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
  197. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
  198. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
  199. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
  200. package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
  201. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
  202. package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
  239. package/corpus/templates/design/e2e/global-setup.ts +3 -6
  240. package/corpus/templates/design/e2e/helpers.ts +27 -6
  241. package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
  242. package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
  243. package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
  244. package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
  245. package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
  246. package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
  247. package/corpus/templates/design/server/plugins/db.ts +41 -0
  248. package/corpus/templates/design/server/source-workspace.ts +64 -0
  249. package/corpus/templates/design/shared/board-file.ts +13 -2
  250. package/corpus/templates/design/shared/canvas-math.ts +231 -33
  251. package/corpus/templates/design/shared/code-layer.ts +122 -8
  252. package/corpus/templates/design/shared/component-library.ts +161 -0
  253. package/corpus/templates/design/shared/db-conflict.ts +27 -0
  254. package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
  255. package/corpus/templates/design/shared/figma-url.ts +149 -0
  256. package/corpus/templates/design/shared/pen-path.ts +16 -7
  257. package/corpus/templates/design/shared/source-mode.ts +1 -0
  258. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
  259. package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
  260. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
  261. package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
  262. package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
  263. package/dist/agent/production-agent.d.ts +79 -6
  264. package/dist/agent/production-agent.d.ts.map +1 -1
  265. package/dist/agent/production-agent.js +161 -14
  266. package/dist/agent/production-agent.js.map +1 -1
  267. package/dist/agent/run-manager.d.ts.map +1 -1
  268. package/dist/agent/run-manager.js +29 -5
  269. package/dist/agent/run-manager.js.map +1 -1
  270. package/dist/agent/run-store.d.ts +46 -0
  271. package/dist/agent/run-store.d.ts.map +1 -1
  272. package/dist/agent/run-store.js +61 -0
  273. package/dist/agent/run-store.js.map +1 -1
  274. package/dist/cli/design-connect.d.ts +6 -0
  275. package/dist/cli/design-connect.d.ts.map +1 -1
  276. package/dist/cli/design-connect.js +336 -139
  277. package/dist/cli/design-connect.js.map +1 -1
  278. package/dist/cli/skills.d.ts.map +1 -1
  279. package/dist/cli/skills.js +14 -0
  280. package/dist/cli/skills.js.map +1 -1
  281. package/dist/client/AssistantChat.d.ts +2 -0
  282. package/dist/client/AssistantChat.d.ts.map +1 -1
  283. package/dist/client/AssistantChat.js +19 -3
  284. package/dist/client/AssistantChat.js.map +1 -1
  285. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  286. package/dist/client/MultiTabAssistantChat.js +38 -18
  287. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  288. package/dist/client/agent-chat.d.ts +60 -0
  289. package/dist/client/agent-chat.d.ts.map +1 -1
  290. package/dist/client/agent-chat.js +122 -1
  291. package/dist/client/agent-chat.js.map +1 -1
  292. package/dist/client/chat/index.d.ts +1 -1
  293. package/dist/client/chat/index.d.ts.map +1 -1
  294. package/dist/client/chat/index.js +1 -1
  295. package/dist/client/chat/index.js.map +1 -1
  296. package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
  297. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  298. package/dist/client/extensions/EmbeddedExtension.js +36 -2
  299. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  300. package/dist/client/index.d.ts +1 -1
  301. package/dist/client/index.d.ts.map +1 -1
  302. package/dist/client/index.js +1 -1
  303. package/dist/client/index.js.map +1 -1
  304. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  305. package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
  306. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  307. package/dist/collab/awareness-store.d.ts +5 -0
  308. package/dist/collab/awareness-store.d.ts.map +1 -1
  309. package/dist/collab/awareness-store.js +19 -12
  310. package/dist/collab/awareness-store.js.map +1 -1
  311. package/dist/collab/client.d.ts.map +1 -1
  312. package/dist/collab/client.js +13 -5
  313. package/dist/collab/client.js.map +1 -1
  314. package/dist/collab/index.d.ts +1 -0
  315. package/dist/collab/index.d.ts.map +1 -1
  316. package/dist/collab/index.js +1 -0
  317. package/dist/collab/index.js.map +1 -1
  318. package/dist/collab/recent-edits.d.ts +3 -1
  319. package/dist/collab/recent-edits.d.ts.map +1 -1
  320. package/dist/collab/recent-edits.js +57 -2
  321. package/dist/collab/recent-edits.js.map +1 -1
  322. package/dist/index.browser.d.ts +1 -1
  323. package/dist/index.browser.d.ts.map +1 -1
  324. package/dist/index.browser.js +1 -1
  325. package/dist/index.browser.js.map +1 -1
  326. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  327. package/dist/server/agent-chat-plugin.js +87 -10
  328. package/dist/server/agent-chat-plugin.js.map +1 -1
  329. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  330. package/dist/server/builder-design-systems.d.ts +15 -0
  331. package/dist/server/builder-design-systems.d.ts.map +1 -1
  332. package/dist/server/builder-design-systems.js +9 -4
  333. package/dist/server/builder-design-systems.js.map +1 -1
  334. package/package.json +1 -1
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 2155
31
- - template files: 5119
31
+ - template files: 5195
@@ -1,5 +1,28 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.92.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 4552931: Keep local React visual-edit previews hydrated by preserving Vite request metadata and response lengths through the bridge, and recover exact development source locations from React jsxDEV Fiber stacks.
8
+ - 4552931: Expose strict active-collaboration awareness reads so safety-critical sync flows can distinguish no open editor from presence-storage failures.
9
+ - 4552931: Add cancellation-safe `sendToAgentChatAndConfirm` delivery confirmation and its submit-result event contract so callers can preserve user work when a local chat message is rejected or times out, without allowing that timed-out message to arrive later.
10
+ - 4552931: Fix `.fig` and other binary files silently corrupting when uploaded through `index-design-system-with-builder`: `buildBuilderDesignSystemIndexFiles` always UTF-8-encoded file content even though `mimeTypeForBuilderDesignSystemFilename` already recognized `.fig` as binary (`application/octet-stream`). Add an optional per-file `encoding: "utf8" | "base64"` (defaults to `utf8`, unchanged for existing text-file callers) so binary files can be base64-encoded by the caller and decoded byte-exact here.
11
+ - 4552931: Prevent pre-seed collaborative editor updates from reaching autosave, and allow newer authoritative restores to reapply content previously emitted during mount while retaining stale-echo protection during active typing.
12
+ - 4552931: Prevent PR recap workflows from publishing screenshots of failed recap pages, and report SSR render failures through configured error monitoring.
13
+ - 4552931: Fix long agent-chat turns dying with a Netlify "508 Loop Detected" error after several server-driven continuation chunks: nested self-dispatch chains now break proactively before the platform's undocumented loop-protection limit, and a 508 that does occur is classified distinctly and deferred to the existing unclaimed-run sweep for recovery instead of failing the turn outright.
14
+ - 4552931: Recover background chat turns whose continuation handoff dispatch failed instead of failing them immediately: the pre-inserted successor run is left claimable so the unclaimed-run sweep can redispatch it (and the client poll defers to that sweep within a bound), backed by a backstop that still fails loud if the handoff never lands.
15
+
16
+ Operational note — terminal-reason change: when a continuation handoff exhausts its dispatch retry budget but the successor row exists, the run's `terminal_reason` is now `background_continuation_dispatch_deferred` (recoverable, awaiting sweep redispatch) instead of `background_continuation_dispatch_failed`. The old `background_continuation_dispatch_failed` reason is still emitted, but now only in the narrower case where the successor row itself could not be pre-inserted. Any dashboards, alerts, or audit queries matching `background_continuation_dispatch_failed` should add `background_continuation_dispatch_deferred` to keep covering this failure class.
17
+
18
+ - 4552931: Fix an awareness "storm" in `useCollaborativeDoc`: the shared collab connection's fast awareness-push path re-broadcast a client's own (unchanged) presence state whenever ANY remote participant's awareness changed, not just when the local user actually moved their cursor or updated their presence. With several people collaborating on the same document, every peer's cursor move caused every other connected client to also re-POST its own state, multiplying awareness traffic roughly quadratically with participant count. The fast-push listener now only fires on locally-originated awareness changes (`origin === "local"`), matching the equivalent guard already present in `usePresence`.
19
+
20
+ Also add a defensive size cap to the collab `recentEdits` ring (`appendRecentEdit`): descriptor strings (`quote`, `selector`, path entries) and the edit `label` are now truncated to 500 characters. The ring was already bounded in length, but an app forgetting to trim its own excerpt before publishing (e.g. passing a whole paragraph or document as `quote`) could otherwise push an oversized payload through the awareness fast-path broadcast and into the `_collab_awareness` SQL mirror.
21
+
22
+ - 4552931: Give the Design localhost bridge a per-boot `bridgeInstanceId`, exposed on `/health`, the `/live-edit-bridge` registration response, and the `/live-edit` "unknown bridge key" 409 (now carrying a machine-readable `code: "unknown-bridge-key"` and the echoed `bridgeKey`). This lets a client distinguish a bridge process restart — which silently empties the in-memory live-edit bridge script registry — from a genuine registration bug, instead of guessing from free-text error strings.
23
+ - 4552931: Fix a recurring `DataCloneError` console error when any embedded extension (Design's Tools/Extensions panel, or any other app using `EmbeddedExtension`) loads or its slot context updates. Slot contexts commonly carry live callback functions the host uses internally; `postMessage`'s structured clone algorithm throws on function-valued properties, so the context update silently never reached the extension iframe. Sanitize the context through a JSON round-trip (dropping functions) before posting it.
24
+ - 4552931: Harden local Design source writes with SHA-256 version checks, per-file serialization, atomic replacement, and repeated symlink containment validation.
25
+
3
26
  ## 0.92.10
4
27
 
5
28
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.92.10",
3
+ "version": "0.92.11",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -5038,6 +5038,70 @@ export function resolveContinuationDispatchBudget(opts: {
5038
5038
  };
5039
5039
  }
5040
5040
 
5041
+ /**
5042
+ * True when a `fireInternalDispatch` failure is Netlify's Functions platform
5043
+ * loop-protection response (`HTTP 508 Loop Detected`), matched against the
5044
+ * exact message `self-dispatch.ts`'s `dispatchResponseError` constructs
5045
+ * (`Self-dispatch to ${path} returned HTTP ${res.status} ${res.statusText}...`).
5046
+ * Matches on the status code alone (not the reason phrase text) so it is
5047
+ * robust to any wording Netlify's edge puts in `statusText`.
5048
+ *
5049
+ * VERIFIED: production `agent_runs` diagnostics show exactly this failure mode
5050
+ * — 8 successful `chain_dispatch_sent` self-dispatches followed by a 9th/10th
5051
+ * that dies with `HTTP 508 Loop Detected`, terminal reason
5052
+ * `background_continuation_dispatch_failed`. UNVERIFIED (Netlify does not
5053
+ * document the mechanism — checked the Functions overview, Functions API
5054
+ * reference, Background Functions overview, Status Codes reference, and
5055
+ * Request Chain troubleshooting docs, none mention it): the ONLY public
5056
+ * confirmation is a Netlify staff forum reply — "we prevent multiple
5057
+ * executions after one-another as that's a 'loop' ... I believe we enforce
5058
+ * this after 9 or 10 self-invocations"
5059
+ * (https://answers.netlify.com/t/self-invoke-background-function-via-post-requests/146012)
5060
+ * — which also confirms Background Functions do NOT escape the limit (the
5061
+ * reporter's case was already a `-background` function self-invoking). See
5062
+ * `MAX_NESTED_SELF_DISPATCH_DEPTH` for how this classification is used.
5063
+ */
5064
+ export function isLoopProtectionDispatchError(err: unknown): boolean {
5065
+ if (!(err instanceof Error)) return false;
5066
+ return /\bHTTP\s*508\b/i.test(err.message);
5067
+ }
5068
+
5069
+ /**
5070
+ * Conservative safety margin on NESTED self-dispatch chaining — a
5071
+ * continuation dispatched directly from within the live invocation that is
5072
+ * about to finish, as opposed to being picked up later by the
5073
+ * unclaimed-background-run sweep (`agent-chat-plugin.ts`), which fires its
5074
+ * redispatch from an unrelated, timer-driven invocation rather than from
5075
+ * inside the chain's own execution.
5076
+ *
5077
+ * Netlify's loop-protection ceiling is undocumented and platform-reported
5078
+ * only approximately ("I believe... 9 or 10" — see
5079
+ * `isLoopProtectionDispatchError`), so hard-coding that exact number here
5080
+ * would be pinning behavior to a number Netlify itself won't commit to, and
5081
+ * production evidence shows it can trigger by the 9th self-dispatch. Rather
5082
+ * than only reacting after triggering that undocumented limit,
5083
+ * `chainServerDrivenContinuation` proactively hands a chunk to the sweep once
5084
+ * `backgroundContinuationCount` (nested hops since the last chain break)
5085
+ * reaches this value — comfortably below the observed ~9-10 failure point —
5086
+ * instead of attempting another nested dispatch. This is the SAME deferred-
5087
+ * recovery path already used when a dispatch fails outright: the row is left
5088
+ * `status='running', dispatch_mode='background'` for the sweep to redispatch,
5089
+ * never silently dropped.
5090
+ *
5091
+ * The sweep's redispatch marker intentionally omits `continuationCount` (see
5092
+ * the "Unclaimed background-run sweep" in `agent-chat-plugin.ts`), so a
5093
+ * sweep-recovered chunk's own `backgroundContinuationCount` resets to 0 —
5094
+ * this constant therefore bounds each NESTED segment between chain breaks,
5095
+ * not the whole turn. The TRUE ceiling on total turn length is unaffected by
5096
+ * that reset: it is the durable per-turn SQL ledger (`countRunsForTurn`,
5097
+ * checked above in this function) plus `MAX_BACKGROUND_RUN_CONTINUATIONS` —
5098
+ * both counted independently of this in-marker value — so a legitimately
5099
+ * long turn keeps making progress in bounded nested segments, each recovered
5100
+ * by the sweep, until it genuinely exhausts the intentional overall budget
5101
+ * and fails loud with `turn_continuation_budget_exhausted`.
5102
+ */
5103
+ export const MAX_NESTED_SELF_DISPATCH_DEPTH = 6;
5104
+
5041
5105
  /**
5042
5106
  * Server-driven continuation handoff for a chunk that hit its soft-timeout
5043
5107
  * boundary still unfinished: mint the next chunk's runId, PRE-INSERT its run
@@ -5046,12 +5110,26 @@ export function resolveContinuationDispatchBudget(opts: {
5046
5110
  * `_process-run` self-dispatch carrying ids only (the body is persisted on
5047
5111
  * the row as `dispatch_payload`), fully AWAIT the dispatch acknowledgment
5048
5112
  * with retries, and mark this chunk terminal only after the handoff landed.
5049
- * On failure every path is loud: the successor row is errored, the failure
5050
- * is recorded as the run's diag stage, and this chunk is flipped to errored
5051
- * with a terminal reason never a silent loss. (For a FOREGROUND self-chain
5052
- * the client additionally still receives the terminal `auto_continue` event
5053
- * run-manager emits it after this callback so the existing client
5054
- * re-POST path takes over as the fallback.)
5113
+ * On failure this chunk always goes terminal loudly (diag stage + terminal
5114
+ * reason recorded never a silent loss), but the successor row's fate
5115
+ * depends on WHY the dispatch failed:
5116
+ * - the pre-insert itself failed (no successor row exists) — nothing for a
5117
+ * sweep to find, so this is unrecoverable: fail loud immediately with
5118
+ * `background_continuation_dispatch_failed`.
5119
+ * - every dispatch attempt failed but the successor row DOES exist with its
5120
+ * `dispatch_payload` intact — this is RECOVERABLE: the row is left alone
5121
+ * (`status='running', dispatch_mode='background'`) instead of being
5122
+ * errored, so the unclaimed-background-run sweep in `agent-chat-plugin.ts`
5123
+ * can redispatch it once `UNCLAIMED_BACKGROUND_RUN_GRACE_MS` has passed.
5124
+ * This chunk is flipped to errored with the distinct, honest
5125
+ * `background_continuation_dispatch_deferred` reason — the TURN is
5126
+ * deferred, not dead. The sweep still bounds this by
5127
+ * `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS`: past that it falls back
5128
+ * to the existing loud reap, so a genuinely dead handoff never hangs
5129
+ * silently forever. (For a FOREGROUND self-chain the client additionally
5130
+ * still receives the terminal `auto_continue` event — run-manager emits
5131
+ * it after this callback — so the existing client re-POST path is a
5132
+ * second, faster fallback alongside the sweep.)
5055
5133
  *
5056
5134
  * `chainViaDurableBackground` selects the dispatch target:
5057
5135
  * - true → the durable-background worker chain (unchanged behavior): the
@@ -5244,9 +5322,23 @@ export async function chainServerDrivenContinuation(opts: {
5244
5322
  };
5245
5323
  let dispatched = false;
5246
5324
  let lastDispatchErr: unknown;
5325
+ // Proactive nested-chain safety margin — see `MAX_NESTED_SELF_DISPATCH_DEPTH`.
5326
+ // Skip the nested dispatch attempt entirely once this segment's hop count
5327
+ // reaches the cap; a nested attempt at this depth is expected to trip
5328
+ // Netlify's loop protection, so there is nothing to gain by trying it and
5329
+ // burning this worker's remaining wall clock on a doomed call. Falls
5330
+ // straight into the same deferred-recovery path below as an exhausted
5331
+ // retry budget.
5332
+ const nestedDepthExceeded =
5333
+ opts.backgroundContinuationCount >= MAX_NESTED_SELF_DISPATCH_DEPTH;
5334
+ if (nestedDepthExceeded) {
5335
+ lastDispatchErr = new Error(
5336
+ `proactive nested-dispatch depth cap reached (backgroundContinuationCount=${opts.backgroundContinuationCount} >= MAX_NESTED_SELF_DISPATCH_DEPTH=${MAX_NESTED_SELF_DISPATCH_DEPTH}) — deferring to the unclaimed-background-run sweep instead of risking Netlify loop protection`,
5337
+ );
5338
+ }
5247
5339
  for (
5248
5340
  let attempt = 0;
5249
- attempt < maxDispatchAttempts && !dispatched;
5341
+ !nestedDepthExceeded && attempt < maxDispatchAttempts && !dispatched;
5250
5342
  attempt++
5251
5343
  ) {
5252
5344
  try {
@@ -5313,25 +5405,99 @@ export async function chainServerDrivenContinuation(opts: {
5313
5405
  `[agent-chat] background continuation dispatch attempt ${attempt + 1} failed:`,
5314
5406
  dispatchErr instanceof Error ? dispatchErr.message : dispatchErr,
5315
5407
  );
5408
+ // Netlify loop protection (see `isLoopProtectionDispatchError`) is a
5409
+ // property of this same live, nested call chain — retrying the exact
5410
+ // same nested self-dispatch within the next few seconds will not
5411
+ // change that, so further attempts are a guaranteed-doomed use of
5412
+ // this worker's remaining wall clock. Stop immediately (instead of
5413
+ // burning the full `maxDispatchAttempts` budget) and fall into the
5414
+ // same deferred-recovery path below, which hands the successor to the
5415
+ // sweep — a genuinely different, non-nested invocation.
5416
+ if (isLoopProtectionDispatchError(dispatchErr)) {
5417
+ break;
5418
+ }
5316
5419
  }
5317
5420
  }
5318
5421
  if (!dispatched) {
5319
- // The pre-inserted successor row would otherwise sit unclaimed until
5320
- // the sweep reaps it — error it now so the failure is immediate and
5321
- // truthful.
5322
5422
  if (nextRowInserted) {
5323
- const nextStatusUpdated = await d
5324
- .updateRunStatusIfRunning(nextRunId, "errored")
5423
+ // Classify WHY this handoff is being deferred — distinct, greppable
5424
+ // tags so production diagnostics (which is all that is readable from
5425
+ // a background worker) can tell "we proactively avoided Netlify loop
5426
+ // protection", "we hit loop protection and stopped retrying", and "a
5427
+ // generic transient dispatch failure exhausted its retry budget"
5428
+ // apart, instead of lumping every deferred handoff into one bucket.
5429
+ const deferralClassification = nestedDepthExceeded
5430
+ ? "proactive_depth_cap"
5431
+ : isLoopProtectionDispatchError(lastDispatchErr)
5432
+ ? "netlify_loop_protection"
5433
+ : "dispatch_budget_exhausted";
5434
+ // RECOVERABLE: the successor row already exists in SQL with its
5435
+ // rehydration payload (`dispatch_payload`) intact and is still
5436
+ // `status='running', dispatch_mode='background'` — exactly the state
5437
+ // the unclaimed-background-run sweep (`agent-chat-plugin.ts`) already
5438
+ // scans for. Do NOT error it here: leave it alone so the sweep can
5439
+ // redispatch it once `UNCLAIMED_BACKGROUND_RUN_GRACE_MS` has passed,
5440
+ // bounded by `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS` before it
5441
+ // falls back to the existing loud reap
5442
+ // (`background_worker_never_started`) — so this is deferred, never a
5443
+ // silent hang. This chunk still goes terminal (its own soft-timeout
5444
+ // budget is genuinely spent), but with an honest reason: the TURN is
5445
+ // not dead, only this handoff attempt was.
5446
+ //
5447
+ // THREE-SITE INVARIANT (keep in lockstep — a future reader must not
5448
+ // "fix" one without the others): this deferral only survives because
5449
+ // the ~1s client poll in `getActiveRunForThreadAsync`
5450
+ // (run-manager.ts) ALSO skips `reapUnclaimedBackgroundRun` while the
5451
+ // successor is within `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS`
5452
+ // (via `shouldRedispatchUnclaimedBackgroundRun`). Without that guard a
5453
+ // connected client would reap this row at the 25s grace, before the
5454
+ // ~2-min sweep, defeating the deferral. The sweep in agent-chat-plugin
5455
+ // is the recovery actor; run-manager is the guard; this is the
5456
+ // producer.
5457
+ await d
5458
+ .recordRunDiagnostic(
5459
+ nextRunId,
5460
+ RUN_DIAG_STAGE.workerThrew,
5461
+ `chain_dispatch_deferred[${deferralClassification}]: dispatch budget exhausted (${maxDispatchAttempts} attempts) awaiting unclaimed-run sweep redispatch; ${
5462
+ lastDispatchErr instanceof Error
5463
+ ? lastDispatchErr.message
5464
+ : String(lastDispatchErr)
5465
+ }`,
5466
+ )
5467
+ .catch(() => {});
5468
+ await d
5469
+ .recordRunDiagnostic(
5470
+ runId,
5471
+ RUN_DIAG_STAGE.workerThrew,
5472
+ `chain_dispatch_deferred[${deferralClassification}] nextRunId=${nextRunId} ${
5473
+ lastDispatchErr instanceof Error
5474
+ ? lastDispatchErr.message
5475
+ : String(lastDispatchErr)
5476
+ }`,
5477
+ )
5478
+ .catch(() => {});
5479
+ console.error(
5480
+ `[agent-chat] background continuation dispatch deferred (${deferralClassification}); leaving the pre-inserted successor for the unclaimed-run sweep to redispatch:`,
5481
+ lastDispatchErr instanceof Error
5482
+ ? lastDispatchErr.message
5483
+ : lastDispatchErr,
5484
+ );
5485
+ const statusUpdated = await d
5486
+ .updateRunStatusIfRunning(runId, "errored")
5325
5487
  .catch(() => false);
5326
- if (nextStatusUpdated) {
5488
+ if (statusUpdated) {
5327
5489
  await d
5328
5490
  .setRunTerminalReason(
5329
- nextRunId,
5330
- "background_continuation_dispatch_failed",
5491
+ runId,
5492
+ "background_continuation_dispatch_deferred",
5331
5493
  )
5332
5494
  .catch(() => {});
5333
5495
  }
5496
+ return;
5334
5497
  }
5498
+ // No successor row exists at all (the pre-insert itself failed) — there
5499
+ // is nothing for the sweep to find and recover, so this really is
5500
+ // fatal. Fail loud immediately via the shared catch block below.
5335
5501
  throw lastDispatchErr instanceof Error
5336
5502
  ? lastDispatchErr
5337
5503
  : new Error(String(lastDispatchErr));
@@ -16,6 +16,7 @@ import {
16
16
  bumpRunProgress,
17
17
  reapIfStale,
18
18
  reapUnclaimedBackgroundRun,
19
+ shouldRedispatchUnclaimedBackgroundRun,
19
20
  reconcileTerminalRunFromEvents,
20
21
  ensureTerminalRunEvent,
21
22
  getLastTerminalRunEvent,
@@ -1469,10 +1470,36 @@ export async function getActiveRunForThreadAsync(threadId: string): Promise<{
1469
1470
  // past the tight grace means the bg-fn worker never started — a silent
1470
1471
  // async-worker death that the 202-ack inline fallback can't catch. Reap it
1471
1472
  // early and recoverably (background_worker_never_started) so the run no
1472
- // longer hangs for the full 90s window and the client's recoverable-error
1473
- // path can re-drive the turn. Only fires when there is provably no live
1474
- // worker; a claimed/heartbeating run is left alone by the conditional SQL.
1475
- if (sqlRun.dispatchMode === "background") {
1473
+ // longer hangs for the full 90s window. Only fires when there is provably
1474
+ // no live worker; a claimed/heartbeating run is left alone by the
1475
+ // conditional SQL.
1476
+ //
1477
+ // REDISPATCH-BOUND GUARD (must be kept in lockstep with the "Unclaimed
1478
+ // background-run sweep" in agent-chat-plugin.ts and with
1479
+ // chainServerDrivenContinuation's deferral in production-agent.ts — do NOT
1480
+ // remove this guard without reading those two sites):
1481
+ // `chainServerDrivenContinuation` now DEFERS a dispatch-failed successor
1482
+ // instead of erroring it — it leaves the row status='running',
1483
+ // dispatch_mode='background' with its dispatch_payload intact so the sweep
1484
+ // can silently redispatch it. This client poll runs every ~1s while a
1485
+ // client is connected, so without this guard it would reap that deferred
1486
+ // successor at the 25s unclaimed grace — long before the ~2-min sweep —
1487
+ // converting the intended SILENT server-side recovery into a user-visible
1488
+ // `background_worker_never_started` manual-retry error (that terminal
1489
+ // reason does NOT auto-continue in the client follow loop; only `stale_run`
1490
+ // does). While the successor is still inside its redispatch bound we skip
1491
+ // this reap and leave it for the sweep. The outer backstops still bound it:
1492
+ // `reapIfStale` below reaps a heartbeat-stale background row at 90s
1493
+ // (BACKGROUND_RUN_STALE_MS) to the recoverable `stale_run` — which the
1494
+ // follow loop AUTO-continues — and once the redispatch bound is exceeded
1495
+ // this reap fires loudly as before. So recovery stays automatic in the
1496
+ // common case and loud failure is only moved later, never removed.
1497
+ if (
1498
+ sqlRun.dispatchMode === "background" &&
1499
+ !shouldRedispatchUnclaimedBackgroundRun({
1500
+ startedAt: sqlRun.startedAt,
1501
+ })
1502
+ ) {
1476
1503
  const recovered = await reapUnclaimedBackgroundRun(sqlRun.id).catch(
1477
1504
  () => false,
1478
1505
  );
@@ -99,6 +99,21 @@ export const CLAIMED_BACKGROUND_WORKER_FAILED_ERROR_EVENT = {
99
99
  */
100
100
  export const UNCLAIMED_BACKGROUND_RUN_GRACE_MS = 25_000;
101
101
 
102
+ /**
103
+ * Backstop ceiling — measured from the row's ORIGINAL `started_at`, which never
104
+ * changes — after which the unclaimed-background-run sweep stops attempting to
105
+ * redispatch a lost handoff and instead reaps it via `reapUnclaimedBackgroundRun`
106
+ * (loud, attributable `errored`). This is what keeps redispatch recoverable
107
+ * WITHOUT becoming a silent hang: a handoff that cannot be delivered within this
108
+ * window (a genuinely dead platform, not a transient blip) still fails loudly,
109
+ * it just gets a few sweep-cycle chances first. 5 minutes comfortably allows
110
+ * multiple 2-minute sweep ticks (see `agent-chat-plugin.ts`'s
111
+ * "Unclaimed background-run sweep") while staying well inside both the 40s
112
+ * foreground chunk clamp and the ~13min background soft-timeout ceiling that
113
+ * bound how long a real user turn is worth waiting on before failing loud.
114
+ */
115
+ export const UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS = 5 * 60_000;
116
+
102
117
  async function ensureRunTables(): Promise<void> {
103
118
  if (!_initPromise) {
104
119
  _initPromise = (async () => {
@@ -648,6 +663,71 @@ export async function listUnclaimedBackgroundRunIds(): Promise<string[]> {
648
663
  return ids;
649
664
  }
650
665
 
666
+ /** A row returned by `listUnclaimedBackgroundRunRows`. */
667
+ export interface UnclaimedBackgroundRunRow {
668
+ id: string;
669
+ /** The row's ORIGINAL `started_at` (never bumped by heartbeats), so a
670
+ * caller can measure total elapsed time since the handoff was first
671
+ * pre-inserted — independent of any liveness bump a redispatch attempt
672
+ * makes along the way. */
673
+ startedAt: number;
674
+ }
675
+
676
+ /**
677
+ * Same eligibility as `listUnclaimedBackgroundRunIds`, but also returns each
678
+ * row's original `started_at` so a caller can bound total redispatch time
679
+ * (see `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS`) independent of the
680
+ * liveness bumps a redispatch attempt makes along the way. Used by the
681
+ * unclaimed-background-run sweep's redispatch pass; `listUnclaimedBackgroundRunIds`
682
+ * is kept as the simpler, pre-existing surface for callers that only need ids.
683
+ */
684
+ export async function listUnclaimedBackgroundRunRows(): Promise<
685
+ UnclaimedBackgroundRunRow[]
686
+ > {
687
+ await ensureRunTables();
688
+ const client = getDbExec();
689
+ const { rows } = await client.execute({
690
+ // CAST keeps the ms-epoch param 64-bit on Postgres (see
691
+ // backgroundAwareStaleCutoffSql for the int4-inference failure mode).
692
+ sql: `SELECT id, started_at FROM agent_runs
693
+ WHERE status = 'running'
694
+ AND dispatch_mode = 'background'
695
+ AND COALESCE(heartbeat_at, started_at) < (CAST(? AS BIGINT) - ${UNCLAIMED_BACKGROUND_RUN_GRACE_MS})`,
696
+ args: [Date.now()],
697
+ });
698
+ const result: UnclaimedBackgroundRunRow[] = [];
699
+ for (const row of rows ?? []) {
700
+ const id = (row as { id?: unknown }).id;
701
+ const startedAt = (row as { started_at?: unknown }).started_at;
702
+ if (typeof id === "string" && id) {
703
+ result.push({
704
+ id,
705
+ startedAt:
706
+ typeof startedAt === "number" ? startedAt : Number(startedAt) || 0,
707
+ });
708
+ }
709
+ }
710
+ return result;
711
+ }
712
+
713
+ /**
714
+ * Pure decision for the unclaimed-background-run sweep: should THIS row get
715
+ * another redispatch attempt, or has it exceeded
716
+ * `UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS` and must fall back to the
717
+ * loud reap (`reapUnclaimedBackgroundRun`)? Measured from the row's ORIGINAL
718
+ * `started_at` (never bumped by a redispatch's heartbeat write), so this is
719
+ * the total-elapsed-time backstop that keeps recovery bounded — a handoff
720
+ * that cannot be delivered within the window is not spinning forever, it
721
+ * fails loud. Exported as a pure function (no DB access) so the bound is unit
722
+ * -testable independent of the sweep's setInterval wiring.
723
+ */
724
+ export function shouldRedispatchUnclaimedBackgroundRun(
725
+ row: { startedAt: number },
726
+ now: number = Date.now(),
727
+ ): boolean {
728
+ return now - row.startedAt < UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS;
729
+ }
730
+
651
731
  /**
652
732
  * Count how many runs (chunks) a logical turn has consumed so far. This is the
653
733
  * durable per-turn recovery ledger: unlike the in-marker `continuationCount`