@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
@@ -123,6 +123,33 @@ export function pgliteDataDirFromUrl(url: string): string {
123
123
  return dataDir;
124
124
  }
125
125
 
126
+ export function pgliteRuntimeDataDir(dataDir: string): string {
127
+ if (dataDir === "memory://") return dataDir;
128
+ if (!isServerlessRuntime() || path.isAbsolute(dataDir)) return dataDir;
129
+
130
+ const safeParts = dataDir
131
+ .split(/[\\/]+/)
132
+ .filter((part) => part && part !== "." && part !== "..");
133
+ const safeRelative =
134
+ safeParts.length > 0
135
+ ? path.join(...safeParts)
136
+ : path.join("data", "pglite");
137
+ return path.join("/tmp", safeRelative);
138
+ }
139
+
140
+ async function preparePgliteDataDir(dataDir: string): Promise<string> {
141
+ const runtimeDataDir = pgliteRuntimeDataDir(dataDir);
142
+ if (runtimeDataDir === "memory://") return runtimeDataDir;
143
+
144
+ try {
145
+ const fs = await import("fs");
146
+ fs.mkdirSync(runtimeDataDir, { recursive: true });
147
+ } catch {
148
+ // Edge runtimes may not expose fs. PGlite will surface any real open error.
149
+ }
150
+ return runtimeDataDir;
151
+ }
152
+
126
153
  async function importOptionalModule(specifier: string): Promise<any> {
127
154
  return import(/* @vite-ignore */ specifier);
128
155
  }
@@ -170,7 +197,7 @@ export async function loadPgliteDrizzle(): Promise<{
170
197
  const _pgliteClients = new Map<string, Promise<any>>();
171
198
 
172
199
  export async function getPgliteClient(url: string): Promise<any> {
173
- const dataDir = pgliteDataDirFromUrl(url);
200
+ const dataDir = await preparePgliteDataDir(pgliteDataDirFromUrl(url));
174
201
  let ready = _pgliteClients.get(dataDir);
175
202
  if (!ready) {
176
203
  ready = loadPglitePackage().then(({ PGlite }) => PGlite.create(dataDir));
@@ -190,7 +217,7 @@ export async function closePgliteClients(): Promise<void> {
190
217
  }
191
218
 
192
219
  export async function closePgliteClient(url: string): Promise<void> {
193
- const dataDir = pgliteDataDirFromUrl(url);
220
+ const dataDir = pgliteRuntimeDataDir(pgliteDataDirFromUrl(url));
194
221
  const ready = _pgliteClients.get(dataDir);
195
222
  _pgliteClients.delete(dataDir);
196
223
  if (!ready) return;
@@ -58,6 +58,7 @@ export const PROVIDER_API_IDS = [
58
58
  "ga4",
59
59
  "gcloud",
60
60
  "github",
61
+ "figma",
61
62
  "gmail",
62
63
  "gong",
63
64
  "google_calendar",
@@ -374,6 +375,7 @@ export interface ProviderApiExample {
374
375
  label: string;
375
376
  method: ProviderApiMethod;
376
377
  path: string;
378
+ query?: unknown;
377
379
  body?: unknown;
378
380
  }
379
381
 
@@ -777,6 +779,33 @@ const PROVIDER_CONFIGS: Record<ProviderApiId, ProviderApiConfig> = {
777
779
  { label: "Search issues", method: "GET", path: "/search/issues" },
778
780
  ],
779
781
  },
782
+ figma: {
783
+ id: "figma",
784
+ label: "Figma REST API",
785
+ defaultBaseUrl: "https://api.figma.com/v1",
786
+ auth: {
787
+ type: "api-key-header",
788
+ key: "FIGMA_ACCESS_TOKEN",
789
+ header: "X-Figma-Token",
790
+ },
791
+ credentialKeys: ["FIGMA_ACCESS_TOKEN"],
792
+ docsUrls: ["https://www.figma.com/developers/api"],
793
+ allowedHostSuffixes: ["figma.com"],
794
+ templateUses: ["design"],
795
+ examples: [
796
+ {
797
+ label: "List file components",
798
+ method: "GET",
799
+ path: "/files/{fileKey}/components",
800
+ },
801
+ {
802
+ label: "Render file nodes",
803
+ method: "GET",
804
+ path: "/images/{fileKey}",
805
+ query: { ids: "1:2", format: "svg" },
806
+ },
807
+ ],
808
+ },
780
809
  gmail: {
781
810
  id: "gmail",
782
811
  label: "Gmail API",
@@ -236,6 +236,11 @@ export async function runDbHealthProbe(
236
236
  const DEFAULT_BUILDER_WAITLIST_FORM_ID = "DYTHuM0jlV";
237
237
  const DEFAULT_BUILDER_WAITLIST_FORMS_ORIGIN = "https://forms.agent-native.com";
238
238
  const BUILDER_WAITLIST_FORM_SOURCE = "connect_builder_card";
239
+ const BUILDER_WAITLIST_DEFAULT_USE_CASE = "builder_agent_background_coding";
240
+ const BUILDER_WAITLIST_USE_CASES = new Set([
241
+ BUILDER_WAITLIST_DEFAULT_USE_CASE,
242
+ "design_publish_app",
243
+ ]);
239
244
  const BUILDER_WAITLIST_FORM_TIMEOUT_MS = 8000;
240
245
  const BUILDER_WAITLIST_TEXT_LIMIT = 4000;
241
246
 
@@ -244,12 +249,13 @@ interface BuilderWaitlistFormTarget {
244
249
  formsOrigin: string;
245
250
  }
246
251
 
247
- interface BuilderWaitlistBody {
252
+ export interface BuilderWaitlistBody {
248
253
  prompt?: unknown;
249
254
  orgName?: unknown;
250
255
  appUrl?: unknown;
251
256
  pageUrl?: unknown;
252
257
  source?: unknown;
258
+ useCase?: unknown;
253
259
  }
254
260
 
255
261
  export function resolveFrameworkSseRoutes(sseRoute?: string): string[] {
@@ -274,6 +280,13 @@ function cleanBuilderWaitlistText(
274
280
  return trimmed.slice(0, maxLength);
275
281
  }
276
282
 
283
+ function normalizeBuilderWaitlistUseCase(value: unknown): string {
284
+ const useCase = cleanBuilderWaitlistText(value, 100);
285
+ return useCase && BUILDER_WAITLIST_USE_CASES.has(useCase)
286
+ ? useCase
287
+ : BUILDER_WAITLIST_DEFAULT_USE_CASE;
288
+ }
289
+
277
290
  function normalizeHttpOrigin(value: string): string | null {
278
291
  try {
279
292
  const url = new URL(value);
@@ -317,20 +330,45 @@ export function resolveBuilderWaitlistFormTargetForRequest(
317
330
  return { formId, formsOrigin };
318
331
  }
319
332
 
320
- async function submitBuilderWaitlistForm(
333
+ export function buildBuilderWaitlistFormPayload(
321
334
  event: H3Event,
322
335
  sessionEmail: string,
323
336
  body: BuilderWaitlistBody,
324
- ): Promise<{ submitted: boolean; formId?: string }> {
325
- const target = resolveBuilderWaitlistFormTargetForRequest(event);
326
- if (!target) return { submitted: false };
327
-
337
+ ) {
328
338
  const appUrl =
329
339
  cleanBuilderWaitlistText(body.pageUrl ?? body.appUrl, 2000) ??
330
340
  cleanBuilderWaitlistText(getHeader(event, "referer"), 2000) ??
331
341
  getOrigin(event);
332
342
  const source =
333
343
  cleanBuilderWaitlistText(body.source, 100) ?? BUILDER_WAITLIST_FORM_SOURCE;
344
+ const useCase = normalizeBuilderWaitlistUseCase(body.useCase);
345
+
346
+ return {
347
+ data: {
348
+ email: sessionEmail,
349
+ orgName: cleanBuilderWaitlistText(body.orgName, 500),
350
+ appUrl,
351
+ prompt: cleanBuilderWaitlistText(body.prompt),
352
+ source,
353
+ useCase,
354
+ },
355
+ _hp: "",
356
+ _meta: {
357
+ submitterEmail: sessionEmail,
358
+ pageUrl: appUrl,
359
+ source,
360
+ useCase,
361
+ },
362
+ };
363
+ }
364
+
365
+ async function submitBuilderWaitlistForm(
366
+ event: H3Event,
367
+ sessionEmail: string,
368
+ body: BuilderWaitlistBody,
369
+ ): Promise<{ submitted: boolean; formId?: string }> {
370
+ const target = resolveBuilderWaitlistFormTargetForRequest(event);
371
+ if (!target) return { submitted: false };
334
372
 
335
373
  const controller = new AbortController();
336
374
  const timeout = setTimeout(
@@ -344,20 +382,9 @@ async function submitBuilderWaitlistForm(
344
382
  {
345
383
  method: "POST",
346
384
  headers: { "Content-Type": "application/json" },
347
- body: JSON.stringify({
348
- data: {
349
- email: sessionEmail,
350
- orgName: cleanBuilderWaitlistText(body.orgName, 500),
351
- appUrl,
352
- prompt: cleanBuilderWaitlistText(body.prompt),
353
- source,
354
- },
355
- _hp: "",
356
- _meta: {
357
- submitterEmail: sessionEmail,
358
- pageUrl: appUrl,
359
- },
360
- }),
385
+ body: JSON.stringify(
386
+ buildBuilderWaitlistFormPayload(event, sessionEmail, body),
387
+ ),
361
388
  signal: controller.signal,
362
389
  },
363
390
  );
@@ -1671,6 +1698,13 @@ export function createCoreRoutesPlugin(
1671
1698
  }
1672
1699
  const body = ((await readBody(event).catch(() => ({}))) ??
1673
1700
  {}) as BuilderWaitlistBody;
1701
+ const waitlistPayload = buildBuilderWaitlistFormPayload(
1702
+ event,
1703
+ session.email,
1704
+ body,
1705
+ );
1706
+ const waitlistSource = waitlistPayload.data.source;
1707
+ const waitlistUseCase = waitlistPayload.data.useCase;
1674
1708
  let formSubmission: { submitted: boolean; formId?: string };
1675
1709
  try {
1676
1710
  formSubmission = await submitBuilderWaitlistForm(
@@ -1686,7 +1720,9 @@ export function createCoreRoutesPlugin(
1686
1720
  {
1687
1721
  reason:
1688
1722
  err instanceof Error ? err.message : "unknown_waitlist_error",
1723
+ source: waitlistSource,
1689
1724
  stage: "waitlist",
1725
+ useCase: waitlistUseCase,
1690
1726
  },
1691
1727
  );
1692
1728
  setResponseStatus(event, 502);
@@ -1702,7 +1738,9 @@ export function createCoreRoutesPlugin(
1702
1738
  {
1703
1739
  formId: formSubmission.formId ?? null,
1704
1740
  formSubmitted: formSubmission.submitted,
1741
+ source: waitlistSource,
1705
1742
  stage: "waitlist",
1743
+ useCase: waitlistUseCase,
1706
1744
  },
1707
1745
  );
1708
1746
  return { ok: true, formSubmitted: formSubmission.submitted };
@@ -537,6 +537,60 @@
537
537
  }
538
538
  }
539
539
 
540
+ /* Connect AI card: use the card width, not the viewport, so narrow embedded
541
+ sidebars stack the copy and actions before the secondary button clips. */
542
+ .agent-builder-setup-card {
543
+ min-inline-size: min(18rem, 100%);
544
+ }
545
+
546
+ .agent-builder-setup-card--sidebar {
547
+ container-type: inline-size;
548
+ container-name: agent-builder-setup;
549
+ }
550
+
551
+ @container agent-builder-setup (max-width: 560px) {
552
+ .agent-builder-setup-card__content {
553
+ align-items: stretch;
554
+ flex-direction: column;
555
+ }
556
+
557
+ .agent-builder-setup-card__actions {
558
+ align-items: center;
559
+ flex-direction: row;
560
+ flex-wrap: wrap;
561
+ gap: 0.5rem;
562
+ width: 100%;
563
+ }
564
+
565
+ .agent-builder-setup-card__builder-cta {
566
+ align-items: stretch;
567
+ flex: 1 1 11rem;
568
+ }
569
+
570
+ .agent-builder-setup-card__builder-button,
571
+ .agent-builder-setup-card__key-button {
572
+ justify-content: center;
573
+ min-width: 0;
574
+ width: 100%;
575
+ }
576
+
577
+ .agent-builder-setup-card__key-button {
578
+ border: 1px solid hsl(var(--border));
579
+ background: hsl(var(--background));
580
+ color: hsl(var(--foreground));
581
+ flex: 1 1 8rem;
582
+ height: 2rem;
583
+ padding-inline: 0.75rem;
584
+ }
585
+ }
586
+
587
+ @container agent-builder-setup (max-width: 360px) {
588
+ .agent-builder-setup-card__actions {
589
+ align-items: stretch;
590
+ flex-direction: column;
591
+ }
592
+ }
593
+
540
594
  .agent-composer-area--hero {
541
595
  padding-inline: 0;
542
596
  padding-block: 0.5rem;
@@ -112,12 +112,12 @@ const PRICING: Array<{ match: RegExp; pricing: ModelPricing }> = [
112
112
  // ── Google Gemini ───────────────────────────────────────────────────────────
113
113
  // Gemini 3 Pro / 3.1 Pro: ~$1.25/$10 per MTok (approximate; verify on billing)
114
114
  {
115
- match: /gemini-3[.\-]1-pro/i,
115
+ match: /gemini-3[.-]1-pro/i,
116
116
  pricing: { input: 125, output: 1000, cacheRead: 31, cacheWrite: 0 },
117
117
  },
118
118
  // Gemini 3.5 Flash / 3 Flash: ~$0.15/$0.60 per MTok
119
119
  {
120
- match: /gemini-3[.\-][0-9]+-flash/i,
120
+ match: /gemini-3[.-][0-9]+-flash/i,
121
121
  pricing: { input: 15, output: 60, cacheRead: 4, cacheWrite: 0 },
122
122
  },
123
123
  // Gemini 2.5 Pro/Flash (catch-all for older 2.5)
@@ -1,22 +1,32 @@
1
1
  import {
2
+ appBasePath,
2
3
  AgentSidebar,
3
4
  GuidedQuestionFlow,
4
5
  focusAgentChat,
6
+ markAgentChatHomeHandoff,
5
7
  navigateWithAgentChatViewTransition,
6
8
  useAgentChatHomeHandoff,
7
- useAgentChatHomeHandoffLinks,
8
9
  useGuidedQuestionFlow,
9
10
  useT,
10
11
  } from "@agent-native/core/client";
11
12
  import { InvitationBanner } from "@agent-native/core/client/org";
12
- import { useMemo } from "react";
13
+ import { useEffect, useMemo } from "react";
13
14
  import { useLocation, useNavigate } from "react-router";
14
15
 
15
16
  import { useNavigationState } from "@/hooks/use-navigation-state";
17
+ import {
18
+ ANALYTICS_CHAT_STORAGE_KEY,
19
+ hasRecentAnalyticsChat,
20
+ markAnalyticsChatActivity,
21
+ } from "@/lib/chat-handoff";
16
22
  import { TAB_ID } from "@/lib/tab-id";
17
23
 
18
24
  import { Header } from "./Header";
19
25
  import { HeaderActionsProvider } from "./HeaderActions";
26
+ import {
27
+ isAnalyticsSessionsRoute,
28
+ shouldDefaultOpenAnalyticsSidebar,
29
+ } from "./layout-route-policy";
20
30
  import { MobileNav } from "./MobileNav";
21
31
  import { Sidebar } from "./Sidebar";
22
32
 
@@ -26,6 +36,59 @@ interface LayoutProps {
26
36
 
27
37
  const BARE_ROUTES = new Set(["/chart"]);
28
38
 
39
+ function stripBasePath(path: string): string {
40
+ const basePath = appBasePath();
41
+ if (!basePath) return path;
42
+ if (path === basePath) return "/";
43
+ if (path.startsWith(`${basePath}/`)) return path.slice(basePath.length);
44
+ if (path.startsWith(`${basePath}?`) || path.startsWith(`${basePath}#`)) {
45
+ return `/${path.slice(basePath.length)}`;
46
+ }
47
+ return path;
48
+ }
49
+
50
+ function pathnameFromLocalPath(path: string): string {
51
+ return path.split(/[?#]/, 1)[0] || "/";
52
+ }
53
+
54
+ function isFrameworkOrApiPath(pathname: string): boolean {
55
+ return (
56
+ pathname === "/_agent-native" ||
57
+ pathname.startsWith("/_agent-native/") ||
58
+ pathname === "/api" ||
59
+ pathname.startsWith("/api/")
60
+ );
61
+ }
62
+
63
+ function isStaticAssetPath(pathname: string): boolean {
64
+ const lastSegment = pathname.split("/").pop() ?? "";
65
+ return /\.[A-Za-z0-9]{1,12}$/.test(lastSegment);
66
+ }
67
+
68
+ function localPathFromAnchor(anchor: HTMLAnchorElement): string | null {
69
+ if (!anchor.href) return null;
70
+ try {
71
+ const url = new URL(anchor.href);
72
+ if (url.origin !== window.location.origin) return null;
73
+ return stripBasePath(`${url.pathname}${url.search}${url.hash}`);
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+
79
+ function shouldHandleAnchorClick(
80
+ event: MouseEvent,
81
+ anchor: HTMLAnchorElement,
82
+ ): boolean {
83
+ if (event.defaultPrevented || event.button !== 0) return false;
84
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
85
+ return false;
86
+ }
87
+ if (anchor.target && anchor.target !== "_self") return false;
88
+ if (anchor.hasAttribute("download")) return false;
89
+ return true;
90
+ }
91
+
29
92
  export function Layout({ children }: LayoutProps) {
30
93
  useNavigationState();
31
94
  const location = useLocation();
@@ -82,18 +145,60 @@ export function Layout({ children }: LayoutProps) {
82
145
  const isExtensionsRoute =
83
146
  location.pathname === "/extensions" ||
84
147
  location.pathname.startsWith("/extensions/");
148
+ const isSessionsRoute = isAnalyticsSessionsRoute(location.pathname);
85
149
  const isAskRoute = location.pathname === "/ask";
86
150
  const chatHomeHandoffActive = useAgentChatHomeHandoff({
87
- storageKey: "analytics",
151
+ storageKey: ANALYTICS_CHAT_STORAGE_KEY,
88
152
  activePath: location.pathname,
89
153
  enabled: !isAskRoute && !reportScreenshot,
90
154
  });
91
- useAgentChatHomeHandoffLinks({
92
- storageKey: "analytics",
93
- chatPath: "/ask",
94
- });
95
155
  const sidebarScope = chatHomeHandoffActive ? null : analyticsScope;
96
156
 
157
+ useEffect(() => {
158
+ function handleChatRunning(event: Event) {
159
+ const detail = (event as CustomEvent).detail;
160
+ if (typeof detail?.isRunning === "boolean") {
161
+ markAnalyticsChatActivity();
162
+ }
163
+ }
164
+
165
+ window.addEventListener("agentNative.chatRunning", handleChatRunning);
166
+ return () =>
167
+ window.removeEventListener("agentNative.chatRunning", handleChatRunning);
168
+ }, []);
169
+
170
+ useEffect(() => {
171
+ if (!isAskRoute) return;
172
+
173
+ function handleClick(event: MouseEvent) {
174
+ const target = event.target;
175
+ if (!(target instanceof Element)) return;
176
+ const anchor = target.closest("a[href]");
177
+ if (!(anchor instanceof HTMLAnchorElement)) return;
178
+ if (!shouldHandleAnchorClick(event, anchor)) return;
179
+ if (anchor.closest(".agent-panel-root")) return;
180
+
181
+ const path = localPathFromAnchor(anchor);
182
+ const pathname = path ? pathnameFromLocalPath(path) : "";
183
+ if (
184
+ !path ||
185
+ pathname === "/ask" ||
186
+ isFrameworkOrApiPath(pathname) ||
187
+ isStaticAssetPath(pathname) ||
188
+ !hasRecentAnalyticsChat()
189
+ ) {
190
+ return;
191
+ }
192
+
193
+ event.preventDefault();
194
+ markAgentChatHomeHandoff(ANALYTICS_CHAT_STORAGE_KEY);
195
+ navigateWithAgentChatViewTransition(navigate, path);
196
+ }
197
+
198
+ document.addEventListener("click", handleClick, true);
199
+ return () => document.removeEventListener("click", handleClick, true);
200
+ }, [isAskRoute, navigate]);
201
+
97
202
  function openAskAgentFullscreen() {
98
203
  focusAgentChat();
99
204
  navigateWithAgentChatViewTransition(navigate, "/ask");
@@ -158,11 +263,14 @@ export function Layout({ children }: LayoutProps) {
158
263
  ) : (
159
264
  <AgentSidebar
160
265
  position="right"
161
- defaultOpen
266
+ defaultOpen={
267
+ chatHomeHandoffActive &&
268
+ shouldDefaultOpenAnalyticsSidebar(location.pathname)
269
+ }
162
270
  chatViewTransition
163
- storageKey="analytics"
271
+ storageKey={ANALYTICS_CHAT_STORAGE_KEY}
164
272
  browserTabId={TAB_ID}
165
- openOnChatRunning={chatHomeHandoffActive}
273
+ openOnChatRunning={chatHomeHandoffActive && !isSessionsRoute}
166
274
  onFullscreenRequest={openAskAgentFullscreen}
167
275
  emptyStateText={t("chat.emptyState")}
168
276
  suggestions={[
@@ -0,0 +1,7 @@
1
+ export function isAnalyticsSessionsRoute(pathname: string): boolean {
2
+ return pathname === "/sessions" || pathname.startsWith("/sessions/");
3
+ }
4
+
5
+ export function shouldDefaultOpenAnalyticsSidebar(pathname: string): boolean {
6
+ return !isAnalyticsSessionsRoute(pathname);
7
+ }
@@ -464,6 +464,10 @@
464
464
  container: analytics-session-detail / inline-size;
465
465
  }
466
466
 
467
+ .analytics-session-detail-timeline {
468
+ display: none;
469
+ }
470
+
467
471
  @container analytics-session-detail (min-width: 760px) {
468
472
  .analytics-session-detail-header {
469
473
  flex-direction: row;
@@ -476,6 +480,10 @@
476
480
  .analytics-session-detail-workbench {
477
481
  grid-template-columns: minmax(0, 1fr) 330px;
478
482
  }
483
+
484
+ .analytics-session-detail-timeline {
485
+ display: flex;
486
+ }
479
487
  }
480
488
 
481
489
  /* The dashboard grid responds to the available content width — which shrinks
@@ -4,6 +4,10 @@ import {
4
4
  } from "@agent-native/core/client";
5
5
  import { useLocation } from "react-router";
6
6
 
7
+ import {
8
+ ANALYTICS_CHAT_STORAGE_KEY,
9
+ hasRecentAnalyticsChat,
10
+ } from "@/lib/chat-handoff";
7
11
  import { rememberLastOpened } from "@/lib/last-opened";
8
12
  import { TAB_ID } from "@/lib/tab-id";
9
13
 
@@ -102,7 +106,9 @@ export function useNavigationState() {
102
106
  },
103
107
  onNavigate: (_command, path) => {
104
108
  if (location.pathname === "/ask" && pathnameFromPath(path) !== "/ask") {
105
- markAgentChatHomeHandoff("analytics");
109
+ if (hasRecentAnalyticsChat()) {
110
+ markAgentChatHomeHandoff(ANALYTICS_CHAT_STORAGE_KEY);
111
+ }
106
112
  }
107
113
  },
108
114
  });
@@ -0,0 +1,34 @@
1
+ export const ANALYTICS_CHAT_STORAGE_KEY = "analytics";
2
+
3
+ export const ANALYTICS_RECENT_CHAT_HANDOFF_TTL_MS = 5 * 60 * 1000;
4
+
5
+ const ANALYTICS_LAST_CHAT_ACTIVITY_KEY =
6
+ "agent-native.analytics.last-chat-activity-at";
7
+
8
+ function readAnalyticsLastChatActivityAt(): number {
9
+ if (typeof window === "undefined") return 0;
10
+ try {
11
+ const raw = window.sessionStorage.getItem(ANALYTICS_LAST_CHAT_ACTIVITY_KEY);
12
+ const parsed = raw ? Number.parseInt(raw, 10) : 0;
13
+ return Number.isFinite(parsed) ? parsed : 0;
14
+ } catch {
15
+ return 0;
16
+ }
17
+ }
18
+
19
+ export function markAnalyticsChatActivity(now = Date.now()): void {
20
+ if (typeof window === "undefined") return;
21
+ try {
22
+ window.sessionStorage.setItem(
23
+ ANALYTICS_LAST_CHAT_ACTIVITY_KEY,
24
+ String(now),
25
+ );
26
+ } catch {}
27
+ }
28
+
29
+ export function hasRecentAnalyticsChat(now = Date.now()): boolean {
30
+ const lastChatAt = readAnalyticsLastChatActivityAt();
31
+ return (
32
+ lastChatAt > 0 && now - lastChatAt <= ANALYTICS_RECENT_CHAT_HANDOFF_TTL_MS
33
+ );
34
+ }
@@ -1,25 +1,15 @@
1
- import {
2
- AgentChatSurface,
3
- markAgentChatHomeHandoff,
4
- useT,
5
- } from "@agent-native/core/client";
6
- import { useEffect } from "react";
1
+ import { AgentChatSurface, useT } from "@agent-native/core/client";
2
+ import { useState } from "react";
7
3
 
4
+ import {
5
+ ANALYTICS_CHAT_STORAGE_KEY,
6
+ hasRecentAnalyticsChat,
7
+ } from "@/lib/chat-handoff";
8
8
  import { TAB_ID } from "@/lib/tab-id";
9
9
 
10
10
  export default function AskPage() {
11
11
  const t = useT();
12
-
13
- useEffect(() => {
14
- function handleChatRunning(event: Event) {
15
- const detail = (event as CustomEvent).detail;
16
- if (detail?.isRunning === true) markAgentChatHomeHandoff("analytics");
17
- }
18
-
19
- window.addEventListener("agentNative.chatRunning", handleChatRunning);
20
- return () =>
21
- window.removeEventListener("agentNative.chatRunning", handleChatRunning);
22
- }, []);
12
+ const [restoreActiveThread] = useState(() => hasRecentAnalyticsChat());
23
13
 
24
14
  return (
25
15
  <div className="analytics-ask-page flex h-full min-h-0 flex-col bg-background">
@@ -28,7 +18,8 @@ export default function AskPage() {
28
18
  chatViewTransition
29
19
  className="analytics-chat-panel"
30
20
  defaultMode="chat"
31
- storageKey="analytics"
21
+ storageKey={ANALYTICS_CHAT_STORAGE_KEY}
22
+ restoreActiveThread={restoreActiveThread}
32
23
  browserTabId={TAB_ID}
33
24
  showHeader={false}
34
25
  showTabBar={false}
@@ -28,7 +28,7 @@ import {
28
28
  import {
29
29
  IconArchive,
30
30
  IconClock,
31
- IconDots,
31
+ IconDotsVertical,
32
32
  IconEye,
33
33
  IconEyeOff,
34
34
  IconGripVertical,
@@ -1391,7 +1391,7 @@ export default function SqlDashboardPage() {
1391
1391
  className="text-muted-foreground hover:text-foreground"
1392
1392
  aria-label={t("sqlDashboard.dashboardActions")}
1393
1393
  >
1394
- <IconDots className="h-4 w-4" />
1394
+ <IconDotsVertical className="h-4 w-4" />
1395
1395
  </Button>
1396
1396
  </DropdownMenuTrigger>
1397
1397
  </TooltipTrigger>