@agent-native/core 0.80.11 → 0.81.1

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 (230) 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/cli/design-connect.ts +419 -19
  5. package/corpus/core/src/client/AgentPanel.tsx +33 -1
  6. package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
  7. package/corpus/core/src/client/chat/index.ts +1 -0
  8. package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
  9. package/corpus/core/src/client/chat-view-transition.ts +33 -2
  10. package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
  11. package/corpus/core/src/client/index.ts +1 -0
  12. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
  13. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
  14. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
  15. package/corpus/core/src/db/client.ts +29 -2
  16. package/corpus/core/src/provider-api/index.ts +29 -0
  17. package/corpus/core/src/server/core-routes-plugin.ts +58 -20
  18. package/corpus/core/src/styles/agent-native.css +54 -0
  19. package/corpus/core/src/usage/store.ts +2 -2
  20. package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
  21. package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
  22. package/corpus/templates/analytics/app/global.css +8 -0
  23. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
  24. package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
  25. package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
  26. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
  27. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
  28. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
  29. package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
  34. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
  35. package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
  36. package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
  37. package/corpus/templates/assets/app/global.css +15 -0
  38. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
  39. package/corpus/templates/assets/app/routes/library.tsx +90 -16
  40. package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
  41. package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
  42. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
  43. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
  44. package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
  45. package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
  46. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  47. package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
  48. package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
  49. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
  50. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
  51. package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
  52. package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
  53. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
  54. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
  55. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
  56. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
  57. package/corpus/templates/design/AGENTS.md +27 -0
  58. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
  59. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
  60. package/corpus/templates/design/actions/apply-component-prop-edit.ts +63 -20
  61. package/corpus/templates/design/actions/apply-motion-edit.ts +67 -69
  62. package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
  63. package/corpus/templates/design/actions/capture-design-state.ts +27 -4
  64. package/corpus/templates/design/actions/connect-localhost.ts +59 -22
  65. package/corpus/templates/design/actions/export-zip.ts +23 -8
  66. package/corpus/templates/design/actions/generate-design.ts +53 -1
  67. package/corpus/templates/design/actions/get-component-details.ts +5 -19
  68. package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
  69. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
  70. package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
  71. package/corpus/templates/design/actions/index-design-tokens.ts +10 -1
  72. package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
  73. package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
  74. package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
  75. package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
  76. package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
  77. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
  78. package/corpus/templates/design/actions/navigate.ts +18 -3
  79. package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
  80. package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
  81. package/corpus/templates/design/actions/provider-api-request.ts +3 -3
  82. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
  83. package/corpus/templates/design/actions/run-design-audit.ts +53 -4
  84. package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
  85. package/corpus/templates/design/actions/view-screen.ts +1 -1
  86. package/corpus/templates/design/actions/write-local-file.ts +213 -0
  87. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +230 -3308
  88. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
  89. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +776 -287
  90. package/corpus/templates/design/app/components/design/EditPanel.tsx +212 -208
  91. package/corpus/templates/design/app/components/design/LayersPanel.tsx +14 -2
  92. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
  93. package/corpus/templates/design/app/components/design/MotionDock.tsx +235 -266
  94. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +490 -55
  95. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +43 -62
  96. package/corpus/templates/design/app/components/design/StatesPanel.tsx +34 -61
  97. package/corpus/templates/design/app/components/design/TokensPanel.tsx +251 -0
  98. package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
  99. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
  100. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
  101. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
  102. package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
  103. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
  104. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
  105. package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
  106. package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
  107. package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
  108. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
  109. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
  110. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
  111. package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
  112. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  113. package/corpus/templates/design/app/global.css +7 -0
  114. package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
  115. package/corpus/templates/design/app/i18n/zh-TW.ts +21 -0
  116. package/corpus/templates/design/app/i18n-data.ts +358 -0
  117. package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
  118. package/corpus/templates/design/app/pages/DesignEditor.tsx +2402 -499
  119. package/corpus/templates/design/app/pages/Index.tsx +5 -1
  120. package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
  121. package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
  122. package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
  123. package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
  124. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
  125. package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
  126. package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
  127. package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
  128. package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
  129. package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
  130. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
  131. package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
  132. package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
  133. package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
  134. package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
  135. package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
  136. package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
  137. package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
  138. package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
  139. package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
  140. package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
  141. package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
  142. package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
  144. package/corpus/templates/design/e2e/helpers.ts +168 -65
  145. package/corpus/templates/design/package.json +3 -1
  146. package/corpus/templates/design/server/db/schema.ts +23 -0
  147. package/corpus/templates/design/server/handlers/uploads.ts +22 -1
  148. package/corpus/templates/design/server/lib/provider-api.ts +7 -4
  149. package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
  150. package/corpus/templates/design/server/plugins/db.ts +39 -0
  151. package/corpus/templates/design/server/register-secrets.ts +38 -0
  152. package/corpus/templates/design/shared/board-file.ts +228 -0
  153. package/corpus/templates/design/shared/board-objects.ts +288 -0
  154. package/corpus/templates/design/shared/code-layer.ts +52 -0
  155. package/corpus/templates/design/shared/motion-compiler.ts +58 -7
  156. package/corpus/templates/design/shared/motion-timeline.ts +2 -2
  157. package/corpus/templates/design/tsconfig.json +2 -1
  158. package/corpus/templates/slides/AGENTS.md +9 -0
  159. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
  160. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
  161. package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
  162. package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
  163. package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
  164. package/corpus/templates/slides/app/vite-env.d.ts +18 -0
  165. package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
  166. package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
  167. package/corpus/templates/slides/package.json +1 -0
  168. package/corpus/templates/slides/vite.config.ts +1 -0
  169. package/dist/cli/design-connect.d.ts +25 -0
  170. package/dist/cli/design-connect.d.ts.map +1 -1
  171. package/dist/cli/design-connect.js +357 -18
  172. package/dist/cli/design-connect.js.map +1 -1
  173. package/dist/client/AgentPanel.d.ts +1 -1
  174. package/dist/client/AgentPanel.d.ts.map +1 -1
  175. package/dist/client/AgentPanel.js +18 -3
  176. package/dist/client/AgentPanel.js.map +1 -1
  177. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  178. package/dist/client/ConnectBuilderCard.js +1 -0
  179. package/dist/client/ConnectBuilderCard.js.map +1 -1
  180. package/dist/client/chat/index.d.ts +1 -1
  181. package/dist/client/chat/index.d.ts.map +1 -1
  182. package/dist/client/chat/index.js +1 -1
  183. package/dist/client/chat/index.js.map +1 -1
  184. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  185. package/dist/client/chat/run-recovery.js +5 -5
  186. package/dist/client/chat/run-recovery.js.map +1 -1
  187. package/dist/client/chat-view-transition.d.ts +6 -0
  188. package/dist/client/chat-view-transition.d.ts.map +1 -1
  189. package/dist/client/chat-view-transition.js +23 -2
  190. package/dist/client/chat-view-transition.js.map +1 -1
  191. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  192. package/dist/client/composer/PromptComposer.js +3 -2
  193. package/dist/client/composer/PromptComposer.js.map +1 -1
  194. package/dist/client/index.d.ts +1 -1
  195. package/dist/client/index.d.ts.map +1 -1
  196. package/dist/client/index.js +1 -1
  197. package/dist/client/index.js.map +1 -1
  198. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  199. package/dist/client/org/OrgSwitcher.js +11 -4
  200. package/dist/client/org/OrgSwitcher.js.map +1 -1
  201. package/dist/client/sharing/ShareButton.js +3 -3
  202. package/dist/client/sharing/ShareButton.js.map +1 -1
  203. package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
  204. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  205. package/dist/client/use-agent-chat-home-handoff.js +20 -6
  206. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  207. package/dist/collab/routes.d.ts +1 -1
  208. package/dist/db/client.d.ts +1 -0
  209. package/dist/db/client.d.ts.map +1 -1
  210. package/dist/db/client.js +28 -2
  211. package/dist/db/client.js.map +1 -1
  212. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  213. package/dist/notifications/routes.d.ts +2 -2
  214. package/dist/observability/routes.d.ts +8 -8
  215. package/dist/progress/routes.d.ts +1 -1
  216. package/dist/provider-api/index.d.ts +5 -4
  217. package/dist/provider-api/index.d.ts.map +1 -1
  218. package/dist/provider-api/index.js +28 -0
  219. package/dist/provider-api/index.js.map +1 -1
  220. package/dist/resources/handlers.d.ts +3 -3
  221. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  222. package/dist/server/core-routes-plugin.d.ts +25 -0
  223. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  224. package/dist/server/core-routes-plugin.js +43 -18
  225. package/dist/server/core-routes-plugin.js.map +1 -1
  226. package/dist/server/transcribe-voice.d.ts +1 -1
  227. package/dist/styles/agent-native.css +54 -0
  228. package/dist/usage/store.js +2 -2
  229. package/dist/usage/store.js.map +1 -1
  230. package/package.json +1 -1
@@ -14,7 +14,6 @@
14
14
  */
15
15
 
16
16
  import {
17
- listAppState,
18
17
  readAppState,
19
18
  writeAppState,
20
19
  } from "@agent-native/core/application-state";
@@ -36,6 +35,7 @@ import {
36
35
  import finalizeRecording from "../../../../../actions/finalize-recording.js";
37
36
  import { getDb, schema } from "../../../../db/index.js";
38
37
  import { debugLog } from "../../../../lib/debug.js";
38
+ import { sumRecordingChunkBytes } from "../../../../lib/recording-upload-state.js";
39
39
  import {
40
40
  getEventOwnerContext,
41
41
  ownerEmailMatches,
@@ -82,14 +82,6 @@ function stateNumber(
82
82
  return typeof raw === "number" && Number.isFinite(raw) ? raw : undefined;
83
83
  }
84
84
 
85
- async function sumPersistedChunkBytes(recordingId: string): Promise<number> {
86
- const chunks = await listAppState(`recording-chunks-${recordingId}-`);
87
- return chunks.reduce(
88
- (total, entry) => total + (stateNumber(entry.value, "bytes") ?? 0),
89
- 0,
90
- );
91
- }
92
-
93
85
  export default defineEventHandler(async (event: H3Event) => {
94
86
  const recordingId = getRouterParam(event, "recordingId");
95
87
  if (!recordingId) {
@@ -278,7 +270,7 @@ export default defineEventHandler(async (event: H3Event) => {
278
270
  recordingId,
279
271
  status: "failed",
280
272
  failureReason: reason,
281
- bytesReceived: await sumPersistedChunkBytes(recordingId),
273
+ bytesReceived: await sumRecordingChunkBytes(ownerEmail, recordingId),
282
274
  maxBytes: MAX_RECORDING_UPLOAD_BYTES,
283
275
  updatedAt: new Date().toISOString(),
284
276
  });
@@ -323,7 +315,10 @@ export default defineEventHandler(async (event: H3Event) => {
323
315
  const chunkKey = `recording-chunks-${recordingId}-${paddedIndex}`;
324
316
  const previousChunk = await readAppState(chunkKey);
325
317
  const previousBytes = stateNumber(previousChunk, "bytes") ?? 0;
326
- const persistedBytesBefore = await sumPersistedChunkBytes(recordingId);
318
+ const persistedBytesBefore = await sumRecordingChunkBytes(
319
+ ownerEmail,
320
+ recordingId,
321
+ );
327
322
  const nextBytes =
328
323
  Math.max(0, persistedBytesBefore - previousBytes) + bytes.byteLength;
329
324
 
@@ -339,7 +334,7 @@ export default defineEventHandler(async (event: H3Event) => {
339
334
  data: toBase64(bytes),
340
335
  createdAt: new Date().toISOString(),
341
336
  });
342
- bytesReceived = await sumPersistedChunkBytes(recordingId);
337
+ bytesReceived = await sumRecordingChunkBytes(ownerEmail, recordingId);
343
338
  if (bytesReceived > MAX_RECORDING_UPLOAD_BYTES) {
344
339
  return failRecordingTooLarge(bytesReceived);
345
340
  }
@@ -396,7 +391,7 @@ export default defineEventHandler(async (event: H3Event) => {
396
391
  // Final chunk — kick off finalize. We await so the client gets a single
397
392
  // "done" response with the final URL (instead of needing to poll).
398
393
  if (isFinal) {
399
- bytesReceived = await sumPersistedChunkBytes(recordingId);
394
+ bytesReceived = await sumRecordingChunkBytes(ownerEmail, recordingId);
400
395
  if (bytesReceived > MAX_RECORDING_UPLOAD_BYTES) {
401
396
  return failRecordingTooLarge(bytesReceived);
402
397
  }
@@ -437,6 +432,61 @@ export default defineEventHandler(async (event: H3Event) => {
437
432
  };
438
433
  } catch (err) {
439
434
  console.error("[clips] finalize-recording failed:", err);
435
+ const [committed] = await db
436
+ .select({
437
+ id: schema.recordings.id,
438
+ status: schema.recordings.status,
439
+ videoUrl: schema.recordings.videoUrl,
440
+ durationMs: schema.recordings.durationMs,
441
+ width: schema.recordings.width,
442
+ height: schema.recordings.height,
443
+ hasAudio: schema.recordings.hasAudio,
444
+ hasCamera: schema.recordings.hasCamera,
445
+ })
446
+ .from(schema.recordings)
447
+ .where(
448
+ and(
449
+ eq(schema.recordings.id, recordingId),
450
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
451
+ ),
452
+ );
453
+ if (committed?.status === "ready" && committed.videoUrl) {
454
+ console.warn(
455
+ "[clips] finalize reported an error after committing a ready recording; returning committed success.",
456
+ {
457
+ recordingId,
458
+ error: err instanceof Error ? err.message : String(err),
459
+ },
460
+ );
461
+ try {
462
+ await writeAppState(`recording-upload-${recordingId}`, {
463
+ recordingId,
464
+ status: "ready",
465
+ progress: 100,
466
+ videoUrl: committed.videoUrl,
467
+ finishedAt: new Date().toISOString(),
468
+ });
469
+ } catch (stateErr) {
470
+ console.warn("[clips] committed-ready state repair failed:", {
471
+ recordingId,
472
+ err:
473
+ stateErr instanceof Error ? stateErr.message : String(stateErr),
474
+ });
475
+ }
476
+ return {
477
+ ok: true,
478
+ finalized: true,
479
+ recoveredAfterFinalizeError: true,
480
+ id: committed.id,
481
+ status: "ready",
482
+ videoUrl: committed.videoUrl,
483
+ durationMs: committed.durationMs,
484
+ width: committed.width,
485
+ height: committed.height,
486
+ hasAudio: committed.hasAudio,
487
+ hasCamera: committed.hasCamera,
488
+ };
489
+ }
440
490
  await db
441
491
  .update(schema.recordings)
442
492
  .set({
@@ -0,0 +1,74 @@
1
+ import { runWithRequestContext } from "@agent-native/core/server";
2
+ import { and, eq } from "drizzle-orm";
3
+ import {
4
+ createError,
5
+ defineEventHandler,
6
+ getRouterParam,
7
+ setResponseStatus,
8
+ type H3Event,
9
+ } from "h3";
10
+
11
+ import { getDb, schema } from "../../../../db/index.js";
12
+ import { resolvePlayerVideoUrl } from "../../../../lib/player-video-url.js";
13
+ import {
14
+ getEventOwnerContext,
15
+ ownerEmailMatches,
16
+ } from "../../../../lib/recordings.js";
17
+
18
+ function appPath(path: string): string {
19
+ if (!path.startsWith("/")) return path;
20
+ const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || "";
21
+ const base = raw.trim().replace(/^\/+/, "").replace(/\/+$/, "");
22
+ return base ? `/${base}${path}` : path;
23
+ }
24
+
25
+ export default defineEventHandler(async (event: H3Event) => {
26
+ const recordingId = getRouterParam(event, "recordingId");
27
+ if (!recordingId) {
28
+ throw createError({ statusCode: 400, message: "Missing recordingId" });
29
+ }
30
+
31
+ let ownerEmail: string;
32
+ let orgId: string | undefined;
33
+ try {
34
+ const context = await getEventOwnerContext(event);
35
+ ownerEmail = context.userEmail;
36
+ orgId = context.orgId;
37
+ } catch {
38
+ throw createError({ statusCode: 401, message: "Unauthorized" });
39
+ }
40
+
41
+ return runWithRequestContext({ userEmail: ownerEmail, orgId }, async () => {
42
+ const [recording] = await getDb()
43
+ .select()
44
+ .from(schema.recordings)
45
+ .where(
46
+ and(
47
+ eq(schema.recordings.id, recordingId),
48
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
49
+ ),
50
+ )
51
+ .limit(1);
52
+
53
+ if (!recording) {
54
+ setResponseStatus(event, 404);
55
+ return { error: "Not found" };
56
+ }
57
+
58
+ return {
59
+ recording: {
60
+ id: recording.id,
61
+ status: recording.status,
62
+ videoUrl: resolvePlayerVideoUrl(recording, { appPath }),
63
+ durationMs: recording.durationMs,
64
+ width: recording.width,
65
+ height: recording.height,
66
+ hasAudio: Boolean(recording.hasAudio),
67
+ hasCamera: Boolean(recording.hasCamera),
68
+ uploadProgress: recording.uploadProgress,
69
+ failureReason: recording.failureReason,
70
+ updatedAt: recording.updatedAt,
71
+ },
72
+ };
73
+ });
74
+ });
@@ -166,6 +166,24 @@ pnpm action index-design-system-with-builder --codeFiles '[{"filename":"globals.
166
166
 
167
167
  Uploads code/design files to Builder and starts design-system indexing. Do not create a local design system from uploaded code files unless the user explicitly asks for a manual local fallback.
168
168
 
169
+ For the active design's Tokens panel, use `import-design-tokens` when the user
170
+ wants to pull reusable CSS vars/tokens straight into the open design without
171
+ creating a full design system:
172
+
173
+ ```bash
174
+ pnpm action import-design-tokens \
175
+ --designId "design_123" \
176
+ --source files \
177
+ --files '[{"filename":"design.md","content":"Primary color: #2563eb"}]'
178
+ ```
179
+
180
+ Supported sources are `files`, `paste`, and `current-design`. The action parses
181
+ CSS variables, design.md-style labeled lines, Tailwind/theme JSON, colors,
182
+ spacing, radii, and fonts, then persists them through the design's
183
+ `tweakSelections` so the canvas updates like any other token edit. Treat manual
184
+ `apply-design-token-edit` calls as a last-resort one-off edit after import has
185
+ been tried or ruled out.
186
+
169
187
  ### Source: Documents (DOCX, PPTX, PDF)
170
188
 
171
189
  ```bash
@@ -204,6 +222,20 @@ indexing through the setup page upload route. Do not parse `.fig` files locally
204
222
  and do not call `create-design-system` from raw `.fig` output; Builder owns the
205
223
  indexed brand kit, generated docs, and usage guidance.
206
224
 
225
+ **When the user wants a Figma Assets-style native component drawer inside
226
+ Design**, do not use Figma or media assets. Use `list-design-native-assets` to
227
+ choose an editable primitive/component/layout, then
228
+ `insert-design-native-asset` to insert it into the active screen. These entries
229
+ are Design-native HTML stamped with component/layer metadata.
230
+
231
+ **When the user wants reusable Figma components/assets**, do not run
232
+ design-system indexing just to insert a component. Use
233
+ `list-figma-library-assets` with a Figma file URL/key, then
234
+ `insert-figma-library-asset` with the returned `renderUrl`, `fileKey`,
235
+ `nodeId`, `componentKey`, and `sourceUrl`. This inserts a rendered
236
+ component/component set with provenance. Styles and variables still belong in
237
+ the Builder-backed design-system path above.
238
+
207
239
  ### Source: Brand Analysis (combines website + notes)
208
240
 
209
241
  ```bash
@@ -32,6 +32,11 @@ patterns live in `.agents/skills/`.
32
32
  per direction; avoid lorem ipsum, generic SaaS filler, and decorative
33
33
  placeholders. Include expected responsive/accessibility states and visually
34
34
  inspect the result before calling it ready.
35
+ - For editable reusable building blocks inside Design, use
36
+ `list-design-native-assets` first, then `insert-design-native-asset` with the
37
+ chosen kind. These are Design-native HTML primitives/components, not external
38
+ media, so prefer them when the user asks for a Figma Assets-style library that
39
+ supports our own primitives.
35
40
  - For raster image generation, restyling, or editing existing screenshots/photos,
36
41
  use the available first-party Assets MCP tool such as `generate-asset` instead
37
42
  of placeholders or generic stock imagery. When the Assets picker returns a
@@ -43,6 +48,15 @@ patterns live in `.agents/skills/`.
43
48
  chat-attachment URL or call `upload-image` to create one before delegating. If
44
49
  no image/upload provider is configured, say that specific setup is needed and
45
50
  continue any non-image Design work separately.
51
+ - For reusable Figma library components, use `list-figma-library-assets` with a
52
+ Figma file URL or file key. It returns components/component sets with
53
+ thumbnails, rendered insert URLs, and Figma provenance. Insert with
54
+ `insert-figma-library-asset`, preserving `fileKey`, `nodeId`, `componentKey`,
55
+ `sourceUrl`, and the rendered URL. This path requires the saved
56
+ `FIGMA_ACCESS_TOKEN` secret; never ask the user to paste that token into chat
57
+ or pass it as an action parameter. Figma styles and variables are design-system
58
+ inputs, not draggable media assets; route full file/design-system extraction
59
+ through Builder-backed indexing.
46
60
  - Use Alpine.js and Tailwind CDN for interactive prototypes. Prefer Alpine
47
61
  directives over raw inline event handlers.
48
62
  - Navigate between prototype screens with Alpine state (`x-show`), a
@@ -72,6 +86,13 @@ patterns live in `.agents/skills/`.
72
86
  `inspectorTab: "extensions"` after installing it.
73
87
  - Follow linked design-system tokens and `customInstructions` whenever present;
74
88
  explicit user instructions in the current turn still win.
89
+ - When a user wants tokens from design.md, CSS, theme/tokens JSON, Tailwind
90
+ config, local files, or the current design, call `import-design-tokens` and
91
+ preserve its `tokens`, `filesAnalyzed`, and provenance in your answer. Manual
92
+ `apply-design-token-edit` / one-by-one token entry is the fallback for a small
93
+ one-off token, not the primary import workflow. For Figma variables/styles or
94
+ raw `.fig` files, keep using Builder-backed design-system indexing instead of
95
+ local `.fig` parsing.
75
96
  - Persist useful work early: create/update the design and files as soon as a
76
97
  coherent candidate exists, then iterate.
77
98
  - For non-trivial new design prompts, ask before generating: create/open the
@@ -104,6 +125,12 @@ patterns live in `.agents/skills/`.
104
125
  generated CSS selectors as a compatibility fallback only. For localhost React
105
126
  screens, resolve through build-time source/debug metadata (stable generated
106
127
  ids, component name, file, and line) before falling back to selectors.
128
+ - For inline/Alpine motion, use `get-motion-timeline` to inspect the active
129
+ file's saved or CSS-recovered timeline, then call `apply-motion-edit` with the
130
+ same `sourceRef`/`fileId` to update it. Motion edits persist as durable
131
+ managed keyframes in `<style data-agent-native-motion>` plus editable timeline
132
+ metadata; it is not a one-way export. Real CSS module or `motion/react`
133
+ write-back remains a localhost/fusion follow-up capability.
107
134
  - For multi-variant work, use `present-design-variants` so every candidate is
108
135
  saved as a normal overview-board screen and the user gets one inline chat
109
136
  button per screen name. After the user picks, delete the unchosen variant
@@ -396,7 +396,7 @@ Requirements:
396
396
  - diamond keyframes
397
397
  - play/scrub controls
398
398
  - auto-keyframe control
399
- - primary `Write to CSS` action
399
+ - autosave status for managed CSS persistence
400
400
  - compact Motion/Keyframe inspector section
401
401
  - no separate motion app/screen
402
402
 
@@ -347,7 +347,7 @@ The CSS is the runtime truth; the JSON `tracks` only aid editing.
347
347
 
348
348
  - **UI (matches the motion artboard):** a full-width, collapsible **Motion dock**
349
349
  at the bottom of `DesignEditor.tsx` (animated layer rows, property tracks, time
350
- ruler, diamond keyframes, play/scrub, auto-keyframe toggle, **Write to CSS**),
350
+ ruler, diamond keyframes, play/scrub, auto-keyframe toggle, autosave status),
351
351
  with the canvas still visible above; a compact **Motion section** in the
352
352
  inspector for the selected keyframe (numeric + easing + transform/opacity).
353
353
  - **Preview:** scrubbing sends preview-only bridge messages (`motion-preview` /
@@ -360,8 +360,8 @@ The CSS is the runtime truth; the JSON `tracks` only aid editing.
360
360
  **Real-app superset:** write keyframes into real CSS modules, optional
361
361
  `motion`-react round-trip, Dev Mode export.
362
362
 
363
- **Acceptance:** scrubbing never writes; **Write to CSS** is one atomic action with
364
- diff/rollback proof; multiple layers and tracks animate.
363
+ **Acceptance:** scrubbing never writes; timeline edits autosave through one atomic
364
+ action with diff/rollback proof; multiple layers and tracks animate.
365
365
 
366
366
  ### 6.4 States, responsive & captures
367
367
 
@@ -615,7 +615,7 @@ motion edits safely, use review outputs, and offer Builder migration CTAs.
615
615
  runtime + source-write + fallback + diff proof.
616
616
 
617
617
  **First user-visible milestone:** on an inline design, edit a token (live, persisted)
618
- and add a keyframe animation that **Write to CSS** commits with a visible diff —
618
+ and add a keyframe animation that autosaves to managed CSS with a visible diff —
619
619
  "visual edit becomes persisted code/CSS" without the whole real-app stack.
620
620
 
621
621
  ---
@@ -659,7 +659,7 @@ and add a keyframe animation that **Write to CSS** commits with a visible diff
659
659
  (Mobile) is untouched; the Desktop frame reflects the cascade; reset-to-base clears
660
660
  the override; the same flow works on an inline design and a real-app URL.
661
661
  - **Alpine smoke:** edit layout/styles; preview + persist a CSS-var token change;
662
- add simple keyframes and Write to CSS; run a basic a11y scan; see the real-app CTA
662
+ add simple keyframes that autosave to managed CSS; run a basic a11y scan; see the real-app CTA
663
663
  for full component controls.
664
664
 
665
665
  ---
@@ -25,7 +25,6 @@ import {
25
25
  agentLeaveDocument,
26
26
  agentUpdateSelection,
27
27
  applyText,
28
- getText,
29
28
  hasCollabState,
30
29
  seedFromText,
31
30
  } from "@agent-native/core/collab";
@@ -117,26 +116,11 @@ export function applyRootAttributeEdit(
117
116
  };
118
117
  }
119
118
 
120
- async function liveContent(
121
- fileId: string,
122
- storedContent: string,
123
- ): Promise<string> {
124
- try {
125
- if (await hasCollabState(fileId)) {
126
- const live = await getText(fileId, "content");
127
- if (typeof live === "string") return live;
128
- }
129
- } catch {
130
- // Collab reads are best-effort; SQL content is the fallback.
131
- }
132
- return storedContent;
133
- }
134
-
135
119
  async function persistEdit(file: {
136
120
  id: string;
137
121
  designId: string;
138
122
  content: string;
139
- }): Promise<void> {
123
+ }): Promise<string> {
140
124
  await assertAccess("design", file.designId, "editor");
141
125
  const db = getDb();
142
126
  const now = new Date().toISOString();
@@ -161,6 +145,8 @@ async function persistEdit(file: {
161
145
  } finally {
162
146
  agentLeaveDocument(file.id);
163
147
  }
148
+
149
+ return now;
164
150
  }
165
151
 
166
152
  // ─── Action ───────────────────────────────────────────────────────────────────
@@ -213,8 +199,24 @@ export default defineAction({
213
199
  }),
214
200
  ])
215
201
  .describe("The prop edit to apply"),
202
+ source: z
203
+ .object({
204
+ currentContent: z
205
+ .string()
206
+ .optional()
207
+ .describe(
208
+ "Latest editor HTML snapshot. Used to compose rapid sequential prop edits before collab persistence catches up.",
209
+ ),
210
+ revision: z
211
+ .string()
212
+ .optional()
213
+ .describe(
214
+ "design_files.updatedAt value the currentContent is based on.",
215
+ ),
216
+ })
217
+ .optional(),
216
218
  }),
217
- run: async ({ designId, nodeId, fileId, edit }) => {
219
+ run: async ({ designId, nodeId, fileId, edit, source }) => {
218
220
  const db = getDb();
219
221
 
220
222
  // ── Access check ────────────────────────────────────────────────────────
@@ -274,6 +276,7 @@ export default defineAction({
274
276
  designId: schema.designFiles.designId,
275
277
  filename: schema.designFiles.filename,
276
278
  content: schema.designFiles.content,
279
+ updatedAt: schema.designFiles.updatedAt,
277
280
  })
278
281
  .from(schema.designFiles)
279
282
  .innerJoin(
@@ -285,7 +288,31 @@ export default defineAction({
285
288
 
286
289
  if (!file) throw new Error("Design HTML file not found.");
287
290
 
288
- const html = await liveContent(file.id, file.content ?? "");
291
+ if (
292
+ source?.currentContent &&
293
+ source.revision &&
294
+ file.updatedAt &&
295
+ source.revision !== file.updatedAt
296
+ ) {
297
+ return {
298
+ designId,
299
+ nodeId,
300
+ persisted: false,
301
+ conflict: true,
302
+ fileId: file.id,
303
+ filename: file.filename,
304
+ error:
305
+ "This file changed since this component prop edit was prepared. Refresh the editor and try again.",
306
+ };
307
+ }
308
+
309
+ // Prefer explicit editor content after the caller's revision check, and use
310
+ // the saved SQL content as the fallback. Collab/Yjs reads can be stale
311
+ // across local dev worker processes and make prop controls lag behind.
312
+ const html =
313
+ typeof source?.currentContent === "string"
314
+ ? source.currentContent
315
+ : (file.content ?? "");
289
316
 
290
317
  // ── Resolve node ─────────────────────────────────────────────────────────
291
318
  const codeLayerSource: CodeLayerSource = {
@@ -406,7 +433,7 @@ export default defineAction({
406
433
  const shouldPersist = changed || patchedContent !== (file.content ?? "");
407
434
 
408
435
  if (shouldPersist) {
409
- await persistEdit({
436
+ const updatedAt = await persistEdit({
410
437
  id: file.id,
411
438
  designId: file.designId,
412
439
  content: patchedContent,
@@ -418,6 +445,22 @@ export default defineAction({
418
445
  editingFile: file.filename,
419
446
  designId: file.designId,
420
447
  });
448
+ return {
449
+ designId,
450
+ nodeId,
451
+ componentName,
452
+ sourceType,
453
+ editKind: edit.kind,
454
+ persisted: shouldPersist,
455
+ ctaRequired: false,
456
+ fileId: file.id,
457
+ filename: file.filename,
458
+ updatedAt,
459
+ content: patchedContent,
460
+ bytesBefore: html.length,
461
+ bytesAfter: patchedContent.length,
462
+ note: "Edit applied and persisted via the deterministic HTML-patch path.",
463
+ };
421
464
  }
422
465
 
423
466
  return {