@agent-native/core 0.131.5 → 0.131.7

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 (350) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +70 -0
  3. package/corpus/core/docs/content/agent-native-toolkit.mdx +13 -6
  4. package/corpus/core/docs/content/cloneable-saas.mdx +5 -5
  5. package/corpus/core/docs/content/creating-templates.mdx +9 -0
  6. package/corpus/core/docs/content/deployment.mdx +18 -12
  7. package/corpus/core/docs/content/doctor.mdx +8 -1
  8. package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
  9. package/corpus/core/docs/content/extensions.mdx +18 -18
  10. package/corpus/core/docs/content/faq.mdx +4 -4
  11. package/corpus/core/docs/content/key-concepts.mdx +30 -21
  12. package/corpus/core/docs/content/security.mdx +2 -2
  13. package/corpus/core/docs/content/template-brain-developers.mdx +4 -1
  14. package/corpus/core/docs/content/template-mail-developers.mdx +4 -1
  15. package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/a2a/client.ts +449 -66
  18. package/corpus/core/src/a2a/correlation.ts +31 -0
  19. package/corpus/core/src/a2a/invoke.ts +4 -2
  20. package/corpus/core/src/a2a/types.ts +4 -0
  21. package/corpus/core/src/action.ts +3 -0
  22. package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
  23. package/corpus/core/src/agent/engine/registry.ts +98 -6
  24. package/corpus/core/src/agent/production-agent.ts +151 -18
  25. package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
  26. package/corpus/core/src/agent/run-manager.ts +117 -41
  27. package/corpus/core/src/agent/thread-debug-history.ts +86 -0
  28. package/corpus/core/src/agent/types.ts +3 -1
  29. package/corpus/core/src/cli/create.ts +11 -1
  30. package/corpus/core/src/cli/templates-meta.ts +2 -2
  31. package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
  32. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
  33. package/corpus/core/src/client/sse-event-processor.ts +17 -3
  34. package/corpus/core/src/db/client.ts +57 -17
  35. package/corpus/core/src/guards/no-env-credentials.ts +2 -0
  36. package/corpus/core/src/integrations/adapters/slack.ts +8 -3
  37. package/corpus/core/src/localization/default-messages.ts +44 -0
  38. package/corpus/core/src/observability/traces.ts +78 -5
  39. package/corpus/core/src/scripts/call-agent.ts +294 -11
  40. package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
  41. package/corpus/core/src/secrets/crypto.ts +156 -35
  42. package/corpus/core/src/secrets/storage.ts +64 -26
  43. package/corpus/core/src/server/agent-capabilities.ts +1 -1
  44. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +113 -7
  45. package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
  46. package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
  47. package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
  48. package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
  49. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  50. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  51. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  54. package/corpus/core/src/vite/client.ts +1 -0
  55. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
  56. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
  57. package/corpus/templates/analytics/AGENTS.md +7 -4
  58. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
  59. package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
  61. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
  62. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
  63. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
  64. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
  65. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
  66. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
  67. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
  68. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
  69. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
  70. package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
  71. package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
  72. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
  73. package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
  74. package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
  75. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
  76. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
  77. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
  78. package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
  79. package/corpus/templates/brain/AGENTS.md +3 -1
  80. package/corpus/templates/brain/README.md +4 -1
  81. package/corpus/templates/brain/actions/_schemas.ts +30 -8
  82. package/corpus/templates/brain/actions/ask-brain.ts +124 -14
  83. package/corpus/templates/brain/actions/create-source.ts +18 -2
  84. package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
  85. package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
  86. package/corpus/templates/brain/actions/import-capture.ts +17 -5
  87. package/corpus/templates/brain/actions/import-transcript.ts +17 -5
  88. package/corpus/templates/brain/actions/update-source.ts +25 -5
  89. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
  90. package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
  91. package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
  92. package/corpus/templates/brain/server/lib/brain.ts +49 -19
  93. package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
  94. package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
  95. package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
  96. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
  97. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
  98. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  99. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
  100. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
  101. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
  102. package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
  103. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
  104. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
  105. package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
  106. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
  107. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
  108. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
  109. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
  110. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
  111. package/corpus/templates/design/package.json +0 -1
  112. package/corpus/templates/dispatch/AGENTS.md +8 -0
  113. package/corpus/templates/dispatch/DEVELOPING.md +29 -0
  114. package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
  115. package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
  116. package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
  117. package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
  118. package/corpus/templates/dispatch/netlify.toml +3 -0
  119. package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
  120. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
  121. package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
  122. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  123. package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
  124. package/corpus/templates/plan/shared/plan-content.ts +35 -0
  125. package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
  126. package/corpus/templates/slides/AGENTS.md +4 -4
  127. package/corpus/templates/slides/actions/create-deck.ts +1 -1
  128. package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
  129. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
  130. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
  131. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
  132. package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
  133. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
  134. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
  135. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
  136. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
  137. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
  138. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
  139. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
  140. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
  141. package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
  142. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
  143. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
  144. package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
  145. package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
  146. package/corpus/templates/slides/app/global.css +105 -0
  147. package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
  148. package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
  149. package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
  150. package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
  151. package/corpus/templates/slides/app/pages/Index.tsx +98 -41
  152. package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
  153. package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
  154. package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
  155. package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
  156. package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
  157. package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
  158. package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
  159. package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
  160. package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
  161. package/corpus/templates/slides/netlify.toml +3 -1
  162. package/corpus/templates/slides/package.json +0 -1
  163. package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
  164. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  165. package/corpus/templates/slides/vite.config.ts +0 -1
  166. package/corpus/toolkit/CHANGELOG.md +13 -0
  167. package/corpus/toolkit/README.md +19 -0
  168. package/corpus/toolkit/agent-native.eject.json +38 -0
  169. package/corpus/toolkit/package.json +29 -1
  170. package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
  171. package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
  172. package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
  173. package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
  174. package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
  175. package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
  176. package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
  177. package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
  178. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
  179. package/corpus/toolkit/src/index.ts +1 -0
  180. package/dist/a2a/client.d.ts +23 -0
  181. package/dist/a2a/client.d.ts.map +1 -1
  182. package/dist/a2a/client.js +309 -44
  183. package/dist/a2a/client.js.map +1 -1
  184. package/dist/a2a/correlation.d.ts +1 -0
  185. package/dist/a2a/correlation.d.ts.map +1 -1
  186. package/dist/a2a/correlation.js +27 -0
  187. package/dist/a2a/correlation.js.map +1 -1
  188. package/dist/a2a/invoke.d.ts.map +1 -1
  189. package/dist/a2a/invoke.js +4 -2
  190. package/dist/a2a/invoke.js.map +1 -1
  191. package/dist/a2a/types.d.ts +4 -0
  192. package/dist/a2a/types.d.ts.map +1 -1
  193. package/dist/a2a/types.js.map +1 -1
  194. package/dist/action.d.ts +3 -0
  195. package/dist/action.d.ts.map +1 -1
  196. package/dist/action.js.map +1 -1
  197. package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
  198. package/dist/agent/action-continuation-guidance.js +2 -1
  199. package/dist/agent/action-continuation-guidance.js.map +1 -1
  200. package/dist/agent/engine/registry.d.ts.map +1 -1
  201. package/dist/agent/engine/registry.js +82 -8
  202. package/dist/agent/engine/registry.js.map +1 -1
  203. package/dist/agent/production-agent.d.ts +40 -1
  204. package/dist/agent/production-agent.d.ts.map +1 -1
  205. package/dist/agent/production-agent.js +113 -15
  206. package/dist/agent/production-agent.js.map +1 -1
  207. package/dist/agent/run-loop-with-resume.d.ts +21 -0
  208. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  209. package/dist/agent/run-loop-with-resume.js +163 -4
  210. package/dist/agent/run-loop-with-resume.js.map +1 -1
  211. package/dist/agent/run-manager.d.ts +16 -9
  212. package/dist/agent/run-manager.d.ts.map +1 -1
  213. package/dist/agent/run-manager.js +93 -42
  214. package/dist/agent/run-manager.js.map +1 -1
  215. package/dist/agent/thread-debug-history.d.ts +10 -0
  216. package/dist/agent/thread-debug-history.d.ts.map +1 -0
  217. package/dist/agent/thread-debug-history.js +68 -0
  218. package/dist/agent/thread-debug-history.js.map +1 -0
  219. package/dist/agent/types.d.ts +3 -1
  220. package/dist/agent/types.d.ts.map +1 -1
  221. package/dist/agent/types.js.map +1 -1
  222. package/dist/cli/create.d.ts.map +1 -1
  223. package/dist/cli/create.js +6 -1
  224. package/dist/cli/create.js.map +1 -1
  225. package/dist/cli/templates-meta.js +2 -2
  226. package/dist/cli/templates-meta.js.map +1 -1
  227. package/dist/client/agent-chat-adapter.d.ts +1 -1
  228. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  229. package/dist/client/agent-chat-adapter.js +76 -13
  230. package/dist/client/agent-chat-adapter.js.map +1 -1
  231. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  232. package/dist/client/resources/McpIntegrationDialog.js +1 -1
  233. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  234. package/dist/client/sse-event-processor.d.ts.map +1 -1
  235. package/dist/client/sse-event-processor.js +12 -3
  236. package/dist/client/sse-event-processor.js.map +1 -1
  237. package/dist/collab/routes.d.ts +1 -1
  238. package/dist/db/client.d.ts.map +1 -1
  239. package/dist/db/client.js +48 -17
  240. package/dist/db/client.js.map +1 -1
  241. package/dist/guards/no-env-credentials.d.ts.map +1 -1
  242. package/dist/guards/no-env-credentials.js +2 -0
  243. package/dist/guards/no-env-credentials.js.map +1 -1
  244. package/dist/integrations/adapters/slack.js +7 -3
  245. package/dist/integrations/adapters/slack.js.map +1 -1
  246. package/dist/localization/default-messages.d.ts +43 -0
  247. package/dist/localization/default-messages.d.ts.map +1 -1
  248. package/dist/localization/default-messages.js +43 -0
  249. package/dist/localization/default-messages.js.map +1 -1
  250. package/dist/observability/traces.d.ts +3 -1
  251. package/dist/observability/traces.d.ts.map +1 -1
  252. package/dist/observability/traces.js +73 -4
  253. package/dist/observability/traces.js.map +1 -1
  254. package/dist/progress/routes.d.ts +1 -1
  255. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  256. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  257. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  258. package/dist/scripts/call-agent.d.ts.map +1 -1
  259. package/dist/scripts/call-agent.js +237 -12
  260. package/dist/scripts/call-agent.js.map +1 -1
  261. package/dist/scripts/describe-workspace-apps.js +2 -2
  262. package/dist/scripts/describe-workspace-apps.js.map +1 -1
  263. package/dist/secrets/crypto.d.ts +36 -21
  264. package/dist/secrets/crypto.d.ts.map +1 -1
  265. package/dist/secrets/crypto.js +134 -33
  266. package/dist/secrets/crypto.js.map +1 -1
  267. package/dist/secrets/storage.d.ts +6 -6
  268. package/dist/secrets/storage.d.ts.map +1 -1
  269. package/dist/secrets/storage.js +43 -26
  270. package/dist/secrets/storage.js.map +1 -1
  271. package/dist/server/agent-capabilities.js +1 -1
  272. package/dist/server/agent-capabilities.js.map +1 -1
  273. package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
  274. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  275. package/dist/server/agent-chat/action-filters-a2a.js +94 -3
  276. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  277. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  278. package/dist/server/agent-chat/context-tools.js +2 -0
  279. package/dist/server/agent-chat/context-tools.js.map +1 -1
  280. package/dist/server/agent-chat/plugin-options.d.ts +23 -0
  281. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  282. package/dist/server/agent-chat/plugin-options.js +4 -1
  283. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  284. package/dist/server/agent-chat/prompt-resources.js +1 -1
  285. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  286. package/dist/server/agent-chat-plugin.d.ts +2 -1
  287. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  288. package/dist/server/agent-chat-plugin.js +79 -56
  289. package/dist/server/agent-chat-plugin.js.map +1 -1
  290. package/dist/server/realtime-token.d.ts +1 -1
  291. package/dist/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  292. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  293. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  294. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  295. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  296. package/dist/vite/client.d.ts.map +1 -1
  297. package/dist/vite/client.js +1 -0
  298. package/dist/vite/client.js.map +1 -1
  299. package/docs/content/agent-native-toolkit.mdx +13 -6
  300. package/docs/content/cloneable-saas.mdx +5 -5
  301. package/docs/content/creating-templates.mdx +9 -0
  302. package/docs/content/deployment.mdx +18 -12
  303. package/docs/content/doctor.mdx +8 -1
  304. package/docs/content/drop-in-agent.mdx +1 -1
  305. package/docs/content/extensions.mdx +18 -18
  306. package/docs/content/faq.mdx +4 -4
  307. package/docs/content/key-concepts.mdx +30 -21
  308. package/docs/content/security.mdx +2 -2
  309. package/docs/content/template-brain-developers.mdx +4 -1
  310. package/docs/content/template-mail-developers.mdx +4 -1
  311. package/docs/content/what-is-agent-native.mdx +6 -6
  312. package/package.json +3 -3
  313. package/src/a2a/client.ts +449 -66
  314. package/src/a2a/correlation.ts +31 -0
  315. package/src/a2a/invoke.ts +4 -2
  316. package/src/a2a/types.ts +4 -0
  317. package/src/action.ts +3 -0
  318. package/src/agent/action-continuation-guidance.ts +2 -1
  319. package/src/agent/engine/registry.ts +98 -6
  320. package/src/agent/production-agent.ts +151 -18
  321. package/src/agent/run-loop-with-resume.ts +190 -3
  322. package/src/agent/run-manager.ts +117 -41
  323. package/src/agent/thread-debug-history.ts +86 -0
  324. package/src/agent/types.ts +3 -1
  325. package/src/cli/create.ts +11 -1
  326. package/src/cli/templates-meta.ts +2 -2
  327. package/src/client/agent-chat-adapter.ts +91 -13
  328. package/src/client/resources/McpIntegrationDialog.tsx +11 -9
  329. package/src/client/sse-event-processor.ts +17 -3
  330. package/src/db/client.ts +57 -17
  331. package/src/guards/no-env-credentials.ts +2 -0
  332. package/src/integrations/adapters/slack.ts +8 -3
  333. package/src/localization/default-messages.ts +44 -0
  334. package/src/observability/traces.ts +78 -5
  335. package/src/scripts/call-agent.ts +294 -11
  336. package/src/scripts/describe-workspace-apps.ts +2 -2
  337. package/src/secrets/crypto.ts +156 -35
  338. package/src/secrets/storage.ts +64 -26
  339. package/src/server/agent-capabilities.ts +1 -1
  340. package/src/server/agent-chat/action-filters-a2a.ts +113 -7
  341. package/src/server/agent-chat/context-tools.ts +2 -0
  342. package/src/server/agent-chat/plugin-options.ts +34 -1
  343. package/src/server/agent-chat/prompt-resources.ts +1 -1
  344. package/src/server/agent-chat-plugin.ts +91 -59
  345. package/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  346. package/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  347. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  348. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  349. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  350. package/src/vite/client.ts +1 -0
@@ -58,6 +58,10 @@ type GranularOp =
58
58
  | { op: "full-replace"; deck: Deck };
59
59
 
60
60
  export type PatchDeckOp = Exclude<GranularOp, { op: "full-replace" }>;
61
+ export type DeckReloadStatus = "loaded" | "failed" | "stale";
62
+ export interface UpdateSlideOptions {
63
+ persistence?: "debounced" | "immediate";
64
+ }
61
65
 
62
66
  // ---------------------------------------------------------------------------
63
67
  // Inverse-op undo
@@ -164,6 +168,7 @@ interface DeckContextType {
164
168
  updates: Partial<Omit<Deck, "id" | "createdAt">>,
165
169
  ) => void;
166
170
  reloadDecks: () => Promise<void>;
171
+ reloadDecksWithStatus: () => Promise<DeckReloadStatus>;
167
172
  getDeck: (id: string) => Deck | undefined;
168
173
  addSlide: (
169
174
  deckId: string,
@@ -174,6 +179,7 @@ interface DeckContextType {
174
179
  deckId: string,
175
180
  slideId: string,
176
181
  updates: Partial<Omit<Slide, "id">>,
182
+ options?: UpdateSlideOptions,
177
183
  ) => void;
178
184
  deleteSlide: (deckId: string, slideId: string) => void;
179
185
  duplicateSlide: (deckId: string, slideId: string) => void;
@@ -260,7 +266,13 @@ function normalizeActionDeck(value: unknown): Deck | null {
260
266
  // uncommitted?" for the indicator.
261
267
  const pendingSaves = new Map<string, ReturnType<typeof setTimeout>>();
262
268
  const inFlightSaves = new Set<string>();
269
+ const inFlightSaveChains = new Map<string, Promise<void>>();
270
+ const immediateFlushRequests = new Set<string>();
271
+ const deckSaveRetryAttempts = new Map<string, number>();
272
+ const failedSaveDecks = new Set<string>();
263
273
  const saveStateListeners = new Set<() => void>();
274
+ const MAX_DECK_SAVE_RETRIES = 2;
275
+ const DECK_SAVE_RETRY_BASE_MS = 250;
264
276
 
265
277
  // Per-deck queue of granular ops waiting to be flushed. Keys are deck IDs.
266
278
  // Ops are appended by enqueueDeckOp and drained when the debounce fires.
@@ -273,7 +285,8 @@ const pendingOpsQueue = new Map<string, GranularOp[]>();
273
285
  let cachedSnapshot: { saving: boolean } = { saving: false };
274
286
 
275
287
  function recomputeSnapshot() {
276
- const saving = pendingSaves.size > 0 || inFlightSaves.size > 0;
288
+ const saving =
289
+ pendingSaves.size > 0 || inFlightSaves.size > 0 || pendingOpsQueue.size > 0;
277
290
  if (saving !== cachedSnapshot.saving) {
278
291
  cachedSnapshot = { saving };
279
292
  }
@@ -322,10 +335,118 @@ function deckPayload(deck: Deck): Record<string, unknown> {
322
335
  * the `save-deck` action is called first, then any trailing granular ops are
323
336
  * sent through `patch-deck`.
324
337
  */
325
- function enqueueDeckOp(deckId: string, op: GranularOp) {
326
- // Clear any pending save timer — we're about to reset it
338
+ async function persistDeckOps(deckId: string, ops: GranularOp[]) {
339
+ if (ops[0].op === "full-replace") {
340
+ // Legacy full-deck write — used by undo/redo and setDeckSlides.
341
+ // `callAction` bounds it so a stalled save can't wedge `inFlightSaves`
342
+ // forever (its `finally` cleanup below only runs once this await
343
+ // settles; an AbortError from the timeout still reaches it).
344
+ const deck = ops[0].deck;
345
+ await callAction(
346
+ "save-deck",
347
+ { deckId, deck: deckPayload(deck) },
348
+ { method: "PUT" },
349
+ );
350
+ const trailingOps = ops.slice(1) as PatchDeckOp[];
351
+ if (trailingOps.length > 0) {
352
+ await callAction("patch-deck", {
353
+ deckId,
354
+ operations: trailingOps,
355
+ });
356
+ }
357
+ } else {
358
+ await callAction("patch-deck", {
359
+ deckId,
360
+ operations: ops as PatchDeckOp[],
361
+ });
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Drain the current operation batch behind every earlier batch for this deck.
367
+ * Slide content patches replace the full HTML field, so overlapping requests
368
+ * could otherwise complete out of order and let a stale drag overwrite a
369
+ * newer resize.
370
+ */
371
+ function drainPendingDeckOps(deckId: string): Promise<void> {
372
+ const timer = pendingSaves.get(deckId);
373
+ if (timer) clearTimeout(timer);
374
+ pendingSaves.delete(deckId);
375
+
376
+ const active = inFlightSaveChains.get(deckId);
377
+ if (active) {
378
+ immediateFlushRequests.add(deckId);
379
+ notifySaveListeners();
380
+ return active;
381
+ }
382
+
383
+ const ops = pendingOpsQueue.get(deckId) ?? [];
384
+ pendingOpsQueue.delete(deckId);
385
+ if (ops.length === 0) {
386
+ notifySaveListeners();
387
+ return Promise.resolve();
388
+ }
389
+
390
+ inFlightSaves.add(deckId);
391
+ let succeeded = false;
392
+ const next = persistDeckOps(deckId, ops)
393
+ .then(() => {
394
+ succeeded = true;
395
+ deckSaveRetryAttempts.delete(deckId);
396
+ failedSaveDecks.delete(deckId);
397
+ })
398
+ .catch((err) => {
399
+ console.error(`Failed to save deck ${deckId}:`, err);
400
+ const pending = pendingOpsQueue.get(deckId) ?? [];
401
+ pendingOpsQueue.set(deckId, [...ops, ...pending]);
402
+ const attempt = (deckSaveRetryAttempts.get(deckId) ?? 0) + 1;
403
+ deckSaveRetryAttempts.set(deckId, attempt);
404
+ immediateFlushRequests.delete(deckId);
405
+ const pendingTimer = pendingSaves.get(deckId);
406
+ if (pendingTimer) clearTimeout(pendingTimer);
407
+ pendingSaves.delete(deckId);
408
+ if (attempt <= MAX_DECK_SAVE_RETRIES) {
409
+ const retryTimer = setTimeout(
410
+ () => {
411
+ void drainPendingDeckOps(deckId);
412
+ },
413
+ DECK_SAVE_RETRY_BASE_MS * 2 ** (attempt - 1),
414
+ );
415
+ pendingSaves.set(deckId, retryTimer);
416
+ } else {
417
+ failedSaveDecks.add(deckId);
418
+ }
419
+ })
420
+ .finally(() => {
421
+ if (inFlightSaveChains.get(deckId) === next) {
422
+ inFlightSaveChains.delete(deckId);
423
+ inFlightSaves.delete(deckId);
424
+ const flushImmediately = immediateFlushRequests.delete(deckId);
425
+ notifySaveListeners();
426
+ if (succeeded && flushImmediately) {
427
+ void drainPendingDeckOps(deckId);
428
+ }
429
+ }
430
+ });
431
+ inFlightSaveChains.set(deckId, next);
432
+ notifySaveListeners();
433
+ return next;
434
+ }
435
+
436
+ function enqueueDeckOp(
437
+ deckId: string,
438
+ op: GranularOp,
439
+ options?: { persistence?: "debounced" | "immediate" },
440
+ ) {
327
441
  const existing = pendingSaves.get(deckId);
328
442
  if (existing) clearTimeout(existing);
443
+ if (
444
+ (deckSaveRetryAttempts.get(deckId) ?? 0) > MAX_DECK_SAVE_RETRIES &&
445
+ !inFlightSaveChains.has(deckId)
446
+ ) {
447
+ deckSaveRetryAttempts.delete(deckId);
448
+ failedSaveDecks.delete(deckId);
449
+ }
329
450
 
330
451
  if (op.op === "full-replace") {
331
452
  // Discard any accumulated granular ops — this is a wholesale replacement
@@ -336,53 +457,15 @@ function enqueueDeckOp(deckId: string, op: GranularOp) {
336
457
  pendingOpsQueue.set(deckId, queue);
337
458
  }
338
459
 
339
- // Arm the debounce
340
- const timer = setTimeout(async () => {
341
- pendingSaves.delete(deckId);
342
- inFlightSaves.add(deckId);
460
+ if (options?.persistence === "immediate") {
461
+ void drainPendingDeckOps(deckId);
462
+ } else {
463
+ const timer = setTimeout(() => {
464
+ void drainPendingDeckOps(deckId);
465
+ }, 500);
466
+ pendingSaves.set(deckId, timer);
343
467
  notifySaveListeners();
344
-
345
- const ops = pendingOpsQueue.get(deckId) ?? [];
346
- pendingOpsQueue.delete(deckId);
347
-
348
- try {
349
- if (ops.length === 0) return;
350
-
351
- if (ops[0].op === "full-replace") {
352
- // Legacy full-deck write — used by undo/redo and setDeckSlides.
353
- // `callAction` bounds it so a stalled save can't wedge `inFlightSaves`
354
- // forever (its `finally` cleanup below only runs once this await
355
- // settles; an AbortError from the timeout still reaches it).
356
- const deck = ops[0].deck;
357
- await callAction(
358
- "save-deck",
359
- { deckId, deck: deckPayload(deck) },
360
- { method: "PUT" },
361
- );
362
- const trailingOps = ops.slice(1) as PatchDeckOp[];
363
- if (trailingOps.length > 0) {
364
- await callAction("patch-deck", {
365
- deckId,
366
- operations: trailingOps,
367
- });
368
- }
369
- } else {
370
- // Granular patch — concurrent-safe
371
- await callAction("patch-deck", {
372
- deckId,
373
- operations: ops as PatchDeckOp[],
374
- });
375
- }
376
- } catch (err) {
377
- console.error(`Failed to save deck ${deckId}:`, err);
378
- } finally {
379
- inFlightSaves.delete(deckId);
380
- notifySaveListeners();
381
- }
382
- }, 500);
383
-
384
- pendingSaves.set(deckId, timer);
385
- notifySaveListeners();
468
+ }
386
469
  }
387
470
 
388
471
  /**
@@ -468,6 +551,9 @@ function discardPendingDeckOps(deckId: string) {
468
551
  if (timer) clearTimeout(timer);
469
552
  pendingSaves.delete(deckId);
470
553
  pendingOpsQueue.delete(deckId);
554
+ deckSaveRetryAttempts.delete(deckId);
555
+ failedSaveDecks.delete(deckId);
556
+ immediateFlushRequests.delete(deckId);
471
557
  notifySaveListeners();
472
558
  }
473
559
 
@@ -837,7 +923,8 @@ export function hasUncommittedDeckChanges(
837
923
  return (
838
924
  dirtyDeckIds.has(deckId) ||
839
925
  pendingSaves.has(deckId) ||
840
- inFlightSaves.has(deckId)
926
+ inFlightSaves.has(deckId) ||
927
+ failedSaveDecks.has(deckId)
841
928
  );
842
929
  }
843
930
 
@@ -1270,25 +1357,31 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1270
1357
  [isNewerThanSnapshot],
1271
1358
  );
1272
1359
 
1273
- const reloadDecks = useCallback(async () => {
1274
- const requestId = ++deckBaselineRequestIdRef.current;
1275
- const createSeqAtRequest = localCreateSeqRef.current;
1276
- const requestedOpenDeckId = currentOpenDeckIdFromWindow();
1277
- const loaded = await fetchDecksForCurrentRoute();
1278
- if (
1279
- requestId !== deckBaselineRequestIdRef.current ||
1280
- requestedOpenDeckId !== currentOpenDeckIdFromWindow() ||
1281
- loaded === null
1282
- ) {
1283
- if (requestId === deckBaselineRequestIdRef.current) {
1284
- setLoadError(loaded === null);
1360
+ const reloadDecksWithStatus =
1361
+ useCallback(async (): Promise<DeckReloadStatus> => {
1362
+ const requestId = ++deckBaselineRequestIdRef.current;
1363
+ const createSeqAtRequest = localCreateSeqRef.current;
1364
+ const requestedOpenDeckId = currentOpenDeckIdFromWindow();
1365
+ const loaded = await fetchDecksForCurrentRoute();
1366
+ if (
1367
+ requestId !== deckBaselineRequestIdRef.current ||
1368
+ requestedOpenDeckId !== currentOpenDeckIdFromWindow()
1369
+ ) {
1370
+ return "stale";
1285
1371
  }
1286
- return;
1287
- }
1288
- lastExternalUpdateRef.current = Date.now();
1289
- resetDeckBaseline(loaded, createSeqAtRequest);
1290
- setLoadError(false);
1291
- }, [resetDeckBaseline]);
1372
+ if (loaded === null) {
1373
+ setLoadError(true);
1374
+ return "failed";
1375
+ }
1376
+ lastExternalUpdateRef.current = Date.now();
1377
+ resetDeckBaseline(loaded, createSeqAtRequest);
1378
+ setLoadError(false);
1379
+ return "loaded";
1380
+ }, [resetDeckBaseline]);
1381
+
1382
+ const reloadDecks = useCallback(async () => {
1383
+ await reloadDecksWithStatus();
1384
+ }, [reloadDecksWithStatus]);
1292
1385
 
1293
1386
  // Load decks from API on mount
1294
1387
  useEffect(() => {
@@ -1435,7 +1528,11 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1435
1528
  dirtyDeckIdsRef.current.delete(id);
1436
1529
  // Only fall back to full-replace if no granular ops were enqueued
1437
1530
  // for this deck (they handle the actual save).
1438
- if (!pendingOpsQueue.has(id) && !pendingSaves.has(id)) {
1531
+ if (
1532
+ !pendingOpsQueue.has(id) &&
1533
+ !pendingSaves.has(id) &&
1534
+ !inFlightSaves.has(id)
1535
+ ) {
1439
1536
  const deck = decks.find((d) => d.id === id);
1440
1537
  if (!deck) continue;
1441
1538
  saveDeckToAPI(deck);
@@ -1750,7 +1847,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1750
1847
  };
1751
1848
  optimistic.slides = optimistic.slides.map((s) => ({
1752
1849
  ...s,
1753
- id: nanoid(8),
1850
+ id: `slide-${nanoid(8)}`,
1754
1851
  }));
1755
1852
 
1756
1853
  // Track as pending so the poll doesn't wipe the optimistic deck before
@@ -1766,6 +1863,10 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1766
1863
  deckId: sourceDeckId,
1767
1864
  newId,
1768
1865
  title,
1866
+ // The user can start editing the copy before this resolves, so the
1867
+ // persisted slides must carry the ids the optimistic ones already
1868
+ // have — otherwise those edits address slides the server never had.
1869
+ slideIds: optimistic.slides.map((s) => s.id),
1769
1870
  },
1770
1871
  ).then(() => undefined);
1771
1872
  pendingCreatePromisesRef.current.set(newId, duplicatePromise);
@@ -1941,7 +2042,12 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1941
2042
  );
1942
2043
 
1943
2044
  const updateSlide = useCallback(
1944
- (deckId: string, slideId: string, updates: Partial<Omit<Slide, "id">>) => {
2045
+ (
2046
+ deckId: string,
2047
+ slideId: string,
2048
+ updates: Partial<Omit<Slide, "id">>,
2049
+ options?: UpdateSlideOptions,
2050
+ ) => {
1945
2051
  markDeckDirty(deckId);
1946
2052
  const label = updates.layout
1947
2053
  ? "Change layout"
@@ -1965,7 +2071,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
1965
2071
  );
1966
2072
  // Granular op — only this slide's changed fields reach the server.
1967
2073
  const op: PatchDeckOp = { op: "patch-slide", slideId, fields: updates };
1968
- enqueueDeckOp(deckId, op);
2074
+ enqueueDeckOp(deckId, op, options);
1969
2075
  if (before) {
1970
2076
  // Coalesce a burst of edits to the SAME slide's SAME field-set into one
1971
2077
  // undo step (e.g. typing characters into inline text). Distinct
@@ -2121,6 +2227,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
2121
2227
  deleteDeck,
2122
2228
  updateDeck,
2123
2229
  reloadDecks,
2230
+ reloadDecksWithStatus,
2124
2231
  getDeck,
2125
2232
  addSlide,
2126
2233
  updateSlide,
@@ -61,6 +61,8 @@ button[title="Open agent sidebar"] {
61
61
  --sidebar-accent-foreground: 0 0% 93%;
62
62
  --sidebar-border: 0 0% 20%;
63
63
  --sidebar-ring: 0 0% 50%;
64
+
65
+ --accent-cyan: 187 100% 50%;
64
66
  }
65
67
 
66
68
  .light {
@@ -102,6 +104,9 @@ button[title="Open agent sidebar"] {
102
104
  --sidebar-accent-foreground: 0 0% 10%;
103
105
  --sidebar-border: 0 0% 90%;
104
106
  --sidebar-ring: 0 0% 65%;
107
+
108
+ /* Darker than the dark-theme #00E5FF so text stays >= 4.5:1 against a white popover. */
109
+ --accent-cyan: 193 82% 31%;
105
110
  }
106
111
 
107
112
  /* Slides keeps the shared visual inspector behavior, but the dock needs the
@@ -109,6 +114,9 @@ button[title="Open agent sidebar"] {
109
114
  .slide-style-inspector {
110
115
  --slides-inspector-control-background: hsl(var(--muted) / 0.82);
111
116
  --slides-inspector-divider: hsl(var(--border) / 0.7);
117
+ --design-editor-control-bg: var(--slides-inspector-control-background);
118
+ --design-editor-control-border: transparent;
119
+ --design-editor-accent-color: #609ff8;
112
120
  }
113
121
 
114
122
  .slide-style-inspector > div:first-child {
@@ -1142,6 +1150,103 @@ button[title="Open agent sidebar"] {
1142
1150
  background: rgba(96, 159, 248, 0.35);
1143
1151
  }
1144
1152
 
1153
+ /* Google Slides-style object selection chrome. The edge hit targets are wider
1154
+ than their visible bars, but both centers sit on the 1px outline rather than
1155
+ drifting into the selected object through the outline's border box. */
1156
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle] {
1157
+ box-sizing: border-box;
1158
+ }
1159
+
1160
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="nw"],
1161
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="ne"],
1162
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="sw"],
1163
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="se"],
1164
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle-bar="true"] {
1165
+ border: 1px solid #609ff8;
1166
+ background: #fff;
1167
+ box-shadow: none;
1168
+ }
1169
+
1170
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="nw"],
1171
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="ne"],
1172
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="sw"],
1173
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="se"] {
1174
+ width: 7px;
1175
+ height: 7px;
1176
+ }
1177
+
1178
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="nw"] {
1179
+ top: -4px;
1180
+ left: -4px;
1181
+ }
1182
+
1183
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="ne"] {
1184
+ top: -4px;
1185
+ right: -4px;
1186
+ }
1187
+
1188
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="sw"] {
1189
+ bottom: -4px;
1190
+ left: -4px;
1191
+ }
1192
+
1193
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="se"] {
1194
+ right: -4px;
1195
+ bottom: -4px;
1196
+ }
1197
+
1198
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="n"],
1199
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="s"] {
1200
+ width: 22px;
1201
+ height: 12px;
1202
+ left: 50%;
1203
+ transform: translateX(-50%);
1204
+ }
1205
+
1206
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="n"] {
1207
+ top: -6.5px;
1208
+ }
1209
+
1210
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="s"] {
1211
+ bottom: -6.5px;
1212
+ }
1213
+
1214
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="e"],
1215
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="w"] {
1216
+ width: 12px;
1217
+ height: 22px;
1218
+ top: 50%;
1219
+ transform: translateY(-50%);
1220
+ }
1221
+
1222
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="e"] {
1223
+ right: -6.5px;
1224
+ }
1225
+
1226
+ [data-slide-selection-chrome="true"] [data-slide-resize-handle="w"] {
1227
+ left: -6.5px;
1228
+ }
1229
+
1230
+ [data-slide-selection-chrome="true"]
1231
+ [data-slide-resize-handle="n"]
1232
+ [data-slide-resize-handle-bar="true"],
1233
+ [data-slide-selection-chrome="true"]
1234
+ [data-slide-resize-handle="s"]
1235
+ [data-slide-resize-handle-bar="true"] {
1236
+ width: 14px;
1237
+ height: 4px;
1238
+ }
1239
+
1240
+ [data-slide-selection-chrome="true"]
1241
+ [data-slide-resize-handle="e"]
1242
+ [data-slide-resize-handle-bar="true"],
1243
+ [data-slide-selection-chrome="true"]
1244
+ [data-slide-resize-handle="w"]
1245
+ [data-slide-resize-handle-bar="true"] {
1246
+ width: 4px;
1247
+ height: 14px;
1248
+ }
1249
+
1145
1250
  /* ─── Slide Transition Keyframes ─── */
1146
1251
 
1147
1252
  @keyframes slide-fade-in {
@@ -356,6 +356,8 @@ const messages = {
356
356
  styleInspector: {
357
357
  title: "Style",
358
358
  close: "Close style inspector",
359
+ slideBackground: "Slide background",
360
+ slide: "Slide",
359
361
  deckStyle: "Deck style",
360
362
  designSystemTweaks: "Design system tweaks",
361
363
  closeTweaks: "Close tweaks",
@@ -415,6 +417,10 @@ const messages = {
415
417
  emerald: "Emerald",
416
418
  amber: "Amber",
417
419
  rose: "Rose",
420
+ arrange: "Arrange",
421
+ order: "Order",
422
+ bringToFront: "Bring to front",
423
+ sendToBack: "Send to back",
418
424
  },
419
425
  animations: {
420
426
  appear: "Appear",
@@ -531,6 +537,7 @@ const messages = {
531
537
  deckHasNoSlides: "Deck has no slides.",
532
538
  pdfRenderFailed: "Could not render PDF.",
533
539
  buildingDeck: "Building deck",
540
+ dismissLayoutWarning: "Dismiss layout warning",
534
541
  slidesAdded_one: "{{count}} slide added",
535
542
  slidesAdded_other: "{{count}} slides added",
536
543
  },
@@ -632,6 +639,7 @@ const messages = {
632
639
  clearWorkspaceDefault: "Clear workspace default",
633
640
  workspaceDefaultSet: "Set as the workspace default",
634
641
  workspaceDefaultCleared: "Workspace default cleared",
642
+ duplicateFailed: "Couldn't duplicate that deck",
635
643
  workspaceDefaultFailed: "Couldn't update the workspace default",
636
644
  workspaceDefaultConfirmTitle: "Set as workspace default?",
637
645
  workspaceDefaultDeckShareBody:
@@ -0,0 +1,26 @@
1
+ export function deckAccessCheckKey(
2
+ deckId: string | undefined,
3
+ orgId: string | null | undefined,
4
+ ): string | null {
5
+ return deckId ? JSON.stringify([deckId, orgId ?? null]) : null;
6
+ }
7
+
8
+ export function shouldShowDeckEditorSkeleton({
9
+ deckFound,
10
+ decksLoading,
11
+ orgLoading,
12
+ accessCheckKey,
13
+ checkedAccessKey,
14
+ retrying,
15
+ }: {
16
+ deckFound: boolean;
17
+ decksLoading: boolean;
18
+ orgLoading: boolean;
19
+ accessCheckKey: string | null;
20
+ checkedAccessKey: string | null;
21
+ retrying: boolean;
22
+ }): boolean {
23
+ if (decksLoading) return true;
24
+ if (deckFound || !accessCheckKey) return false;
25
+ return orgLoading || checkedAccessKey !== accessCheckKey || retrying;
26
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Extracts `<div class="mermaid">...</div>` blocks from raw slide HTML and
3
+ * replaces them with `data-mermaid-index="N"` placeholders, BEFORE any
4
+ * sanitization. The sanitizer round-trips HTML through DOMParser +
5
+ * innerHTML, which HTML-escapes `>` in text nodes to `&gt;` — that mangles
6
+ * diagram arrows like `A --> B` into `A --&gt; B` and breaks the mermaid
7
+ * parser. The extracted definitions are the untouched source of truth for
8
+ * re-rendering (SlideRenderer) and for restoring the original markup when
9
+ * saving edits made elsewhere on the same slide (SlideEditor) — the live DOM
10
+ * replaces each placeholder with a rendered SVG, which must never be
11
+ * serialized back into slide.content or the diagram becomes permanently
12
+ * inert raw SVG with no way to edit or regenerate it.
13
+ */
14
+ export function extractMermaidBlocks(content: string): {
15
+ blocks: string[];
16
+ contentWithPlaceholders: string;
17
+ } {
18
+ const blocks: string[] = [];
19
+ const contentWithPlaceholders = content.replace(
20
+ /<div\s+class="mermaid"[^>]*>([\s\S]*?)<\/div>/gi,
21
+ (_, definition) => {
22
+ blocks.push(String(definition).trim());
23
+ return `<div data-mermaid-index="${blocks.length - 1}"></div>`;
24
+ },
25
+ );
26
+ return { blocks, contentWithPlaceholders };
27
+ }