@agent-native/core 0.80.0 → 0.80.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 (220) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
  5. package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
  7. package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
  9. package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
  11. package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  12. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
  13. package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  14. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
  15. package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  16. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
  17. package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  18. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
  19. package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  20. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
  21. package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  22. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
  23. package/corpus/core/docs/content/skills-guide.mdx +5 -0
  24. package/corpus/core/docs/content/template-design.mdx +14 -1
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/application-state/handlers.ts +1 -1
  27. package/corpus/core/src/brand-kit/index.ts +1 -1
  28. package/corpus/core/src/cli/skills.ts +18 -0
  29. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  30. package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
  31. package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
  32. package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
  33. package/corpus/core/src/extensions/path.ts +1 -4
  34. package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
  35. package/corpus/core/src/mcp/build-server.ts +1 -1
  36. package/corpus/core/src/org/handlers.ts +5 -5
  37. package/corpus/core/src/org/plugin.ts +2 -2
  38. package/corpus/core/src/scripts/call-agent.ts +1 -1
  39. package/corpus/core/src/scripts/db/safety.ts +1 -1
  40. package/corpus/core/src/server/auth.ts +3 -0
  41. package/corpus/core/src/server/builder-design-systems.ts +308 -0
  42. package/corpus/core/src/server/core-routes-plugin.ts +29 -3
  43. package/corpus/core/src/server/index.ts +8 -0
  44. package/corpus/core/src/styles/agent-native.css +14 -7
  45. package/corpus/core/src/usage/store.ts +2 -2
  46. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
  47. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
  48. package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
  49. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
  50. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
  51. package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
  52. package/corpus/templates/analytics/app/i18n-data.ts +404 -0
  53. package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
  54. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
  56. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
  57. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
  58. package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
  59. package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
  62. package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
  63. package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
  65. package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
  67. package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
  68. package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
  69. package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
  70. package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
  71. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
  72. package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
  73. package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
  74. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
  75. package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
  76. package/corpus/templates/content/shared/document-export.ts +1 -1
  77. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
  78. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
  79. package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
  80. package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
  81. package/corpus/templates/design/actions/update-file.ts +9 -2
  82. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
  83. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
  84. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
  85. package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
  86. package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
  87. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
  88. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
  89. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
  90. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
  91. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
  92. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
  93. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
  94. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
  95. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
  96. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
  97. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
  98. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
  99. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
  100. package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
  101. package/corpus/templates/design/app/global.css +29 -3
  102. package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
  103. package/corpus/templates/design/app/i18n-data.ts +239 -1
  104. package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
  105. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
  106. package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
  107. package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
  108. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
  109. package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
  110. package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
  111. package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
  112. package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
  113. package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
  114. package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
  115. package/corpus/templates/design/shared/code-layer.ts +209 -9
  116. package/corpus/templates/design/shared/html-content.ts +21 -0
  117. package/corpus/templates/design/shared/pen-path.ts +207 -0
  118. package/corpus/templates/mail/app/lib/utils.ts +2 -2
  119. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
  120. package/corpus/templates/slides/AGENTS.md +3 -2
  121. package/corpus/templates/slides/actions/import-file.ts +26 -17
  122. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
  123. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
  124. package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
  125. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
  126. package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
  127. package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
  128. package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
  129. package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
  130. package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
  131. package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
  132. package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
  133. package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
  134. package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
  135. package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
  136. package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
  137. package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
  138. package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
  139. package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
  140. package/dist/application-state/handlers.js +1 -1
  141. package/dist/application-state/handlers.js.map +1 -1
  142. package/dist/brand-kit/index.d.ts +1 -1
  143. package/dist/brand-kit/index.js +1 -1
  144. package/dist/brand-kit/index.js.map +1 -1
  145. package/dist/cli/skills.d.ts.map +1 -1
  146. package/dist/cli/skills.js +18 -0
  147. package/dist/cli/skills.js.map +1 -1
  148. package/dist/client/AgentPanel.js +1 -1
  149. package/dist/client/AgentPanel.js.map +1 -1
  150. package/dist/client/MultiTabAssistantChat.js +1 -1
  151. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  152. package/dist/client/extensions/portable-extension.d.ts +1 -1
  153. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  154. package/dist/client/extensions/portable-extension.js.map +1 -1
  155. package/dist/code-agents/transcript-normalizer.js +1 -1
  156. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  157. package/dist/collab/awareness.d.ts +2 -2
  158. package/dist/collab/awareness.d.ts.map +1 -1
  159. package/dist/extensions/path.d.ts +1 -1
  160. package/dist/extensions/path.d.ts.map +1 -1
  161. package/dist/extensions/path.js.map +1 -1
  162. package/dist/integrations/a2a-continuation-processor.js +1 -1
  163. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  164. package/dist/mcp/build-server.d.ts +1 -1
  165. package/dist/mcp/build-server.d.ts.map +1 -1
  166. package/dist/mcp/build-server.js.map +1 -1
  167. package/dist/observability/routes.d.ts +3 -3
  168. package/dist/org/handlers.js +5 -5
  169. package/dist/org/handlers.js.map +1 -1
  170. package/dist/org/plugin.js +2 -2
  171. package/dist/org/plugin.js.map +1 -1
  172. package/dist/progress/routes.d.ts +1 -1
  173. package/dist/scripts/call-agent.js +1 -1
  174. package/dist/scripts/call-agent.js.map +1 -1
  175. package/dist/scripts/db/safety.js +1 -1
  176. package/dist/scripts/db/safety.js.map +1 -1
  177. package/dist/server/auth.d.ts.map +1 -1
  178. package/dist/server/auth.js +3 -0
  179. package/dist/server/auth.js.map +1 -1
  180. package/dist/server/builder-design-systems.d.ts +28 -0
  181. package/dist/server/builder-design-systems.d.ts.map +1 -0
  182. package/dist/server/builder-design-systems.js +217 -0
  183. package/dist/server/builder-design-systems.js.map +1 -0
  184. package/dist/server/core-routes-plugin.d.ts +1 -0
  185. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  186. package/dist/server/core-routes-plugin.js +20 -3
  187. package/dist/server/core-routes-plugin.js.map +1 -1
  188. package/dist/server/index.d.ts +1 -0
  189. package/dist/server/index.d.ts.map +1 -1
  190. package/dist/server/index.js +1 -0
  191. package/dist/server/index.js.map +1 -1
  192. package/dist/server/transcribe-voice.d.ts +1 -1
  193. package/dist/styles/agent-native.css +14 -7
  194. package/dist/usage/store.js +2 -2
  195. package/dist/usage/store.js.map +1 -1
  196. package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
  197. package/docs/content/locales/ar-SA/template-design.mdx +14 -1
  198. package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
  199. package/docs/content/locales/de-DE/template-design.mdx +15 -1
  200. package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
  201. package/docs/content/locales/es-ES/template-design.mdx +15 -1
  202. package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
  203. package/docs/content/locales/fr-FR/template-design.mdx +15 -1
  204. package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
  205. package/docs/content/locales/hi-IN/template-design.mdx +15 -1
  206. package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
  207. package/docs/content/locales/ja-JP/template-design.mdx +16 -1
  208. package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
  209. package/docs/content/locales/ko-KR/template-design.mdx +14 -1
  210. package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
  211. package/docs/content/locales/pt-BR/template-design.mdx +14 -1
  212. package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
  213. package/docs/content/locales/zh-CN/template-design.mdx +14 -1
  214. package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
  215. package/docs/content/locales/zh-TW/template-design.mdx +14 -1
  216. package/docs/content/skills-guide.mdx +5 -0
  217. package/docs/content/template-design.mdx +14 -1
  218. package/package.json +1 -1
  219. package/corpus/templates/design/actions/import-figma-file.ts +0 -166
  220. package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Custom onboarding plugin for Analytics.
3
+ *
4
+ * Overrides the framework's default onboarding plugin to add an optional
5
+ * "Session replay storage" step and register the S3 file upload provider. Must
6
+ * live in server/plugins/ so the framework skips its default onboarding plugin,
7
+ * and all registrations share the same module context as the onboarding route
8
+ * handlers (which read from the same in-memory Map).
9
+ *
10
+ * The step is `required: false` because session replay is opt-in: capturing
11
+ * replays only matters once a site embeds the tracking SDK with replay enabled,
12
+ * so we surface storage setup without forcing it into the onboarding checklist.
13
+ */
14
+
15
+ import { registerFileUploadProvider } from "@agent-native/core/file-upload";
16
+ import {
17
+ createOnboardingPlugin,
18
+ registerOnboardingStep,
19
+ } from "@agent-native/core/onboarding";
20
+
21
+ import { hasRequestReplayStorage } from "../lib/replay-storage.js";
22
+ import { s3FileUploadProvider } from "../lib/s3-upload-provider.js";
23
+
24
+ const basePlugin = createOnboardingPlugin();
25
+
26
+ export default async (nitroApp: any): Promise<void> => {
27
+ // Mount the framework's default onboarding plugin (routes + default steps).
28
+ await basePlugin(nitroApp);
29
+
30
+ // Register S3-compatible file upload provider for session-replay chunks.
31
+ registerFileUploadProvider(s3FileUploadProvider);
32
+
33
+ // Add the optional "Session replay storage" onboarding step.
34
+ registerOnboardingStep({
35
+ id: "replay-storage",
36
+ order: 15,
37
+ required: false,
38
+ title: "Session replay storage",
39
+ description:
40
+ "Store session replay recordings with Builder.io or S3-compatible storage.",
41
+ methods: [
42
+ {
43
+ id: "builder",
44
+ kind: "builder-cli-auth",
45
+ label: "Connect Builder.io",
46
+ description:
47
+ "Builder.io's free tier includes object storage for replay chunks.",
48
+ primary: true,
49
+ badge: "free",
50
+ payload: { scope: "browser" },
51
+ },
52
+ {
53
+ id: "s3",
54
+ kind: "form",
55
+ label: "Use S3-compatible storage",
56
+ description:
57
+ "AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, or any S3-compatible service.",
58
+ payload: {
59
+ writeScope: "workspace",
60
+ fields: [
61
+ {
62
+ key: "S3_ENDPOINT",
63
+ label: "Endpoint URL",
64
+ placeholder: "https://s3.us-east-1.amazonaws.com",
65
+ },
66
+ {
67
+ key: "S3_BUCKET",
68
+ label: "Bucket name",
69
+ placeholder: "my-replays-bucket",
70
+ },
71
+ {
72
+ key: "S3_ACCESS_KEY_ID",
73
+ label: "Access key ID",
74
+ placeholder: "AKIA...",
75
+ },
76
+ {
77
+ key: "S3_SECRET_ACCESS_KEY",
78
+ label: "Secret access key",
79
+ secret: true,
80
+ },
81
+ {
82
+ key: "S3_REGION",
83
+ label: "Region (optional)",
84
+ placeholder: "us-east-1",
85
+ },
86
+ {
87
+ key: "S3_PUBLIC_BASE_URL",
88
+ label: "Public base URL (optional)",
89
+ placeholder: "https://cdn.example.com",
90
+ },
91
+ ],
92
+ },
93
+ },
94
+ ],
95
+ isComplete: hasRequestReplayStorage,
96
+ });
97
+ };
@@ -2069,6 +2069,8 @@ async function startNativeFullscreenRecording(
2069
2069
  .then(() => {
2070
2070
  pausedAt = at;
2071
2071
  emitState();
2072
+ console.log("[clips-recorder] native pause: pausing transcription");
2073
+ void transcriptionCapture?.pause().catch(() => {});
2072
2074
  })
2073
2075
  .catch((err) => {
2074
2076
  console.warn("[clips-recorder] native pause failed:", err);
@@ -2076,6 +2078,8 @@ async function startNativeFullscreenRecording(
2076
2078
  }),
2077
2079
  listen("clips:recorder-resume", () => {
2078
2080
  if (pausedAt == null) return;
2081
+ // Only resume transcription once the recorder actually resumed, so a
2082
+ // rejected IPC can't leave transcription running over a paused recording.
2079
2083
  invoke("native_fullscreen_recording_resume")
2080
2084
  .then(() => {
2081
2085
  if (pausedAt != null) {
@@ -2083,6 +2087,8 @@ async function startNativeFullscreenRecording(
2083
2087
  pausedAt = null;
2084
2088
  }
2085
2089
  emitState();
2090
+ console.log("[clips-recorder] native resume: resuming transcription");
2091
+ void transcriptionCapture?.resume().catch(() => {});
2086
2092
  })
2087
2093
  .catch((err) => {
2088
2094
  console.warn("[clips-recorder] native resume failed:", err);
@@ -2125,6 +2131,12 @@ async function startNativeFullscreenRecording(
2125
2131
  if (stopped && transcriptionCapture) {
2126
2132
  void transcriptionCapture.cancel().catch(() => {});
2127
2133
  transcriptionCapture = null;
2134
+ } else if (pausedAt != null && transcriptionCapture) {
2135
+ // The user paused while the engine was still starting; honor it now.
2136
+ console.log(
2137
+ "[clips-recorder] native: paused during startup, pausing transcription",
2138
+ );
2139
+ void transcriptionCapture.pause().catch(() => {});
2128
2140
  } else if (
2129
2141
  wantsAudio &&
2130
2142
  !transcriptionCapture &&
@@ -2885,6 +2897,8 @@ async function startRecordingInner(
2885
2897
  recorder.pause();
2886
2898
  pausedAt = Date.now();
2887
2899
  emitState(true);
2900
+ console.log("[clips-recorder] recorder pause: pausing transcription");
2901
+ void transcriptionCapture?.pause().catch(() => {});
2888
2902
  } catch {
2889
2903
  // ignore
2890
2904
  }
@@ -2897,6 +2911,10 @@ async function startRecordingInner(
2897
2911
  if (pausedAt) accumulatedPauseMs += Date.now() - pausedAt;
2898
2912
  pausedAt = null;
2899
2913
  emitState(false);
2914
+ console.log(
2915
+ "[clips-recorder] recorder resume: resuming transcription",
2916
+ );
2917
+ void transcriptionCapture?.resume().catch(() => {});
2900
2918
  } catch {
2901
2919
  // ignore
2902
2920
  }
@@ -2951,6 +2969,12 @@ async function startRecordingInner(
2951
2969
  if (stopped && transcriptionCapture) {
2952
2970
  void transcriptionCapture.cancel().catch(() => {});
2953
2971
  transcriptionCapture = null;
2972
+ } else if (pausedAt != null && transcriptionCapture) {
2973
+ // The user paused while the engine was still starting; honor it now.
2974
+ console.log(
2975
+ "[clips-recorder] recorder: paused during startup, pausing transcription",
2976
+ );
2977
+ void transcriptionCapture.pause().catch(() => {});
2954
2978
  } else if (
2955
2979
  wantsAudio &&
2956
2980
  !transcriptionCapture &&
@@ -41,6 +41,10 @@ export interface CapturedTranscript {
41
41
  export interface TranscriptionCapture {
42
42
  stop(): Promise<CapturedTranscript>;
43
43
  cancel(): Promise<void>;
44
+ /** Suspend the audio engine without discarding the captured transcript. */
45
+ pause(): Promise<void>;
46
+ /** Restart the audio engine after a `pause()`. */
47
+ resume(): Promise<void>;
44
48
  }
45
49
 
46
50
  interface SpeechRecognitionResultLike {
@@ -154,6 +158,7 @@ async function startBrowserTranscriptionCapture(): Promise<TranscriptionCapture
154
158
  const recognition = new Ctor();
155
159
  let disposed = false;
156
160
  let stopped = false;
161
+ let paused = false;
157
162
  const transcriptBuffer = createWebSpeechTranscriptBuffer();
158
163
  let stopResolver: ((value: CapturedTranscript) => void) | null = null;
159
164
  let settleTimer: ReturnType<typeof window.setTimeout> | null = null;
@@ -195,11 +200,13 @@ async function startBrowserTranscriptionCapture(): Promise<TranscriptionCapture
195
200
 
196
201
  recognition.onend = () => {
197
202
  if (disposed) return;
198
- transcriptBuffer.commitSession({ preserveInterim: stopped });
203
+ transcriptBuffer.commitSession({ preserveInterim: stopped || paused });
199
204
  if (stopped) {
200
205
  settleStop();
201
206
  return;
202
207
  }
208
+ // While paused, keep the committed transcript but don't restart the engine.
209
+ if (paused) return;
203
210
  try {
204
211
  recognition.start();
205
212
  } catch (err) {
@@ -245,6 +252,29 @@ async function startBrowserTranscriptionCapture(): Promise<TranscriptionCapture
245
252
  // ignore
246
253
  }
247
254
  },
255
+ async pause() {
256
+ if (disposed || stopped || paused) return;
257
+ paused = true;
258
+ console.log("[clips-recorder] transcription paused (web-speech)");
259
+ try {
260
+ recognition.stop();
261
+ } catch {
262
+ // ignore
263
+ }
264
+ },
265
+ async resume() {
266
+ if (disposed || stopped || !paused) return;
267
+ paused = false;
268
+ console.log("[clips-recorder] transcription resumed (web-speech)");
269
+ try {
270
+ recognition.start();
271
+ } catch (err) {
272
+ console.warn(
273
+ "[clips-recorder] Web Speech transcription resume failed:",
274
+ err,
275
+ );
276
+ }
277
+ },
248
278
  };
249
279
  }
250
280
 
@@ -260,6 +290,13 @@ export async function startTranscriptionCapture(
260
290
  const lines: string[] = [];
261
291
  const segments: SourcedTranscriptSegment[] = [];
262
292
  let disposed = false;
293
+ let paused = false;
294
+ let desiredPaused = false;
295
+ let transitioning = false;
296
+ // When a pause stops the engine, Whisper still flushes trailing finals
297
+ // asynchronously. Track when those are expected to have landed so a stop
298
+ // soon after a pause waits for them instead of dropping the last words.
299
+ let pauseFinalsSettleUntil = 0;
263
300
  const unlistens: UnlistenFn[] = [];
264
301
 
265
302
  const cleanup = () => {
@@ -299,8 +336,59 @@ export async function startTranscriptionCapture(
299
336
  : null;
300
337
  }
301
338
 
339
+ // Pause/resume run fire-and-forget from the recorder, so a quick
340
+ // pause→resume can arrive while a transition is still awaiting the engine.
341
+ // Track the desired state and re-apply once the in-flight transition settles
342
+ // so the last request always wins (instead of being dropped).
343
+ const applyAudioState = async () => {
344
+ if (transitioning || disposed || desiredPaused === paused) return;
345
+ transitioning = true;
346
+ try {
347
+ if (desiredPaused) {
348
+ await stopTranscriptionEngine(engine);
349
+ paused = true;
350
+ pauseFinalsSettleUntil = Date.now() + WHISPER_STOP_SETTLE_MS;
351
+ console.log(`[clips-recorder] transcription paused (${engine})`);
352
+ } else {
353
+ engine = await startTranscriptionEngine({ mic, captureSystem });
354
+ // stop()/cancel() can run during the await above; if it did, the new
355
+ // engine would leak (mic/system capture stays live). Tear it down.
356
+ if (disposed) {
357
+ await stopTranscriptionEngine(engine).catch(() => {});
358
+ return;
359
+ }
360
+ paused = false;
361
+ console.log(`[clips-recorder] transcription resumed (${engine})`);
362
+ }
363
+ } catch (err) {
364
+ // Transition failed. Keep `desiredPaused` as the still-unmet intent (don't
365
+ // reset it) so the next pause/resume toggle retries and converges, and
366
+ // return early so we don't busy-loop re-applying a persistently failing
367
+ // transition. `paused` still reflects the real engine state.
368
+ console.warn(
369
+ `[clips-recorder] transcription ${desiredPaused ? "pause" : "resume"} failed; engine still ${paused ? "paused" : "live"}:`,
370
+ err,
371
+ );
372
+ // `finally` resets `transitioning`; returning skips the auto re-apply.
373
+ return;
374
+ } finally {
375
+ transitioning = false;
376
+ }
377
+ // Re-apply in case the desired state changed mid-transition.
378
+ void applyAudioState();
379
+ };
380
+
302
381
  return {
303
382
  async stop() {
383
+ // Already paused: the engine is stopped, but the pause-time flush may
384
+ // still be in flight. Wait out any remaining settle window so trailing
385
+ // finals land before we drop the listener.
386
+ if (paused) {
387
+ const remaining = pauseFinalsSettleUntil - Date.now();
388
+ if (remaining > 0) await wait(remaining);
389
+ cleanup();
390
+ return captured();
391
+ }
304
392
  try {
305
393
  await stopTranscriptionEngine(engine);
306
394
  } catch (err) {
@@ -314,12 +402,24 @@ export async function startTranscriptionCapture(
314
402
  return captured();
315
403
  },
316
404
  async cancel() {
317
- try {
318
- await stopTranscriptionEngine(engine);
319
- } catch {
320
- // ignore
405
+ if (!paused) {
406
+ try {
407
+ await stopTranscriptionEngine(engine);
408
+ } catch {
409
+ // ignore
410
+ }
321
411
  }
322
412
  cleanup();
323
413
  },
414
+ async pause() {
415
+ if (disposed) return;
416
+ desiredPaused = true;
417
+ await applyAudioState();
418
+ },
419
+ async resume() {
420
+ if (disposed) return;
421
+ desiredPaused = false;
422
+ await applyAudioState();
423
+ },
324
424
  };
325
425
  }
@@ -52,7 +52,7 @@ function imageAltCandidates({
52
52
  const candidates: ImageAltCandidate[] = [];
53
53
 
54
54
  const markdownImagePattern = new RegExp(
55
- `!\\[[^\\]]*\\]\\((${escapedUrl})(\\s+\"[^\"]*\")?\\)`,
55
+ `!\\[[^\\]]*\\]\\((${escapedUrl})(\\s+"[^"]*")?\\)`,
56
56
  "g",
57
57
  );
58
58
  for (const match of content.matchAll(markdownImagePattern)) {
@@ -115,7 +115,7 @@ function inlineMarkdownToHtml(text: string): string {
115
115
  .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
116
116
  .replace(/__([^_]+)__/g, "<strong>$1</strong>")
117
117
  .replace(/~~([^~]+)~~/g, "<s>$1</s>")
118
- .replace(/(^|[^\*])\*([^*]+)\*/g, "$1<em>$2</em>")
118
+ .replace(/(^|[^*])\*([^*]+)\*/g, "$1<em>$2</em>")
119
119
  .replace(/(^|[^_])_([^_]+)_/g, "$1<em>$2</em>");
120
120
  }
121
121
 
@@ -145,18 +145,18 @@ Returns CSS custom properties, colors, fonts, Google Fonts links, theme-color, O
145
145
  ### Source: GitHub Repository
146
146
 
147
147
  ```bash
148
- pnpm action import-github --repoUrl "https://github.com/acme/ui"
148
+ pnpm action index-design-system-with-builder --githubRepoUrl "https://github.com/acme/ui"
149
149
  ```
150
150
 
151
- Fetches Tailwind configs, CSS files, theme files, package.json. Returns extracted colors, fonts, spacing, border-radius, and styling framework detection.
151
+ Starts Builder design-system indexing for the repository. Builder is the source of truth for the indexed brand kit, generated docs, and usage guidance. If Builder is not connected, stop and ask the user to connect Builder.
152
152
 
153
153
  ### Source: Local Code Files
154
154
 
155
155
  ```bash
156
- pnpm action import-code --files '[{"filename":"globals.css","content":"..."}]'
156
+ pnpm action index-design-system-with-builder --codeFiles '[{"filename":"globals.css","content":"..."}]'
157
157
  ```
158
158
 
159
- Analyzes CSS, Tailwind configs, JSON theme files, TS/JS theme files. Returns structured tokens.
159
+ 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.
160
160
 
161
161
  ### Source: Documents (DOCX, PPTX, PDF)
162
162
 
@@ -192,20 +192,10 @@ effects to CSS box-shadow, and text styles to font tokens; snap spacing to a
192
192
  4/8px scale. If no Figma MCP is connected, ask the user to paste the token
193
193
  values or describe the file.
194
194
 
195
- **When the user uploads a raw `.fig` file**, parse it in-process with
196
- `import-figma-file` (no Figma account needed):
197
-
198
- ```bash
199
- pnpm action import-figma-file --fileBase64 "<base64 of the .fig>" # or --fileDataUrl
200
- ```
201
-
202
- It decodes the binary `.fig`, returns `frames` (each Figma frame rendered to
203
- HTML), an extracted `designSystem` (colors with assigned roles, typography,
204
- spacing, radius, shadows — ready for `DesignSystemData`), and image metadata.
205
- It's read-only/preview: review the result, then call `create-design-system`
206
- with the `designSystem` and/or `create-design` + `generate-design` with the
207
- `frames`. The full `palette` is returned too, so re-assign a color role if a
208
- heuristic looks off.
195
+ **When the user uploads a raw `.fig` file**, send it to Builder design-system
196
+ indexing through the setup page upload route. Do not parse `.fig` files locally
197
+ and do not call `create-design-system` from raw `.fig` output; Builder owns the
198
+ indexed brand kit, generated docs, and usage guidance.
209
199
 
210
200
  ### Source: Brand Analysis (combines website + notes)
211
201
 
@@ -28,6 +28,9 @@ iframe-backed screens on the infinite canvas.
28
28
  new flow state.
29
29
  - Flow visualization is just multiple URL states: `/checkout?step=shipping`,
30
30
  `/checkout?step=payment`, `/checkout?step=done`, etc.
31
+ - When the user gives a named flow or numbered screen list, preserve that order
32
+ and create one screen per URL/path. Shorthand like
33
+ `localhost:1234/onboarding/1` means `http://localhost:1234/onboarding/1`.
31
34
 
32
35
  ## Required Local Bridge
33
36
 
@@ -92,6 +95,20 @@ pnpm action add-localhost-screens '{
92
95
  }'
93
96
  ```
94
97
 
98
+ For a numbered flow the user describes in chat, keep the labels and order:
99
+
100
+ ```bash
101
+ pnpm action add-localhost-screens '{
102
+ "designId": "<design-id>",
103
+ "connectionId": "<connection-id>",
104
+ "routes": [
105
+ { "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
106
+ { "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
107
+ { "url": "localhost:1234/onboarding/3", "title": "Screen 3" }
108
+ ]
109
+ }'
110
+ ```
111
+
95
112
  If no `routes` or `paths` are supplied, `add-localhost-screens` uses every route
96
113
  from the latest localhost manifest. Use `paths` for a concise flow:
97
114
 
@@ -67,14 +67,40 @@ function normalizeBaseUrl(value: string): string {
67
67
  return parsed.toString().replace(/\/$/, "");
68
68
  }
69
69
 
70
- function routeUrl(baseUrl: string, route: { path?: string; url?: string }) {
70
+ function withLocalhostProtocol(value: string): string {
71
+ const raw = value.trim();
72
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return raw;
73
+ if (
74
+ /^(localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[::1\]|::1)(?::\d+)?(?:[/?#]|$)/i.test(
75
+ raw,
76
+ )
77
+ ) {
78
+ return `http://${raw}`;
79
+ }
80
+ return raw;
81
+ }
82
+
83
+ export function routeUrl(
84
+ baseUrl: string,
85
+ route: { path?: string; url?: string },
86
+ ) {
71
87
  const raw = route.url ?? route.path ?? "/";
72
- const parsed = new URL(raw, `${baseUrl}/`);
88
+ let parsed: URL;
89
+ try {
90
+ parsed = new URL(withLocalhostProtocol(raw), `${baseUrl}/`);
91
+ } catch {
92
+ throw new Error(
93
+ `Invalid localhost screen URL "${raw}". Use a path like /pricing or an http(s) localhost URL.`,
94
+ );
95
+ }
96
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
97
+ throw new Error(`Localhost screen URL must be an http(s) URL: ${raw}`);
98
+ }
73
99
  parsed.hash = "";
74
100
  return parsed.toString();
75
101
  }
76
102
 
77
- function pathFromUrl(baseUrl: string, url: string, fallback?: string) {
103
+ export function pathFromUrl(baseUrl: string, url: string, fallback?: string) {
78
104
  try {
79
105
  const parsed = new URL(url);
80
106
  const base = new URL(baseUrl);
@@ -87,10 +113,11 @@ function pathFromUrl(baseUrl: string, url: string, fallback?: string) {
87
113
  return fallback ?? "/";
88
114
  }
89
115
 
90
- function slugForPath(pathOrUrl: string) {
116
+ export function slugForPath(pathOrUrl: string) {
91
117
  const parsed = (() => {
92
118
  try {
93
- return new URL(pathOrUrl).pathname + new URL(pathOrUrl).search;
119
+ const url = new URL(withLocalhostProtocol(pathOrUrl));
120
+ return url.pathname + url.search;
94
121
  } catch {
95
122
  return pathOrUrl;
96
123
  }