@agent-native/core 0.80.10 → 0.81.0

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 (267) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +53 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +108 -15
  5. package/corpus/core/src/cli/design-connect.ts +419 -19
  6. package/corpus/core/src/client/AssistantChat.tsx +123 -26
  7. package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
  8. package/corpus/core/src/client/chat/index.ts +1 -0
  9. package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
  10. package/corpus/core/src/client/chat-view-transition.ts +33 -2
  11. package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
  12. package/corpus/core/src/client/index.ts +1 -0
  13. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
  14. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
  15. package/corpus/core/src/client/sse-event-processor.ts +9 -0
  16. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
  17. package/corpus/core/src/db/client.ts +29 -2
  18. package/corpus/core/src/provider-api/index.ts +29 -0
  19. package/corpus/core/src/server/core-routes-plugin.ts +58 -20
  20. package/corpus/core/src/styles/agent-native.css +54 -0
  21. package/corpus/core/src/usage/store.ts +2 -2
  22. package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
  23. package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
  24. package/corpus/templates/analytics/app/global.css +8 -0
  25. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
  26. package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
  27. package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
  28. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
  29. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
  30. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
  31. package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
  36. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
  37. package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
  38. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
  39. package/corpus/templates/assets/AGENTS.md +4 -0
  40. package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
  41. package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
  42. package/corpus/templates/assets/actions/generate-image.ts +118 -67
  43. package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
  44. package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
  45. package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
  46. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
  47. package/corpus/templates/assets/app/global.css +15 -0
  48. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
  49. package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
  50. package/corpus/templates/assets/app/i18n-data.ts +61 -0
  51. package/corpus/templates/assets/app/routes/_index.tsx +4 -0
  52. package/corpus/templates/assets/app/routes/library.tsx +233 -52
  53. package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
  54. package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
  55. package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
  56. package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
  57. package/corpus/templates/assets/server/lib/generation.ts +135 -11
  58. package/corpus/templates/assets/shared/api.ts +4 -0
  59. package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
  60. package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
  61. package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
  62. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
  63. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
  64. package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
  65. package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
  66. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  67. package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
  68. package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
  69. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
  70. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
  71. package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
  72. package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
  73. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
  74. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
  75. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
  76. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
  77. package/corpus/templates/design/AGENTS.md +27 -0
  78. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
  79. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
  80. package/corpus/templates/design/actions/apply-component-prop-edit.ts +76 -25
  81. package/corpus/templates/design/actions/apply-design-state.ts +17 -4
  82. package/corpus/templates/design/actions/apply-motion-edit.ts +76 -115
  83. package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
  84. package/corpus/templates/design/actions/capture-design-state.ts +27 -4
  85. package/corpus/templates/design/actions/connect-localhost.ts +59 -22
  86. package/corpus/templates/design/actions/delete-design.ts +20 -0
  87. package/corpus/templates/design/actions/export-zip.ts +23 -8
  88. package/corpus/templates/design/actions/generate-design.ts +53 -1
  89. package/corpus/templates/design/actions/get-component-details.ts +21 -26
  90. package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
  91. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
  92. package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
  93. package/corpus/templates/design/actions/index-design-tokens.ts +18 -5
  94. package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
  95. package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
  96. package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
  97. package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
  98. package/corpus/templates/design/actions/list-design-states.ts +19 -1
  99. package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
  100. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
  101. package/corpus/templates/design/actions/navigate.ts +18 -3
  102. package/corpus/templates/design/actions/open-component-source.ts +7 -2
  103. package/corpus/templates/design/actions/preview-component-prop-edit.ts +32 -26
  104. package/corpus/templates/design/actions/preview-shader-fill.ts +9 -11
  105. package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
  106. package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
  107. package/corpus/templates/design/actions/provider-api-request.ts +3 -3
  108. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
  109. package/corpus/templates/design/actions/run-design-audit.ts +74 -10
  110. package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
  111. package/corpus/templates/design/actions/view-screen.ts +1 -1
  112. package/corpus/templates/design/actions/write-local-file.ts +213 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +244 -3197
  114. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
  115. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +795 -289
  116. package/corpus/templates/design/app/components/design/EditPanel.tsx +635 -234
  117. package/corpus/templates/design/app/components/design/LayersPanel.tsx +124 -32
  118. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
  119. package/corpus/templates/design/app/components/design/MotionDock.tsx +244 -266
  120. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +491 -56
  121. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +55 -67
  122. package/corpus/templates/design/app/components/design/StatesPanel.tsx +38 -63
  123. package/corpus/templates/design/app/components/design/TokensPanel.tsx +264 -8
  124. package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
  125. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
  126. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
  127. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
  128. package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
  129. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
  130. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
  131. package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
  132. package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
  133. package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
  134. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
  135. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
  136. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
  137. package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
  138. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  139. package/corpus/templates/design/app/global.css +7 -0
  140. package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
  141. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  142. package/corpus/templates/design/app/i18n-data.ts +369 -0
  143. package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
  144. package/corpus/templates/design/app/pages/DesignEditor.tsx +3024 -616
  145. package/corpus/templates/design/app/pages/Index.tsx +5 -1
  146. package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
  165. package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
  166. package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
  167. package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
  168. package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
  169. package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
  170. package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
  171. package/corpus/templates/design/e2e/global-setup.ts +94 -2
  172. package/corpus/templates/design/e2e/helpers.ts +168 -65
  173. package/corpus/templates/design/package.json +3 -1
  174. package/corpus/templates/design/server/db/schema.ts +23 -0
  175. package/corpus/templates/design/server/handlers/uploads.ts +22 -1
  176. package/corpus/templates/design/server/lib/provider-api.ts +7 -4
  177. package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
  178. package/corpus/templates/design/server/plugins/db.ts +39 -0
  179. package/corpus/templates/design/server/register-secrets.ts +38 -0
  180. package/corpus/templates/design/shared/board-file.ts +228 -0
  181. package/corpus/templates/design/shared/board-objects.ts +288 -0
  182. package/corpus/templates/design/shared/code-layer.ts +52 -0
  183. package/corpus/templates/design/shared/component-model.ts +35 -0
  184. package/corpus/templates/design/shared/motion-compiler.ts +137 -15
  185. package/corpus/templates/design/shared/motion-timeline.ts +2 -2
  186. package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
  187. package/corpus/templates/design/tsconfig.json +2 -1
  188. package/corpus/templates/slides/AGENTS.md +9 -0
  189. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
  190. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
  191. package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
  192. package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
  193. package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
  194. package/corpus/templates/slides/app/vite-env.d.ts +18 -0
  195. package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
  196. package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
  197. package/corpus/templates/slides/package.json +1 -0
  198. package/corpus/templates/slides/vite.config.ts +1 -0
  199. package/dist/agent/production-agent.d.ts.map +1 -1
  200. package/dist/agent/production-agent.js +94 -10
  201. package/dist/agent/production-agent.js.map +1 -1
  202. package/dist/cli/design-connect.d.ts +25 -0
  203. package/dist/cli/design-connect.d.ts.map +1 -1
  204. package/dist/cli/design-connect.js +357 -18
  205. package/dist/cli/design-connect.js.map +1 -1
  206. package/dist/client/AssistantChat.d.ts +14 -0
  207. package/dist/client/AssistantChat.d.ts.map +1 -1
  208. package/dist/client/AssistantChat.js +115 -22
  209. package/dist/client/AssistantChat.js.map +1 -1
  210. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  211. package/dist/client/ConnectBuilderCard.js +1 -0
  212. package/dist/client/ConnectBuilderCard.js.map +1 -1
  213. package/dist/client/chat/index.d.ts +1 -1
  214. package/dist/client/chat/index.d.ts.map +1 -1
  215. package/dist/client/chat/index.js +1 -1
  216. package/dist/client/chat/index.js.map +1 -1
  217. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  218. package/dist/client/chat/run-recovery.js +5 -5
  219. package/dist/client/chat/run-recovery.js.map +1 -1
  220. package/dist/client/chat-view-transition.d.ts +6 -0
  221. package/dist/client/chat-view-transition.d.ts.map +1 -1
  222. package/dist/client/chat-view-transition.js +23 -2
  223. package/dist/client/chat-view-transition.js.map +1 -1
  224. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  225. package/dist/client/composer/PromptComposer.js +3 -2
  226. package/dist/client/composer/PromptComposer.js.map +1 -1
  227. package/dist/client/index.d.ts +1 -1
  228. package/dist/client/index.d.ts.map +1 -1
  229. package/dist/client/index.js +1 -1
  230. package/dist/client/index.js.map +1 -1
  231. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  232. package/dist/client/org/OrgSwitcher.js +11 -4
  233. package/dist/client/org/OrgSwitcher.js.map +1 -1
  234. package/dist/client/sharing/ShareButton.js +3 -3
  235. package/dist/client/sharing/ShareButton.js.map +1 -1
  236. package/dist/client/sse-event-processor.d.ts.map +1 -1
  237. package/dist/client/sse-event-processor.js +10 -0
  238. package/dist/client/sse-event-processor.js.map +1 -1
  239. package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
  240. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  241. package/dist/client/use-agent-chat-home-handoff.js +20 -6
  242. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  243. package/dist/collab/awareness.d.ts +2 -2
  244. package/dist/collab/awareness.d.ts.map +1 -1
  245. package/dist/collab/routes.d.ts +2 -2
  246. package/dist/db/client.d.ts +1 -0
  247. package/dist/db/client.d.ts.map +1 -1
  248. package/dist/db/client.js +28 -2
  249. package/dist/db/client.js.map +1 -1
  250. package/dist/notifications/routes.d.ts +3 -3
  251. package/dist/observability/routes.d.ts +3 -3
  252. package/dist/progress/routes.d.ts +1 -1
  253. package/dist/provider-api/index.d.ts +5 -4
  254. package/dist/provider-api/index.d.ts.map +1 -1
  255. package/dist/provider-api/index.js +28 -0
  256. package/dist/provider-api/index.js.map +1 -1
  257. package/dist/resources/handlers.d.ts +3 -3
  258. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  259. package/dist/server/core-routes-plugin.d.ts +25 -0
  260. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  261. package/dist/server/core-routes-plugin.js +43 -18
  262. package/dist/server/core-routes-plugin.js.map +1 -1
  263. package/dist/server/transcribe-voice.d.ts +1 -1
  264. package/dist/styles/agent-native.css +54 -0
  265. package/dist/usage/store.js +2 -2
  266. package/dist/usage/store.js.map +1 -1
  267. package/package.json +1 -1
@@ -0,0 +1,268 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { readAppStateForCurrentTab } from "@agent-native/core/application-state";
3
+ import {
4
+ applyText,
5
+ getText,
6
+ hasCollabState,
7
+ seedFromText,
8
+ } from "@agent-native/core/collab";
9
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
10
+ import { and, eq } from "drizzle-orm";
11
+ import { z } from "zod";
12
+
13
+ import { getDb, schema } from "../server/db/index.js";
14
+ import {
15
+ DESIGN_NATIVE_ASSET_KINDS,
16
+ type DesignNativeAssetKind,
17
+ } from "./list-design-native-assets.js";
18
+
19
+ const schemaInput = z.object({
20
+ kind: z
21
+ .enum(DESIGN_NATIVE_ASSET_KINDS)
22
+ .describe("Design-native asset kind from list-design-native-assets."),
23
+ designId: z
24
+ .string()
25
+ .optional()
26
+ .describe("Design id. Defaults to the current editor navigation state."),
27
+ fileId: z
28
+ .string()
29
+ .optional()
30
+ .describe("Design file id. Defaults to the active editor file."),
31
+ ownerId: z
32
+ .string()
33
+ .optional()
34
+ .describe("Design editor selection owner token from current screen state."),
35
+ });
36
+
37
+ function stringFromState(state: unknown, key: string): string | undefined {
38
+ if (!state || typeof state !== "object") return undefined;
39
+ const value = (state as Record<string, unknown>)[key];
40
+ return typeof value === "string" && value ? value : undefined;
41
+ }
42
+
43
+ function insertBeforeClosingTag(
44
+ html: string,
45
+ closingTag: "main" | "body",
46
+ snippet: string,
47
+ ): string | null {
48
+ const pattern = new RegExp(`</${closingTag}>`, "i");
49
+ if (!pattern.test(html)) return null;
50
+ return html.replace(pattern, `${snippet}\n</${closingTag}>`);
51
+ }
52
+
53
+ function nativeSnippet(kind: DesignNativeAssetKind): string {
54
+ const attrs = (componentName: string) =>
55
+ `data-agent-native-native-asset data-agent-native-component="${componentName}" data-agent-native-layer-name="${componentName}"`;
56
+ switch (kind) {
57
+ case "section-frame":
58
+ return `
59
+ <section ${attrs("Frame")} class="mx-auto my-8 max-w-5xl rounded-2xl border border-slate-200 bg-white/90 p-8 shadow-sm">
60
+ <div class="text-sm font-medium uppercase text-slate-500">Frame</div>
61
+ <div class="mt-3 min-h-24 rounded-xl border border-dashed border-slate-300 bg-slate-50"></div>
62
+ </section>`;
63
+ case "text-block":
64
+ return `
65
+ <section ${attrs("TextBlock")} class="mx-auto my-8 max-w-3xl px-4">
66
+ <p class="text-sm font-medium uppercase text-slate-500">Eyebrow</p>
67
+ <h2 class="mt-3 text-3xl font-semibold text-slate-950">Editable headline</h2>
68
+ <p class="mt-3 text-base leading-7 text-slate-600">Use this text block as a native content primitive, then edit copy, spacing, and typography in Design.</p>
69
+ </section>`;
70
+ case "button":
71
+ return `
72
+ <section class="mx-auto my-8 max-w-5xl px-4">
73
+ <button ${attrs("Button")} class="inline-flex h-11 items-center justify-center rounded-lg bg-slate-950 px-5 text-sm font-medium text-white shadow-sm transition hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2">
74
+ Primary action
75
+ </button>
76
+ </section>`;
77
+ case "card":
78
+ return `
79
+ <section class="mx-auto my-8 max-w-5xl px-4">
80
+ <article ${attrs("Card")} class="max-w-sm rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
81
+ <div class="flex h-10 w-10 items-center justify-center rounded-xl bg-slate-100 text-sm font-semibold text-slate-700">01</div>
82
+ <h3 class="mt-4 text-lg font-semibold text-slate-950">Native card</h3>
83
+ <p class="mt-2 text-sm leading-6 text-slate-600">A reusable content block with editable text, spacing, border, and action styling.</p>
84
+ <button class="mt-4 text-sm font-medium text-slate-950">Learn more</button>
85
+ </article>
86
+ </section>`;
87
+ case "input":
88
+ return `
89
+ <section class="mx-auto my-8 max-w-md px-4">
90
+ <label ${attrs("Input")} class="block">
91
+ <span class="text-sm font-medium text-slate-700">Email</span>
92
+ <input class="mt-2 h-11 w-full rounded-lg border border-slate-300 bg-white px-3 text-sm text-slate-950 shadow-sm outline-none transition placeholder:text-slate-400 focus:border-slate-500 focus:ring-2 focus:ring-slate-200" placeholder="you@example.com" />
93
+ <span class="mt-2 block text-xs text-slate-500">Helper text can explain the field.</span>
94
+ </label>
95
+ </section>`;
96
+ case "nav-bar":
97
+ return `
98
+ <nav ${attrs("NavBar")} class="mx-auto my-8 flex max-w-5xl items-center justify-between rounded-2xl border border-slate-200 bg-white px-4 py-3 shadow-sm">
99
+ <div class="text-sm font-semibold text-slate-950">Product</div>
100
+ <div class="hidden items-center gap-5 text-sm text-slate-600 sm:flex">
101
+ <a href="#" class="hover:text-slate-950">Overview</a>
102
+ <a href="#" class="hover:text-slate-950">Pricing</a>
103
+ <a href="#" class="hover:text-slate-950">Docs</a>
104
+ </div>
105
+ <button class="rounded-lg bg-slate-950 px-3 py-2 text-sm font-medium text-white">Start</button>
106
+ </nav>`;
107
+ case "hero":
108
+ return `
109
+ <section ${attrs("Hero")} class="mx-auto my-8 grid max-w-5xl gap-8 rounded-3xl bg-slate-950 px-6 py-10 text-white sm:grid-cols-[1.15fr_0.85fr] sm:px-8">
110
+ <div>
111
+ <p class="text-sm font-medium uppercase text-slate-300">Native hero</p>
112
+ <h1 class="mt-4 text-4xl font-semibold">A clear product promise</h1>
113
+ <p class="mt-4 max-w-xl text-base leading-7 text-slate-300">Drop in a complete editable section and reshape it with Design tools.</p>
114
+ <button class="mt-6 rounded-lg bg-white px-4 py-2 text-sm font-medium text-slate-950">Get started</button>
115
+ </div>
116
+ <div class="min-h-48 rounded-2xl bg-white/10 ring-1 ring-white/15"></div>
117
+ </section>`;
118
+ case "feature-grid":
119
+ return `
120
+ <section ${attrs("FeatureGrid")} class="mx-auto my-8 max-w-5xl px-4">
121
+ <div class="grid gap-3 sm:grid-cols-3">
122
+ ${["Fast", "Flexible", "Observable"]
123
+ .map(
124
+ (
125
+ title,
126
+ ) => `<article class="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
127
+ <h3 class="text-base font-semibold text-slate-950">${title}</h3>
128
+ <p class="mt-2 text-sm leading-6 text-slate-600">Edit this native component copy and styling directly.</p>
129
+ </article>`,
130
+ )
131
+ .join("")}
132
+ </div>
133
+ </section>`;
134
+ }
135
+ }
136
+
137
+ function appendNativeAssetMarkup(
138
+ html: string,
139
+ kind: DesignNativeAssetKind,
140
+ ): string {
141
+ const snippet = nativeSnippet(kind);
142
+ return (
143
+ insertBeforeClosingTag(html, "main", snippet) ??
144
+ insertBeforeClosingTag(html, "body", snippet) ??
145
+ `${html}\n${snippet}`
146
+ );
147
+ }
148
+
149
+ async function resolveTarget(args: z.infer<typeof schemaInput>) {
150
+ const [navigation, selection] = await Promise.all([
151
+ readAppStateForCurrentTab("navigation").catch(() => null),
152
+ readAppStateForCurrentTab("design-selection").catch(() => null),
153
+ ]);
154
+ const navigationDesignId = stringFromState(navigation, "designId");
155
+ const selectionDesignId = stringFromState(selection, "designId");
156
+ const selectionOwnerId = stringFromState(selection, "ownerId");
157
+ const selectionMatchesOwner =
158
+ Boolean(args.ownerId) && selectionOwnerId === args.ownerId;
159
+ const designId =
160
+ args.designId ??
161
+ (selectionMatchesOwner ? selectionDesignId : undefined) ??
162
+ navigationDesignId;
163
+ const canUseSelection =
164
+ selectionMatchesOwner &&
165
+ Boolean(designId) &&
166
+ selectionDesignId === designId;
167
+ const navigationActiveFileId =
168
+ designId && navigationDesignId === designId
169
+ ? stringFromState(navigation, "activeFileId")
170
+ : undefined;
171
+ return {
172
+ designId,
173
+ fileId:
174
+ args.fileId ??
175
+ (canUseSelection
176
+ ? stringFromState(selection, "activeFileId")
177
+ : undefined) ??
178
+ navigationActiveFileId,
179
+ };
180
+ }
181
+
182
+ function isHtmlFile(file: {
183
+ fileType: string | null;
184
+ filename: string | null;
185
+ }): boolean {
186
+ return file.fileType === "html" || file.filename?.endsWith(".html") === true;
187
+ }
188
+
189
+ export default defineAction({
190
+ description:
191
+ "Insert a Design-native reusable primitive/component into the active design file. Use list-design-native-assets first to choose a kind. Inserts editable HTML stamped with Design component and layer metadata.",
192
+ schema: schemaInput,
193
+ publicAgent: { expose: true, readOnly: false, requiresAuth: true },
194
+ run: async (args) => {
195
+ const target = await resolveTarget(args);
196
+ if (!target.designId) {
197
+ throw new Error(
198
+ "No active design found. Open a design or pass designId.",
199
+ );
200
+ }
201
+
202
+ const db = getDb();
203
+ const files = await db
204
+ .select({
205
+ id: schema.designFiles.id,
206
+ designId: schema.designFiles.designId,
207
+ filename: schema.designFiles.filename,
208
+ fileType: schema.designFiles.fileType,
209
+ content: schema.designFiles.content,
210
+ })
211
+ .from(schema.designFiles)
212
+ .innerJoin(
213
+ schema.designs,
214
+ eq(schema.designFiles.designId, schema.designs.id),
215
+ )
216
+ .where(
217
+ and(
218
+ eq(schema.designFiles.designId, target.designId),
219
+ accessFilter(schema.designs, schema.designShares),
220
+ ),
221
+ );
222
+ const requestedFile = files.find(
223
+ (candidate) => candidate.id === target.fileId,
224
+ );
225
+ const file =
226
+ requestedFile && isHtmlFile(requestedFile)
227
+ ? requestedFile
228
+ : (files.find(isHtmlFile) ?? null);
229
+ if (!file) throw new Error("No editable HTML design file found.");
230
+ await assertAccess("design", file.designId, "editor");
231
+
232
+ let base = file.content ?? "";
233
+ try {
234
+ if (await hasCollabState(file.id)) {
235
+ const live = await getText(file.id, "content");
236
+ if (typeof live === "string") base = live;
237
+ }
238
+ } catch {
239
+ // Collab read is best-effort; fall back to stored content.
240
+ }
241
+
242
+ const content = appendNativeAssetMarkup(base, args.kind);
243
+ const now = new Date().toISOString();
244
+ await db
245
+ .update(schema.designFiles)
246
+ .set({ content, updatedAt: now })
247
+ .where(eq(schema.designFiles.id, file.id));
248
+ await db
249
+ .update(schema.designs)
250
+ .set({ updatedAt: now })
251
+ .where(eq(schema.designs.id, file.designId));
252
+
253
+ if (await hasCollabState(file.id)) {
254
+ await applyText(file.id, content, "content", "agent");
255
+ } else {
256
+ await seedFromText(file.id, content);
257
+ }
258
+
259
+ return {
260
+ designId: file.designId,
261
+ fileId: file.id,
262
+ filename: file.filename,
263
+ inserted: true,
264
+ source: "design-native",
265
+ kind: args.kind,
266
+ };
267
+ },
268
+ });
@@ -0,0 +1,233 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { readAppStateForCurrentTab } from "@agent-native/core/application-state";
3
+ import {
4
+ applyText,
5
+ getText,
6
+ hasCollabState,
7
+ seedFromText,
8
+ } from "@agent-native/core/collab";
9
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
10
+ import { and, eq } from "drizzle-orm";
11
+ import { z } from "zod";
12
+
13
+ import { getDb, schema } from "../server/db/index.js";
14
+
15
+ const schemaInput = z.object({
16
+ renderUrl: z
17
+ .string()
18
+ .url()
19
+ .refine((value) => {
20
+ try {
21
+ const protocol = new URL(value).protocol;
22
+ return protocol === "http:" || protocol === "https:";
23
+ } catch {
24
+ return false;
25
+ }
26
+ }, "Render URL must use http or https.")
27
+ .describe(
28
+ "Figma-rendered SVG/PNG URL returned by list-figma-library-assets.",
29
+ ),
30
+ fileKey: z.string().describe("Figma file key."),
31
+ nodeId: z.string().optional().describe("Figma node id for this asset."),
32
+ componentKey: z.string().optional().describe("Figma component key."),
33
+ kind: z.enum(["component", "component_set"]).default("component"),
34
+ name: z.string().optional().describe("Human-readable Figma asset name."),
35
+ description: z.string().optional().describe("Figma asset description."),
36
+ sourceUrl: z
37
+ .string()
38
+ .url()
39
+ .optional()
40
+ .describe("URL back to the Figma node."),
41
+ designId: z
42
+ .string()
43
+ .optional()
44
+ .describe("Design id. Defaults to the current editor navigation state."),
45
+ fileId: z
46
+ .string()
47
+ .optional()
48
+ .describe("Design file id. Defaults to the active editor file."),
49
+ ownerId: z
50
+ .string()
51
+ .optional()
52
+ .describe("Design editor selection owner token from current screen state."),
53
+ });
54
+
55
+ function stringFromState(state: unknown, key: string): string | undefined {
56
+ if (!state || typeof state !== "object") return undefined;
57
+ const value = (state as Record<string, unknown>)[key];
58
+ return typeof value === "string" && value ? value : undefined;
59
+ }
60
+
61
+ function escapeHtml(value: string): string {
62
+ return value
63
+ .replace(/&/g, "&amp;")
64
+ .replace(/</g, "&lt;")
65
+ .replace(/>/g, "&gt;")
66
+ .replace(/"/g, "&quot;");
67
+ }
68
+
69
+ function insertBeforeClosingTag(
70
+ html: string,
71
+ closingTag: "main" | "body",
72
+ snippet: string,
73
+ ): string | null {
74
+ const pattern = new RegExp(`</${closingTag}>`, "i");
75
+ if (!pattern.test(html)) return null;
76
+ return html.replace(pattern, `${snippet}\n</${closingTag}>`);
77
+ }
78
+
79
+ function optionalDataAttribute(name: string, value: string | undefined) {
80
+ return value ? ` ${name}="${escapeHtml(value)}"` : "";
81
+ }
82
+
83
+ function appendFigmaAssetMarkup(
84
+ html: string,
85
+ args: z.infer<typeof schemaInput>,
86
+ ): string {
87
+ const label = args.name?.trim() || "Figma library asset";
88
+ const description = args.description?.trim();
89
+ const sourceLink = args.sourceUrl
90
+ ? `<a href="${escapeHtml(args.sourceUrl)}" target="_blank" rel="noreferrer" class="text-slate-500 underline decoration-slate-300 underline-offset-2 hover:text-slate-800">Open in Figma</a>`
91
+ : "";
92
+ const snippet = `
93
+ <section class="mx-auto my-8 max-w-5xl px-4" data-agent-native-asset-source="figma" data-agent-native-figma-asset data-figma-file-key="${escapeHtml(args.fileKey)}"${optionalDataAttribute("data-figma-node-id", args.nodeId)}${optionalDataAttribute("data-figma-component-key", args.componentKey)} data-figma-asset-kind="${escapeHtml(args.kind)}">
94
+ <figure class="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
95
+ <img src="${escapeHtml(args.renderUrl)}" alt="${escapeHtml(label)}" class="w-full rounded-t-2xl object-contain" />
96
+ <figcaption class="flex flex-wrap items-center gap-x-3 gap-y-1 px-4 py-3 text-sm text-slate-600">
97
+ <span class="font-medium text-slate-800">${escapeHtml(label)}</span>
98
+ ${description ? `<span>${escapeHtml(description)}</span>` : ""}
99
+ ${sourceLink}
100
+ </figcaption>
101
+ </figure>
102
+ </section>`;
103
+
104
+ return (
105
+ insertBeforeClosingTag(html, "main", snippet) ??
106
+ insertBeforeClosingTag(html, "body", snippet) ??
107
+ `${html}\n${snippet}`
108
+ );
109
+ }
110
+
111
+ async function resolveTarget(args: z.infer<typeof schemaInput>) {
112
+ const [navigation, selection] = await Promise.all([
113
+ readAppStateForCurrentTab("navigation").catch(() => null),
114
+ readAppStateForCurrentTab("design-selection").catch(() => null),
115
+ ]);
116
+ const navigationDesignId = stringFromState(navigation, "designId");
117
+ const selectionDesignId = stringFromState(selection, "designId");
118
+ const selectionOwnerId = stringFromState(selection, "ownerId");
119
+ const selectionMatchesOwner =
120
+ Boolean(args.ownerId) && selectionOwnerId === args.ownerId;
121
+ const designId =
122
+ args.designId ??
123
+ (selectionMatchesOwner ? selectionDesignId : undefined) ??
124
+ navigationDesignId;
125
+ const canUseSelection =
126
+ selectionMatchesOwner &&
127
+ Boolean(designId) &&
128
+ selectionDesignId === designId;
129
+ const navigationActiveFileId =
130
+ designId && navigationDesignId === designId
131
+ ? stringFromState(navigation, "activeFileId")
132
+ : undefined;
133
+ return {
134
+ designId,
135
+ fileId:
136
+ args.fileId ??
137
+ (canUseSelection
138
+ ? stringFromState(selection, "activeFileId")
139
+ : undefined) ??
140
+ navigationActiveFileId,
141
+ };
142
+ }
143
+
144
+ function isHtmlFile(file: {
145
+ fileType: string | null;
146
+ filename: string | null;
147
+ }): boolean {
148
+ return file.fileType === "html" || file.filename?.endsWith(".html") === true;
149
+ }
150
+
151
+ export default defineAction({
152
+ description:
153
+ "Insert a rendered Figma component or component set into a Design file, preserving Figma file/node/component provenance. Use list-figma-library-assets first to get renderUrl and metadata.",
154
+ schema: schemaInput,
155
+ publicAgent: { expose: true, readOnly: false, requiresAuth: true },
156
+ run: async (args) => {
157
+ const target = await resolveTarget(args);
158
+ if (!target.designId) {
159
+ throw new Error(
160
+ "No active design found. Open a design or pass designId.",
161
+ );
162
+ }
163
+
164
+ const db = getDb();
165
+ const files = await db
166
+ .select({
167
+ id: schema.designFiles.id,
168
+ designId: schema.designFiles.designId,
169
+ filename: schema.designFiles.filename,
170
+ fileType: schema.designFiles.fileType,
171
+ content: schema.designFiles.content,
172
+ })
173
+ .from(schema.designFiles)
174
+ .innerJoin(
175
+ schema.designs,
176
+ eq(schema.designFiles.designId, schema.designs.id),
177
+ )
178
+ .where(
179
+ and(
180
+ eq(schema.designFiles.designId, target.designId),
181
+ accessFilter(schema.designs, schema.designShares),
182
+ ),
183
+ );
184
+ const requestedFile = files.find(
185
+ (candidate) => candidate.id === target.fileId,
186
+ );
187
+ const file =
188
+ requestedFile && isHtmlFile(requestedFile)
189
+ ? requestedFile
190
+ : (files.find(isHtmlFile) ?? null);
191
+ if (!file) throw new Error("No editable HTML design file found.");
192
+ await assertAccess("design", file.designId, "editor");
193
+
194
+ let base = file.content ?? "";
195
+ try {
196
+ if (await hasCollabState(file.id)) {
197
+ const live = await getText(file.id, "content");
198
+ if (typeof live === "string") base = live;
199
+ }
200
+ } catch {
201
+ // Collab read is best-effort; fall back to stored content.
202
+ }
203
+
204
+ const content = appendFigmaAssetMarkup(base, args);
205
+ const now = new Date().toISOString();
206
+ await db
207
+ .update(schema.designFiles)
208
+ .set({ content, updatedAt: now })
209
+ .where(eq(schema.designFiles.id, file.id));
210
+ await db
211
+ .update(schema.designs)
212
+ .set({ updatedAt: now })
213
+ .where(eq(schema.designs.id, file.designId));
214
+
215
+ if (await hasCollabState(file.id)) {
216
+ await applyText(file.id, content, "content", "agent");
217
+ } else {
218
+ await seedFromText(file.id, content);
219
+ }
220
+
221
+ return {
222
+ designId: file.designId,
223
+ fileId: file.id,
224
+ filename: file.filename,
225
+ inserted: true,
226
+ source: "figma",
227
+ fileKey: args.fileKey,
228
+ nodeId: args.nodeId ?? null,
229
+ componentKey: args.componentKey ?? null,
230
+ renderUrl: args.renderUrl,
231
+ };
232
+ },
233
+ });
@@ -68,15 +68,23 @@ const FIRST_PARTY_EXTENSIONS: FirstPartyDesignExtension[] = [
68
68
  id: "design.asset-library",
69
69
  name: "Asset Library",
70
70
  description:
71
- "Browse and insert generated or uploaded assets into the active design screen. " +
71
+ "Browse and insert Design-native primitives, generated or uploaded media, and rendered Figma library components into the active design screen. " +
72
72
  "Selection-aware: inserts near the selected element when one is active.",
73
73
  icon: "Photo",
74
74
  availability: "available",
75
- availabilityNote: "Fully available — call insert-asset with an asset URL.",
75
+ availabilityNote:
76
+ "Fully available — call list-design-native-assets then insert-design-native-asset for editable Design primitives, insert-asset for media, or list-figma-library-assets then insert-figma-library-asset for Figma components.",
76
77
  capabilities: [
77
78
  {
78
- id: "browse",
79
- label: "Browse asset library",
79
+ id: "native",
80
+ label: "Browse Design-native assets",
81
+ status: "available",
82
+ reason:
83
+ "Uses list-design-native-assets and insert-design-native-asset for editable HTML primitives/components.",
84
+ },
85
+ {
86
+ id: "media",
87
+ label: "Browse generated and uploaded media",
80
88
  status: "available",
81
89
  },
82
90
  {
@@ -93,8 +101,22 @@ const FIRST_PARTY_EXTENSIONS: FirstPartyDesignExtension[] = [
93
101
  reason:
94
102
  "Delegate to the Assets app via call-agent or the Assets MCP tool.",
95
103
  },
104
+ {
105
+ id: "figma",
106
+ label: "Browse Figma library assets",
107
+ status: "available",
108
+ reason:
109
+ "Uses FIGMA_ACCESS_TOKEN to list Figma file components/component sets and insert rendered nodes with provenance.",
110
+ },
111
+ ],
112
+ actions: [
113
+ "list-design-native-assets",
114
+ "insert-design-native-asset",
115
+ "insert-asset",
116
+ "list-figma-library-assets",
117
+ "insert-figma-library-asset",
118
+ "get-design-snapshot",
96
119
  ],
97
- actions: ["insert-asset", "get-design-snapshot"],
98
120
  slotId: "design.editor.inspector",
99
121
  },
100
122
 
@@ -212,12 +234,12 @@ const FIRST_PARTY_EXTENSIONS: FirstPartyDesignExtension[] = [
212
234
  description:
213
235
  "One-click animation presets (fade-in, slide-up, pulse, bounce, spin) that " +
214
236
  "apply to the selected node via the motion timeline. Preview is live; " +
215
- "Write to CSS commits the keyframes atomically.",
237
+ "track edits persist to managed CSS atomically.",
216
238
  icon: "PlayerPlay",
217
239
  availability: "available",
218
240
  availabilityNote:
219
- "Motion preview is available for all source types. Write to CSS (apply-motion-edit) " +
220
- "is atomic and available for inline + localhost. Source write-back to real CSS " +
241
+ "Motion preview is available for all source types. Managed CSS persistence " +
242
+ "(apply-motion-edit) is atomic and available for inline + localhost. Source write-back to real CSS " +
221
243
  "modules remains planned for the fusion tier.",
222
244
  capabilities: [
223
245
  {
@@ -229,7 +251,7 @@ const FIRST_PARTY_EXTENSIONS: FirstPartyDesignExtension[] = [
229
251
  },
230
252
  {
231
253
  id: "apply",
232
- label: "Write keyframes to CSS (apply-motion-edit)",
254
+ label: "Persist keyframes to managed CSS (apply-motion-edit)",
233
255
  status: "available",
234
256
  reason:
235
257
  "apply-motion-edit is atomic: persists timeline row + compiled CSS + " +
@@ -259,7 +281,7 @@ export default defineAction({
259
281
  List the first-party Design Studio extensions with their capability and availability status.
260
282
 
261
283
  Returns the four built-in extensions:
262
- 1. Asset Library — selection-aware asset insertion (available now).
284
+ 1. Asset Library — native components, media, and Figma imports (available now).
263
285
  2. Shader Fills — GPU shader fill previews (preview-only; apply is gated).
264
286
  3. Token Auditor — token usage reads + edits (available; source write-back planned).
265
287
  4. Motion Presets — one-click animation presets (available; source write-back planned).
@@ -0,0 +1,105 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+
4
+ export const DESIGN_NATIVE_ASSET_KINDS = [
5
+ "section-frame",
6
+ "text-block",
7
+ "button",
8
+ "card",
9
+ "input",
10
+ "nav-bar",
11
+ "hero",
12
+ "feature-grid",
13
+ ] as const;
14
+
15
+ export type DesignNativeAssetKind = (typeof DESIGN_NATIVE_ASSET_KINDS)[number];
16
+
17
+ type DesignNativeAsset = {
18
+ kind: DesignNativeAssetKind;
19
+ title: string;
20
+ description: string;
21
+ category: "primitive" | "component" | "layout";
22
+ componentName: string;
23
+ };
24
+
25
+ export const DESIGN_NATIVE_ASSETS: DesignNativeAsset[] = [
26
+ {
27
+ kind: "section-frame",
28
+ title: "Frame",
29
+ description:
30
+ "A flexible section container with padding and a subtle border.",
31
+ category: "primitive",
32
+ componentName: "Frame",
33
+ },
34
+ {
35
+ kind: "text-block",
36
+ title: "Text Block",
37
+ description: "Headline, supporting copy, and compact spacing.",
38
+ category: "primitive",
39
+ componentName: "TextBlock",
40
+ },
41
+ {
42
+ kind: "button",
43
+ title: "Button",
44
+ description: "Primary call-to-action with accessible focus styling.",
45
+ category: "component",
46
+ componentName: "Button",
47
+ },
48
+ {
49
+ kind: "card",
50
+ title: "Card",
51
+ description: "Reusable content card with title, body, and action row.",
52
+ category: "component",
53
+ componentName: "Card",
54
+ },
55
+ {
56
+ kind: "input",
57
+ title: "Input",
58
+ description: "Labeled input field with helper copy.",
59
+ category: "component",
60
+ componentName: "Input",
61
+ },
62
+ {
63
+ kind: "nav-bar",
64
+ title: "Nav Bar",
65
+ description: "Compact navigation row for app or page headers.",
66
+ category: "layout",
67
+ componentName: "NavBar",
68
+ },
69
+ {
70
+ kind: "hero",
71
+ title: "Hero",
72
+ description: "Product intro section with headline, copy, and action.",
73
+ category: "layout",
74
+ componentName: "Hero",
75
+ },
76
+ {
77
+ kind: "feature-grid",
78
+ title: "Feature Grid",
79
+ description: "Three-item feature layout for scanning and comparison.",
80
+ category: "layout",
81
+ componentName: "FeatureGrid",
82
+ },
83
+ ];
84
+
85
+ export default defineAction({
86
+ description:
87
+ "List Design-native reusable assets and primitives that can be inserted into the active design screen. These are not external media; they are editable HTML components stamped with Design component/layer metadata.",
88
+ schema: z.object({
89
+ category: z.enum(["primitive", "component", "layout"]).optional(),
90
+ }),
91
+ http: { method: "GET" },
92
+ readOnly: true,
93
+ publicAgent: { expose: true, readOnly: true, requiresAuth: true },
94
+ run: ({ category }) => {
95
+ const assets = category
96
+ ? DESIGN_NATIVE_ASSETS.filter((asset) => asset.category === category)
97
+ : DESIGN_NATIVE_ASSETS;
98
+ return {
99
+ source: "design-native",
100
+ assets,
101
+ guidance:
102
+ "Use insert-design-native-asset to add one of these assets to the active Design screen. They are editable Design-native HTML components, unlike external media or rendered Figma nodes.",
103
+ };
104
+ },
105
+ });