@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
@@ -0,0 +1,53 @@
1
+ import { IconAlertTriangle, IconX } from "@tabler/icons-react";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+
5
+ interface SlideOverflowWarningProps {
6
+ verticalOverflow: number;
7
+ isAskingAgentToFix: boolean;
8
+ dismissLabel: string;
9
+ onFix: () => void;
10
+ onDismiss: () => void;
11
+ }
12
+
13
+ export function SlideOverflowWarning({
14
+ verticalOverflow,
15
+ isAskingAgentToFix,
16
+ dismissLabel,
17
+ onFix,
18
+ onDismiss,
19
+ }: SlideOverflowWarningProps) {
20
+ return (
21
+ <div
22
+ role="status"
23
+ aria-live="polite"
24
+ className="absolute top-3 left-3 z-20 flex items-center gap-2 rounded-md border border-amber-400/70 bg-amber-950/95 px-2.5 py-1.5 text-xs text-amber-50 shadow-lg"
25
+ onPointerDown={(event) => event.stopPropagation()}
26
+ onClick={(event) => event.stopPropagation()}
27
+ >
28
+ <IconAlertTriangle className="h-3.5 w-3.5 flex-shrink-0" stroke={2} />
29
+ <span className="leading-tight">
30
+ Layout overflows by {verticalOverflow}px
31
+ </span>
32
+ <Button
33
+ size="sm"
34
+ variant="ghost"
35
+ className="ml-1 h-6 cursor-pointer px-2 text-[11px] font-medium text-amber-50 hover:bg-amber-400/20 hover:text-white"
36
+ onClick={onFix}
37
+ disabled={isAskingAgentToFix}
38
+ >
39
+ {isAskingAgentToFix ? "Asking…" : "Fix with AI"}
40
+ </Button>
41
+ <Button
42
+ size="icon"
43
+ variant="ghost"
44
+ className="size-6 cursor-pointer text-amber-50 hover:bg-amber-400/20 hover:text-white"
45
+ onClick={onDismiss}
46
+ aria-label={dismissLabel}
47
+ title={dismissLabel}
48
+ >
49
+ <IconX className="size-3.5" />
50
+ </Button>
51
+ </div>
52
+ );
53
+ }
@@ -9,12 +9,20 @@ import {
9
9
  } from "@agent-native/toolkit/design-tweaks";
10
10
  import type { DesignSystemData } from "@shared/api";
11
11
  import {
12
+ IconAngle,
13
+ IconArrowAutofitHeight,
14
+ IconArrowAutofitWidth,
12
15
  IconBorderRadius,
16
+ IconBorderStyle,
13
17
  IconBoxPadding,
14
18
  IconDroplet,
19
+ IconGridDots,
15
20
  IconLetterCase,
16
21
  IconRuler2,
17
22
  IconSpacingHorizontal,
23
+ IconSpacingVertical,
24
+ IconStackBack,
25
+ IconStackFront,
18
26
  IconX,
19
27
  } from "@tabler/icons-react";
20
28
 
@@ -24,6 +32,8 @@ import { cn } from "@/lib/utils";
24
32
  import type { InlineTextStyleKey } from "./rich-text-selection";
25
33
 
26
34
  export interface SlideStyleSnapshot {
35
+ /** Omitted snapshots are existing object snapshots for backward compatibility. */
36
+ mode?: "object";
27
37
  selector: string;
28
38
  label: string;
29
39
  tagName: string;
@@ -50,10 +60,25 @@ export interface SlideStyleSnapshot {
50
60
  borderColor: string;
51
61
  paddingX: number;
52
62
  paddingY: number;
63
+ zIndex: number;
53
64
  textStyleScope?: "block" | "selection";
54
65
  mixedTextStyles?: InlineTextStyleKey[];
55
66
  }
56
67
 
68
+ /**
69
+ * Slide backgrounds are a surface, rather than selectable canvas objects.
70
+ * The editor passes this mode while its Style panel is open without an object
71
+ * selection, so the inspector exposes only background-safe controls.
72
+ */
73
+ export interface SlideBackgroundStyleSnapshot {
74
+ mode: "background";
75
+ backgroundColor: string;
76
+ }
77
+
78
+ export type SlideStyleInspectorSnapshot =
79
+ | SlideStyleSnapshot
80
+ | SlideBackgroundStyleSnapshot;
81
+
57
82
  export type SlideStylePatch = Partial<{
58
83
  color: string;
59
84
  backgroundColor: string;
@@ -74,8 +99,13 @@ export type SlideStylePatch = Partial<{
74
99
  width: string;
75
100
  height: string;
76
101
  transform: string;
102
+ zIndex: string;
77
103
  }>;
78
104
 
105
+ export type SlideBackgroundStylePatch = Required<
106
+ Pick<SlideStylePatch, "backgroundColor">
107
+ >;
108
+
79
109
  function tokenPalette(
80
110
  designSystem: DesignSystemData | undefined,
81
111
  t: (key: string) => string,
@@ -138,6 +168,85 @@ function tokenPalette(
138
168
  ];
139
169
  }
140
170
 
171
+ // `slide.background` holds either a raw CSS value or a Tailwind arbitrary
172
+ // class (`bg-[#000000]`), which SlideRenderer applies as a class rather than
173
+ // an inline style. The picker only speaks CSS colors, so unwrap the arbitrary
174
+ // form and report anything else (named utilities, gradients) as unreadable
175
+ // rather than guessing a hex the slide is not actually using.
176
+ function backgroundCssValue(background: string | undefined): string | null {
177
+ // SlideRenderer's own fallback when the field is unset.
178
+ if (!background) return "#000000";
179
+ const arbitrary = background.match(/^bg-\[(.+)\]$/);
180
+ if (arbitrary) return arbitrary[1].replace(/_/g, " ");
181
+ return background.startsWith("bg-") ? null : background;
182
+ }
183
+
184
+ /**
185
+ * Rendered in the style dock when no element is selected — otherwise the
186
+ * slide's own background is unreachable from the editor UI.
187
+ */
188
+ export function SlideBackgroundInspector({
189
+ background,
190
+ designSystem,
191
+ className,
192
+ onChange,
193
+ onClose,
194
+ }: {
195
+ background: string | undefined;
196
+ designSystem?: DesignSystemData;
197
+ className?: string;
198
+ onChange: (background: string) => void;
199
+ onClose?: () => void;
200
+ }) {
201
+ const t = useT();
202
+ const documentColors = tokenPalette(designSystem, t).map(
203
+ (option) => option.value,
204
+ );
205
+ const solid = backgroundCssValue(background);
206
+
207
+ return (
208
+ <VisualInspectorPanel
209
+ title={t("styleInspector.title")}
210
+ subtitle={t("styleInspector.slide")}
211
+ className={className}
212
+ headerAction={
213
+ onClose ? (
214
+ <Button
215
+ type="button"
216
+ variant="ghost"
217
+ size="icon"
218
+ className="size-7 cursor-pointer text-muted-foreground hover:text-foreground"
219
+ onClick={onClose}
220
+ aria-label={t("styleInspector.close")}
221
+ >
222
+ <IconX className="size-3.5" />
223
+ </Button>
224
+ ) : undefined
225
+ }
226
+ >
227
+ <VisualInspectorSection
228
+ title={
229
+ <span className="inline-flex items-center gap-1.5">
230
+ <IconDroplet className="size-3" />
231
+ {t("styleInspector.slideBackground")}
232
+ </span>
233
+ }
234
+ >
235
+ <VisualControlRow label={t("styleInspector.background")}>
236
+ <VisualColorPicker
237
+ label={t("styleInspector.slideBackground")}
238
+ value={solid ?? "#000000"}
239
+ mixed={solid === null}
240
+ mixedLabel={t("styleInspector.mixed")}
241
+ documentColors={documentColors}
242
+ onChange={onChange}
243
+ />
244
+ </VisualControlRow>
245
+ </VisualInspectorSection>
246
+ </VisualInspectorPanel>
247
+ );
248
+ }
249
+
141
250
  function formatValue(value: number) {
142
251
  return Number.isInteger(value)
143
252
  ? String(value)
@@ -153,21 +262,79 @@ export function SlideStyleInspector({
153
262
  designSystem,
154
263
  className,
155
264
  onChange,
265
+ onArrange,
156
266
  onClose,
157
267
  }: {
158
- snapshot: SlideStyleSnapshot;
268
+ snapshot: SlideStyleInspectorSnapshot;
159
269
  designSystem?: DesignSystemData;
160
270
  className?: string;
161
271
  onChange: (patch: SlideStylePatch) => void;
272
+ /** Bring-to-front / send-to-back for the selected freeform object. Omitted
273
+ * (or the snapshot not being a freeform object) hides the Arrange row. */
274
+ onArrange?: (target: "front" | "back") => void;
162
275
  onClose: () => void;
163
276
  }) {
164
277
  const t = useT();
165
278
  const palette = tokenPalette(designSystem, t);
166
279
  const documentColors = palette.map((option) => option.value);
167
- const mixedTextStyles = snapshot.mixedTextStyles ?? [];
168
280
  const inlineEditSurfaceProps = {
169
281
  "data-slide-inline-edit-surface": "true",
170
282
  };
283
+ const inspectorClassName = cn(
284
+ "slide-style-inspector h-full w-full rounded-none border-0 bg-transparent text-foreground shadow-none backdrop-blur-none",
285
+ className,
286
+ );
287
+ const headerAction = (
288
+ <Button
289
+ type="button"
290
+ variant="ghost"
291
+ size="icon"
292
+ className="size-7 shrink-0 text-muted-foreground hover:text-foreground"
293
+ onClick={onClose}
294
+ aria-label={t("styleInspector.close")}
295
+ >
296
+ <IconX className="size-3.5" />
297
+ </Button>
298
+ );
299
+
300
+ if (snapshot.mode === "background") {
301
+ return (
302
+ <VisualInspectorPanel
303
+ title={t("styleInspector.title")}
304
+ subtitle={t("styleInspector.background")}
305
+ className={inspectorClassName}
306
+ headerAction={headerAction}
307
+ >
308
+ <VisualInspectorSection
309
+ title={
310
+ <span className="inline-flex items-center gap-1.5">
311
+ <IconDroplet className="size-3.5" />
312
+ {t("styleInspector.fill")}
313
+ </span>
314
+ }
315
+ className="slides-inspector-section"
316
+ >
317
+ <VisualControlRow
318
+ label={t("styleInspector.color")}
319
+ className="slides-inspector-control"
320
+ >
321
+ <VisualColorPicker
322
+ label={t("styleInspector.fill")}
323
+ value={snapshot.backgroundColor}
324
+ documentColors={documentColors}
325
+ allowTransparent
326
+ variant="filled"
327
+ className="rounded-sm bg-[var(--slides-inspector-control-background)] hover:bg-[var(--slides-inspector-control-background)]"
328
+ contentProps={inlineEditSurfaceProps}
329
+ onChange={(value) => onChange({ backgroundColor: value })}
330
+ />
331
+ </VisualControlRow>
332
+ </VisualInspectorSection>
333
+ </VisualInspectorPanel>
334
+ );
335
+ }
336
+
337
+ const mixedTextStyles = snapshot.mixedTextStyles ?? [];
171
338
  const targetLabel =
172
339
  snapshot.textPreview || snapshot.label || snapshot.tagName.toUpperCase();
173
340
  const horizontalAlignment =
@@ -208,22 +375,8 @@ export function SlideStyleInspector({
208
375
  <VisualInspectorPanel
209
376
  title={t("styleInspector.title")}
210
377
  subtitle={targetLabel}
211
- className={cn(
212
- "slide-style-inspector h-full w-full rounded-none border-0 bg-transparent text-foreground shadow-none backdrop-blur-none",
213
- className,
214
- )}
215
- headerAction={
216
- <Button
217
- type="button"
218
- variant="ghost"
219
- size="icon"
220
- className="size-7 shrink-0 text-muted-foreground hover:text-foreground"
221
- onClick={onClose}
222
- aria-label={t("styleInspector.close")}
223
- >
224
- <IconX className="size-3.5" />
225
- </Button>
226
- }
378
+ className={inspectorClassName}
379
+ headerAction={headerAction}
227
380
  >
228
381
  {snapshot.isAbsolute ? (
229
382
  <VisualInspectorSection
@@ -268,12 +421,16 @@ export function SlideStyleInspector({
268
421
  <div className="grid grid-cols-2 gap-2">
269
422
  <VisualScrubInput
270
423
  label={t("styleInspector.x")}
424
+ icon={null}
425
+ labelClassName="w-8 justify-center"
271
426
  value={snapshot.x}
272
427
  unit="px"
273
428
  onChange={(x) => onChange({ left: `${formatValue(x)}px` })}
274
429
  />
275
430
  <VisualScrubInput
276
431
  label={t("styleInspector.y")}
432
+ icon={null}
433
+ labelClassName="w-8 justify-center"
277
434
  value={snapshot.y}
278
435
  unit="px"
279
436
  onChange={(y) => onChange({ top: `${formatValue(y)}px` })}
@@ -281,6 +438,8 @@ export function SlideStyleInspector({
281
438
  </div>
282
439
  <VisualScrubInput
283
440
  label={t("styleInspector.rotation")}
441
+ icon={IconAngle}
442
+ prefix="icon"
284
443
  value={snapshot.rotation}
285
444
  min={-360}
286
445
  max={360}
@@ -292,6 +451,46 @@ export function SlideStyleInspector({
292
451
  </VisualInspectorSection>
293
452
  ) : null}
294
453
 
454
+ {snapshot.isAbsolute && onArrange ? (
455
+ <VisualInspectorSection
456
+ title={
457
+ <span className="inline-flex items-center gap-1.5">
458
+ <IconStackFront className="size-3.5" />
459
+ {t("styleInspector.arrange")}
460
+ </span>
461
+ }
462
+ className="slides-inspector-section"
463
+ >
464
+ <VisualControlRow
465
+ label={t("styleInspector.order")}
466
+ className="slides-inspector-control"
467
+ >
468
+ <div className="flex items-center gap-1">
469
+ <Button
470
+ type="button"
471
+ variant="ghost"
472
+ size="icon"
473
+ className="size-7 cursor-pointer rounded-sm bg-[var(--slides-inspector-control-background)] text-muted-foreground hover:bg-[var(--slides-inspector-control-background)] hover:text-foreground"
474
+ onClick={() => onArrange("back")}
475
+ aria-label={t("styleInspector.sendToBack")}
476
+ >
477
+ <IconStackBack className="size-3.5" />
478
+ </Button>
479
+ <Button
480
+ type="button"
481
+ variant="ghost"
482
+ size="icon"
483
+ className="size-7 cursor-pointer rounded-sm bg-[var(--slides-inspector-control-background)] text-muted-foreground hover:bg-[var(--slides-inspector-control-background)] hover:text-foreground"
484
+ onClick={() => onArrange("front")}
485
+ aria-label={t("styleInspector.bringToFront")}
486
+ >
487
+ <IconStackFront className="size-3.5" />
488
+ </Button>
489
+ </div>
490
+ </VisualControlRow>
491
+ </VisualInspectorSection>
492
+ ) : null}
493
+
295
494
  <VisualInspectorSection
296
495
  title={
297
496
  <span className="inline-flex items-center gap-1.5">
@@ -304,6 +503,8 @@ export function SlideStyleInspector({
304
503
  <div className="grid grid-cols-2 gap-2">
305
504
  <VisualScrubInput
306
505
  label={t("styleInspector.width")}
506
+ icon={IconArrowAutofitWidth}
507
+ prefix="icon"
307
508
  value={snapshot.width}
308
509
  min={0}
309
510
  unit="px"
@@ -311,6 +512,8 @@ export function SlideStyleInspector({
311
512
  />
312
513
  <VisualScrubInput
313
514
  label={t("styleInspector.height")}
515
+ icon={IconArrowAutofitHeight}
516
+ prefix="icon"
314
517
  value={snapshot.height}
315
518
  min={0}
316
519
  unit="px"
@@ -333,6 +536,8 @@ export function SlideStyleInspector({
333
536
  <div className="grid grid-cols-2 gap-2">
334
537
  <VisualScrubInput
335
538
  label={t("styleInspector.opacity")}
539
+ icon={IconGridDots}
540
+ prefix="icon"
336
541
  value={snapshot.opacity}
337
542
  min={0}
338
543
  max={100}
@@ -342,6 +547,8 @@ export function SlideStyleInspector({
342
547
  />
343
548
  <VisualScrubInput
344
549
  label={t("styleInspector.cornerRadius")}
550
+ icon={IconBorderRadius}
551
+ prefix="icon"
345
552
  value={snapshot.borderRadius}
346
553
  min={0}
347
554
  max={96}
@@ -396,6 +603,8 @@ export function SlideStyleInspector({
396
603
  >
397
604
  <VisualScrubInput
398
605
  label={t("styleInspector.strokeWeight")}
606
+ icon={IconBorderStyle}
607
+ prefix="icon"
399
608
  value={snapshot.borderWidth}
400
609
  min={0}
401
610
  max={16}
@@ -449,6 +658,8 @@ export function SlideStyleInspector({
449
658
  <div className="grid grid-cols-2 gap-2">
450
659
  <VisualScrubInput
451
660
  label={t("styleInspector.size")}
661
+ icon={IconLetterCase}
662
+ prefix="icon"
452
663
  value={snapshot.fontSize}
453
664
  min={8}
454
665
  max={160}
@@ -461,6 +672,8 @@ export function SlideStyleInspector({
461
672
  />
462
673
  <VisualScrubInput
463
674
  label={t("styleInspector.line")}
675
+ icon={IconArrowAutofitHeight}
676
+ prefix="icon"
464
677
  value={snapshot.lineHeight}
465
678
  min={0.8}
466
679
  max={3}
@@ -512,6 +725,8 @@ export function SlideStyleInspector({
512
725
  <div className="grid grid-cols-2 gap-2">
513
726
  <VisualScrubInput
514
727
  label={t("styleInspector.horizontal")}
728
+ icon={IconSpacingHorizontal}
729
+ prefix="icon"
515
730
  value={snapshot.paddingX}
516
731
  min={0}
517
732
  max={120}
@@ -526,6 +741,8 @@ export function SlideStyleInspector({
526
741
  />
527
742
  <VisualScrubInput
528
743
  label={t("styleInspector.vertical")}
744
+ icon={IconSpacingVertical}
745
+ prefix="icon"
529
746
  value={snapshot.paddingY}
530
747
  min={0}
531
748
  max={120}
@@ -7,6 +7,7 @@ interface SpeakerNotesPanelProps {
7
7
  onChange: (notes: string) => void;
8
8
  slideIndex: number;
9
9
  slideCount: number;
10
+ readOnly?: boolean;
10
11
  }
11
12
 
12
13
  const MIN_NOTES_HEIGHT = 72;
@@ -22,6 +23,7 @@ export function SpeakerNotesPanel({
22
23
  onChange,
23
24
  slideIndex,
24
25
  slideCount,
26
+ readOnly = false,
25
27
  }: SpeakerNotesPanelProps) {
26
28
  const t = useT();
27
29
  const [expanded, setExpanded] = useState(() => {
@@ -105,7 +107,8 @@ export function SpeakerNotesPanel({
105
107
  <textarea
106
108
  value={notes || ""}
107
109
  onChange={(e) => onChange(e.target.value)}
108
- placeholder={t("raw.addSpeakerNotes")}
110
+ readOnly={readOnly}
111
+ placeholder={readOnly ? undefined : t("raw.addSpeakerNotes")}
109
112
  className="h-full w-full resize-none bg-transparent font-mono text-xs text-muted-foreground outline-none placeholder:text-muted-foreground/70"
110
113
  />
111
114
  </div>
@@ -0,0 +1,11 @@
1
+ export {
2
+ createSlidesCanvasGestureController,
3
+ createSlidesCanvasInteractionCore,
4
+ isWithinSlidesCanvasEdgeMoveBand,
5
+ resolveSlidesCanvasPointerIntent,
6
+ slidesCanvasInteractionCore,
7
+ SLIDES_CANVAS_EDGE_MOVE_BAND,
8
+ type SlidesCanvasHtmlMutationAdapter,
9
+ type SlidesCanvasGestureAdapter,
10
+ type SlidesCanvasPointerIntent,
11
+ } from "./slides-canvas-adapter";
@@ -0,0 +1,129 @@
1
+ import {
2
+ createCanvasGestureController,
3
+ createCanvasInteractionCore,
4
+ type CanvasGestureAdapter,
5
+ type CanvasInteractionAdapter,
6
+ } from "@agent-native/toolkit/canvas-interactions";
7
+
8
+ import { MIN_SLIDE_OBJECT_SIZE } from "../slide-object-interactions";
9
+
10
+ export const SLIDES_CANVAS_EDGE_MOVE_BAND = 8;
11
+
12
+ export function isWithinSlidesCanvasEdgeMoveBand(
13
+ rect: Pick<DOMRect, "left" | "right" | "top" | "bottom" | "width" | "height">,
14
+ clientX: number,
15
+ clientY: number,
16
+ ): boolean {
17
+ // Tiny labels still need a usable center click target. Cap the move band at
18
+ // one quarter of either dimension so its opposite edges never consume it.
19
+ const edgeBand = Math.min(
20
+ SLIDES_CANVAS_EDGE_MOVE_BAND,
21
+ rect.width / 4,
22
+ rect.height / 4,
23
+ );
24
+ const outerBand = edgeBand / 2;
25
+ const withinExpandedBounds =
26
+ clientX >= rect.left - outerBand &&
27
+ clientX <= rect.right + outerBand &&
28
+ clientY >= rect.top - outerBand &&
29
+ clientY <= rect.bottom + outerBand;
30
+ if (!withinExpandedBounds) return false;
31
+
32
+ return (
33
+ Math.abs(clientX - rect.left) <= edgeBand ||
34
+ Math.abs(clientX - rect.right) <= edgeBand ||
35
+ Math.abs(clientY - rect.top) <= edgeBand ||
36
+ Math.abs(clientY - rect.bottom) <= edgeBand
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Slides owns its persistence adapter: it translates shared semantic commands
42
+ * into mutations of the selected slide's HTML. Toolkit remains unaware of the
43
+ * DOM, coordinate containers, and the one-write-per-gesture boundary.
44
+ */
45
+ export type SlidesCanvasHtmlMutationAdapter = CanvasInteractionAdapter<string>;
46
+ export type SlidesCanvasGestureAdapter = CanvasGestureAdapter<string>;
47
+
48
+ const slidesCanvasInteractionConfig = {
49
+ textEditing: {
50
+ activation: "single-click" as const,
51
+ escapeBehavior: "select-object" as const,
52
+ },
53
+ drag: {
54
+ threshold: 2,
55
+ duplicateModifier: "alt" as const,
56
+ },
57
+ nudge: {
58
+ amount: 1,
59
+ acceleratedAmount: 10,
60
+ },
61
+ minSize: MIN_SLIDE_OBJECT_SIZE,
62
+ capabilities: {
63
+ multiSelection: true,
64
+ snapping: false,
65
+ alignment: false,
66
+ distribution: false,
67
+ grouping: false,
68
+ rotation: false,
69
+ marquee: true,
70
+ },
71
+ };
72
+
73
+ export function createSlidesCanvasInteractionCore(
74
+ adapter?: SlidesCanvasHtmlMutationAdapter,
75
+ ) {
76
+ return createCanvasInteractionCore(slidesCanvasInteractionConfig, adapter);
77
+ }
78
+
79
+ /** Creates one shared controller per live Slides pointer gesture. */
80
+ export function createSlidesCanvasGestureController(
81
+ adapter: SlidesCanvasGestureAdapter,
82
+ ) {
83
+ return createCanvasGestureController({
84
+ ...slidesCanvasInteractionConfig,
85
+ adapter,
86
+ });
87
+ }
88
+
89
+ /** Shared Slides policy for callers that do not need an HTML command adapter. */
90
+ export const slidesCanvasInteractionCore = createSlidesCanvasInteractionCore();
91
+
92
+ export type SlidesCanvasPointerIntent =
93
+ | "edit-text"
94
+ | "move-object-body"
95
+ | "move-object-perimeter"
96
+ | "none";
97
+
98
+ /**
99
+ * Slides supplies hit testing and this policy decision, while the shared
100
+ * gesture controller owns threshold, coordinate, modifier, and resize math.
101
+ * A selected object's body begins a thresholded move candidate. An unmoved
102
+ * press still falls through to the click handler for text editing, while a
103
+ * real drag consumes that trailing click.
104
+ */
105
+ export function resolveSlidesCanvasPointerIntent({
106
+ hasSelectedObject,
107
+ targetWithinSelectedObject,
108
+ targetContainsSelectedObject,
109
+ pointerWithinMoveBand,
110
+ targetIsEditableText,
111
+ }: {
112
+ hasSelectedObject: boolean;
113
+ targetWithinSelectedObject: boolean;
114
+ targetContainsSelectedObject: boolean;
115
+ pointerWithinMoveBand: boolean;
116
+ targetIsEditableText: boolean;
117
+ }): SlidesCanvasPointerIntent {
118
+ if (
119
+ hasSelectedObject &&
120
+ (targetWithinSelectedObject || targetContainsSelectedObject) &&
121
+ pointerWithinMoveBand
122
+ ) {
123
+ return "move-object-perimeter";
124
+ }
125
+ if (hasSelectedObject && targetWithinSelectedObject) {
126
+ return "move-object-body";
127
+ }
128
+ return targetIsEditableText ? "edit-text" : "none";
129
+ }
@@ -0,0 +1,70 @@
1
+ export interface SelectionOverlayMeasurement {
2
+ key: string;
3
+ rect: DOMRect;
4
+ }
5
+
6
+ export interface SelectionOverlayMeasurementIdentity {
7
+ slideId: string;
8
+ content: string;
9
+ objectId: string | null;
10
+ selector: string | null;
11
+ path: number[] | null;
12
+ canvasZoom: number;
13
+ stylePanelOpen: boolean;
14
+ revision: number;
15
+ }
16
+
17
+ /**
18
+ * The portal paints in viewport coordinates. Its measurement is only valid
19
+ * for this exact rendered selection and canvas geometry.
20
+ */
21
+ export function createSelectionOverlayMeasurementKey({
22
+ slideId,
23
+ content,
24
+ objectId,
25
+ selector,
26
+ path,
27
+ canvasZoom,
28
+ stylePanelOpen,
29
+ revision,
30
+ }: SelectionOverlayMeasurementIdentity): string {
31
+ return JSON.stringify([
32
+ slideId,
33
+ content,
34
+ objectId,
35
+ selector,
36
+ path,
37
+ canvasZoom,
38
+ stylePanelOpen,
39
+ revision,
40
+ ]);
41
+ }
42
+
43
+ /** AutoFit only depends on the rendered slide, not editor-only canvas chrome. */
44
+ export function createSelectionOverlayAutofitKey(
45
+ slideId: string,
46
+ content: string,
47
+ ): string {
48
+ return JSON.stringify([slideId, content]);
49
+ }
50
+
51
+ export function currentSelectionOverlayRect(
52
+ measurement: SelectionOverlayMeasurement | null,
53
+ currentKey: string,
54
+ ): DOMRect | null {
55
+ return measurement?.key === currentKey ? measurement.rect : null;
56
+ }
57
+
58
+ export function isSelectionOverlayAutofitSettled(
59
+ settledAutofitKey: string | null,
60
+ canvasAutofitKey: string,
61
+ ): boolean {
62
+ return settledAutofitKey === canvasAutofitKey;
63
+ }
64
+
65
+ export function isSelectionOverlayOnActiveSlide(
66
+ selectedSlideId: string | null,
67
+ activeSlideId: string,
68
+ ): boolean {
69
+ return selectedSlideId === activeSlideId;
70
+ }