@agent-native/core 0.99.1 → 0.99.2

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 (148) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +13 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +12 -38
  5. package/corpus/core/src/audit/config.ts +0 -1
  6. package/corpus/core/src/chat-threads/store.ts +57 -41
  7. package/corpus/core/src/client/AssistantChat.tsx +1 -2
  8. package/corpus/core/src/client/chat/message-components.tsx +15 -3
  9. package/corpus/core/src/client/chat/tool-call-display.tsx +18 -1
  10. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -9
  11. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +0 -133
  12. package/corpus/core/src/client/index.ts +7 -0
  13. package/corpus/core/src/client/settings/DemoModeSection.tsx +9 -65
  14. package/corpus/core/src/client/settings/SettingsPanel.tsx +1 -1
  15. package/corpus/core/src/client/use-db-sync.ts +3 -15
  16. package/corpus/core/src/client/use-demo-mode-status.ts +16 -30
  17. package/corpus/core/src/demo/browser-state.ts +47 -0
  18. package/corpus/core/src/demo/fetch-interceptor.ts +12 -59
  19. package/corpus/core/src/deploy/workspace-deploy.ts +2 -2
  20. package/corpus/core/src/server/action-discovery.ts +0 -1
  21. package/corpus/core/src/server/core-routes-plugin.ts +0 -30
  22. package/corpus/core/src/templates/workspace-core/.agents/skills/native-navigation/SKILL.md +67 -0
  23. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +48 -7
  24. package/corpus/templates/analytics/AGENTS.md +4 -4
  25. package/corpus/templates/analytics/actions/compose-dashboard.ts +12 -1
  26. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +15 -4
  27. package/corpus/templates/analytics/actions/mutate-dashboard.ts +2 -1
  28. package/corpus/templates/analytics/actions/update-dashboard.ts +14 -0
  29. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -27
  30. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -1
  31. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/interpolate.ts +21 -0
  32. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +14 -0
  33. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +31 -12
  34. package/corpus/templates/analytics/changelog/2026-07-13-dashboard-charts-now-honor-the-selected-time-range-by-defaul.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-07-13-keep-real-authorized-identities-in-analytics-incident-lookup.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-07-13-the-analytics-agents-tab-is-available-again-from-the-main-na.md +6 -0
  37. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
  38. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +4 -0
  39. package/corpus/templates/analytics/server/lib/dashboard-time-scope.ts +170 -0
  40. package/corpus/templates/analytics/server/lib/error-capture.ts +6 -62
  41. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +20 -5
  42. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +1 -1
  43. package/corpus/templates/analytics/server/lib/session-replay.ts +5 -111
  44. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  45. package/corpus/templates/assets/app/routes/library.tsx +3 -4
  46. package/corpus/templates/assets/changelog/2026-07-13-internal-library-links-open-in-new-tabs.md +6 -0
  47. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +43 -40
  48. package/corpus/templates/calendar/app/pages/ManageBookingPage.tsx +6 -8
  49. package/corpus/templates/calendar/changelog/2026-07-13-booking-links-and-previews-open-in-new-tabs.md +6 -0
  50. package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +4 -7
  51. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +19 -9
  52. package/corpus/templates/clips/app/routes/share.$shareId.tsx +5 -3
  53. package/corpus/templates/clips/changelog/2026-07-13-recording-links-open-in-new-tabs.md +6 -0
  54. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +6 -8
  55. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +5 -3
  56. package/corpus/templates/content/app/components/editor/database/FormView.tsx +6 -9
  57. package/corpus/templates/content/changelog/2026-07-13-document-links-open-in-new-tabs.md +6 -0
  58. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +33 -16
  59. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +18 -1
  60. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +4 -4
  61. package/corpus/templates/design/app/pages/DesignSystems.tsx +8 -10
  62. package/corpus/templates/design/app/pages/Index.tsx +6 -1
  63. package/corpus/templates/design/app/pages/Present.tsx +12 -6
  64. package/corpus/templates/design/changelog/2026-07-13-design-navigation-links-open-in-new-tabs.md +6 -0
  65. package/corpus/templates/design/changelog/2026-07-13-design-session-replays-include-preview-iframes.md +6 -0
  66. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -11
  67. package/corpus/templates/forms/app/pages/FormsListPage.tsx +6 -8
  68. package/corpus/templates/forms/changelog/2026-07-13-form-navigation-links-open-in-new-tabs.md +6 -0
  69. package/corpus/templates/mail/app/pages/DraftQueuePage.tsx +3 -8
  70. package/corpus/templates/mail/changelog/2026-07-13-settings-links-open-in-new-tabs.md +6 -0
  71. package/dist/agent/production-agent.d.ts.map +1 -1
  72. package/dist/agent/production-agent.js +13 -37
  73. package/dist/agent/production-agent.js.map +1 -1
  74. package/dist/audit/config.d.ts.map +1 -1
  75. package/dist/audit/config.js +0 -1
  76. package/dist/audit/config.js.map +1 -1
  77. package/dist/chat-threads/store.d.ts.map +1 -1
  78. package/dist/chat-threads/store.js +47 -33
  79. package/dist/chat-threads/store.js.map +1 -1
  80. package/dist/client/AssistantChat.d.ts.map +1 -1
  81. package/dist/client/AssistantChat.js +1 -1
  82. package/dist/client/AssistantChat.js.map +1 -1
  83. package/dist/client/chat/message-components.d.ts.map +1 -1
  84. package/dist/client/chat/message-components.js +9 -3
  85. package/dist/client/chat/message-components.js.map +1 -1
  86. package/dist/client/chat/tool-call-display.d.ts +3 -1
  87. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  88. package/dist/client/chat/tool-call-display.js +10 -2
  89. package/dist/client/chat/tool-call-display.js.map +1 -1
  90. package/dist/client/extensions/EmbeddedExtension.js +2 -6
  91. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  92. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  93. package/dist/client/extensions/ExtensionViewer.js +2 -59
  94. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  95. package/dist/client/index.d.ts +2 -0
  96. package/dist/client/index.d.ts.map +1 -1
  97. package/dist/client/index.js +2 -0
  98. package/dist/client/index.js.map +1 -1
  99. package/dist/client/settings/DemoModeSection.d.ts +1 -13
  100. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  101. package/dist/client/settings/DemoModeSection.js +5 -52
  102. package/dist/client/settings/DemoModeSection.js.map +1 -1
  103. package/dist/client/settings/SettingsPanel.js +1 -1
  104. package/dist/client/settings/SettingsPanel.js.map +1 -1
  105. package/dist/client/use-db-sync.d.ts.map +1 -1
  106. package/dist/client/use-db-sync.js +3 -7
  107. package/dist/client/use-db-sync.js.map +1 -1
  108. package/dist/client/use-demo-mode-status.d.ts +3 -4
  109. package/dist/client/use-demo-mode-status.d.ts.map +1 -1
  110. package/dist/client/use-demo-mode-status.js +8 -23
  111. package/dist/client/use-demo-mode-status.js.map +1 -1
  112. package/dist/collab/awareness.d.ts +2 -2
  113. package/dist/collab/awareness.d.ts.map +1 -1
  114. package/dist/collab/routes.d.ts +1 -1
  115. package/dist/collab/struct-routes.d.ts +1 -1
  116. package/dist/demo/browser-state.d.ts +10 -0
  117. package/dist/demo/browser-state.d.ts.map +1 -0
  118. package/dist/demo/browser-state.js +49 -0
  119. package/dist/demo/browser-state.js.map +1 -0
  120. package/dist/demo/fetch-interceptor.d.ts +2 -7
  121. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  122. package/dist/demo/fetch-interceptor.js +12 -56
  123. package/dist/demo/fetch-interceptor.js.map +1 -1
  124. package/dist/deploy/workspace-deploy.js +2 -2
  125. package/dist/deploy/workspace-deploy.js.map +1 -1
  126. package/dist/notifications/routes.d.ts +2 -2
  127. package/dist/progress/routes.d.ts +1 -1
  128. package/dist/resources/handlers.d.ts +3 -3
  129. package/dist/server/action-discovery.d.ts.map +1 -1
  130. package/dist/server/action-discovery.js +0 -1
  131. package/dist/server/action-discovery.js.map +1 -1
  132. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  133. package/dist/server/core-routes-plugin.js +0 -27
  134. package/dist/server/core-routes-plugin.js.map +1 -1
  135. package/dist/server/transcribe-voice.d.ts +1 -1
  136. package/dist/templates/workspace-core/.agents/skills/native-navigation/SKILL.md +67 -0
  137. package/package.json +1 -1
  138. package/src/templates/workspace-core/.agents/skills/native-navigation/SKILL.md +67 -0
  139. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +0 -23
  140. package/corpus/core/src/demo/config.ts +0 -57
  141. package/dist/demo/actions/toggle-demo-mode.d.ts +0 -8
  142. package/dist/demo/actions/toggle-demo-mode.d.ts.map +0 -1
  143. package/dist/demo/actions/toggle-demo-mode.js +0 -21
  144. package/dist/demo/actions/toggle-demo-mode.js.map +0 -1
  145. package/dist/demo/config.d.ts +0 -9
  146. package/dist/demo/config.d.ts.map +0 -1
  147. package/dist/demo/config.js +0 -58
  148. package/dist/demo/config.js.map +0 -1
@@ -35,7 +35,13 @@ import {
35
35
  } from "@tabler/icons-react";
36
36
  import { useQuery } from "@tanstack/react-query";
37
37
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
38
- import { useParams, useNavigate, NavLink, useSearchParams } from "react-router";
38
+ import {
39
+ Link,
40
+ useParams,
41
+ useNavigate,
42
+ NavLink,
43
+ useSearchParams,
44
+ } from "react-router";
39
45
  import { toast } from "sonner";
40
46
 
41
47
  import { EditableRecordingTitle } from "@/components/editable-recording-title";
@@ -712,8 +718,8 @@ export default function RecordingPage() {
712
718
  {(playerDataQ.error as Error | undefined)?.message ??
713
719
  t("recordingPage.noAccess")}
714
720
  </p>
715
- <Button onClick={() => navigate("/")} variant="outline">
716
- {t("recordingPage.backToLibrary")}
721
+ <Button asChild variant="outline">
722
+ <Link to="/">{t("recordingPage.backToLibrary")}</Link>
717
723
  </Button>
718
724
  </div>
719
725
  );
@@ -772,13 +778,15 @@ export default function RecordingPage() {
772
778
  <div className="flex min-h-screen w-full flex-col bg-background">
773
779
  <header className="flex min-w-0 shrink-0 items-center gap-3 border-b border-border px-3 py-2 sm:px-4 sm:py-3">
774
780
  <Button
781
+ asChild
775
782
  variant="ghost"
776
783
  size="icon"
777
784
  className="shrink-0"
778
- onClick={() => navigate("/")}
779
785
  aria-label={t("recordingPage.back")}
780
786
  >
781
- <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
787
+ <Link to="/">
788
+ <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
789
+ </Link>
782
790
  </Button>
783
791
  <div className="min-w-0 flex-1">
784
792
  <p className="truncate text-sm font-medium">{visibleTitle}</p>
@@ -947,8 +955,8 @@ export default function RecordingPage() {
947
955
  : t("recordingPage.retryUpload")
948
956
  : t("recordingPage.checkAgain")}
949
957
  </Button>
950
- <Button onClick={() => navigate("/")} variant="ghost" size="sm">
951
- {t("recordingPage.backToLibrary")}
958
+ <Button asChild variant="ghost" size="sm">
959
+ <Link to="/">{t("recordingPage.backToLibrary")}</Link>
952
960
  </Button>
953
961
  </div>
954
962
  </div>
@@ -1122,13 +1130,15 @@ export default function RecordingPage() {
1122
1130
  <div className="flex w-full min-w-0 flex-col xl:flex-1">
1123
1131
  <header className="flex min-w-0 shrink-0 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-4 sm:py-3">
1124
1132
  <Button
1133
+ asChild
1125
1134
  variant="ghost"
1126
1135
  size="icon"
1127
1136
  className="shrink-0"
1128
- onClick={() => navigate("/")}
1129
1137
  aria-label={t("recordingPage.back")}
1130
1138
  >
1131
- <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
1139
+ <Link to="/">
1140
+ <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
1141
+ </Link>
1132
1142
  </Button>
1133
1143
  <div className="flex-1 min-w-0">
1134
1144
  <EditableRecordingTitle
@@ -32,7 +32,7 @@ import {
32
32
  type LoaderFunctionArgs,
33
33
  type MetaFunction,
34
34
  } from "react-router";
35
- import { useLoaderData, useNavigate, useParams } from "react-router";
35
+ import { Link, useLoaderData, useNavigate, useParams } from "react-router";
36
36
  import { toast } from "sonner";
37
37
 
38
38
  import { CaptureInstallButton } from "@/components/capture-install-options";
@@ -817,12 +817,14 @@ export default function ShareRoute() {
817
817
  <header className="flex min-w-0 shrink-0 flex-wrap items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-4 sm:py-3 lg:flex-nowrap">
818
818
  {session ? (
819
819
  <Button
820
+ asChild
820
821
  variant="ghost"
821
822
  size="icon"
822
- onClick={() => navigate("/")}
823
823
  aria-label={t("sharePage.backToHome")}
824
824
  >
825
- <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
825
+ <Link to="/">
826
+ <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
827
+ </Link>
826
828
  </Button>
827
829
  ) : null}
828
830
  <div className="min-w-0 flex-1">
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Recording cards and player back links now support opening in a new tab.
@@ -1,7 +1,7 @@
1
1
  import { useT } from "@agent-native/core/client";
2
2
  import { IconExternalLink, IconFileText } from "@tabler/icons-react";
3
3
  import { lazy, Suspense, useMemo } from "react";
4
- import { useNavigate } from "react-router";
4
+ import { Link } from "react-router";
5
5
 
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { useDocument, useDocuments } from "@/hooks/use-documents";
@@ -66,7 +66,6 @@ export function ContentReferencePreview({
66
66
  referenceDepth?: number;
67
67
  }) {
68
68
  const t = useT();
69
- const navigate = useNavigate();
70
69
  const documentsQuery = useDocuments();
71
70
  const resolvedPath = useMemo(
72
71
  () => resolveContentReferencePath(sourcePath, currentPath),
@@ -113,16 +112,15 @@ export function ContentReferencePreview({
113
112
  </div>
114
113
  {document ? (
115
114
  <Button
116
- type="button"
115
+ asChild
117
116
  size="sm"
118
117
  variant="ghost"
119
118
  className="h-8 gap-1.5 px-2 text-xs"
120
- onClick={() =>
121
- navigate(`/page/${document.id}`, { flushSync: true })
122
- }
123
119
  >
124
- <IconExternalLink className="size-3.5" />
125
- {t("editor.reference.open")}
120
+ <Link to={`/page/${document.id}`}>
121
+ <IconExternalLink className="size-3.5" />
122
+ {t("editor.reference.open")}
123
+ </Link>
126
124
  </Button>
127
125
  ) : null}
128
126
  </div>
@@ -139,7 +139,7 @@ import {
139
139
  type PointerEvent as ReactPointerEvent,
140
140
  type ReactNode,
141
141
  } from "react";
142
- import { useLocation, useNavigate } from "react-router";
142
+ import { Link, useLocation, useNavigate } from "react-router";
143
143
  import { toast } from "sonner";
144
144
 
145
145
  import {
@@ -1670,14 +1670,16 @@ function DatabaseTable({
1670
1670
  <Tooltip>
1671
1671
  <TooltipTrigger asChild>
1672
1672
  <Button
1673
+ asChild
1673
1674
  type="button"
1674
1675
  variant="ghost"
1675
1676
  size="sm"
1676
1677
  aria-label={dbText("openAsFullPage")}
1677
1678
  className={databaseToolbarIconButtonClass()}
1678
- onClick={() => navigate(`/page/${databaseDocumentId}`)}
1679
1679
  >
1680
- <IconArrowsDiagonal className="size-3.5" />
1680
+ <Link to={`/page/${databaseDocumentId}`}>
1681
+ <IconArrowsDiagonal className="size-3.5" />
1682
+ </Link>
1681
1683
  </Button>
1682
1684
  </TooltipTrigger>
1683
1685
  <TooltipContent>{dbText("openAsFullPage")}</TooltipContent>
@@ -12,7 +12,7 @@ import {
12
12
  IconExternalLink,
13
13
  } from "@tabler/icons-react";
14
14
  import { useMemo, useState } from "react";
15
- import { useNavigate } from "react-router";
15
+ import { Link, useNavigate } from "react-router";
16
16
 
17
17
  import { Button } from "@/components/ui/button";
18
18
  import {
@@ -362,14 +362,11 @@ export function DatabaseFormView({
362
362
  {t("database.formSubmittedDescription")}
363
363
  </div>
364
364
  </div>
365
- <Button
366
- type="button"
367
- variant="outline"
368
- size="sm"
369
- onClick={() => navigate(`/page/${createdDocumentId}`)}
370
- >
371
- <IconExternalLink className="size-4" />
372
- {t("database.openPage")}
365
+ <Button asChild type="button" variant="outline" size="sm">
366
+ <Link to={`/page/${createdDocumentId}`}>
367
+ <IconExternalLink className="size-4" />
368
+ {t("database.openPage")}
369
+ </Link>
373
370
  </Button>
374
371
  </div>
375
372
  ) : null}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Document links now support opening in a new tab.
@@ -1,4 +1,8 @@
1
1
  import { usePinchZoom, useT } from "@agent-native/core/client";
2
+ import {
3
+ injectSessionReplayIframeBootstrap,
4
+ SESSION_REPLAY_IFRAME_ATTRIBUTE,
5
+ } from "@agent-native/core/client";
2
6
  import {
3
7
  DEFAULT_CANVAS_MAX_ZOOM,
4
8
  DEFAULT_CANVAS_MIN_ZOOM,
@@ -2098,24 +2102,32 @@ export function DesignCanvas({
2098
2102
  contentOffsetX: embeddedFrame?.contentOffsetX ?? 0,
2099
2103
  contentOffsetY: embeddedFrame?.contentOffsetY ?? 0,
2100
2104
  });
2105
+ let frameDocument: string;
2101
2106
  if (frameContent.includes("</body>")) {
2102
- return frameContent.replace("</body>", bridgeToInject + "</body>"); // i18n-ignore generated iframe HTML injection
2103
- }
2104
- if (frameContent.includes("</html>")) {
2105
- return frameContent.replace("</html>", bridgeToInject + "</html>"); // i18n-ignore generated iframe HTML injection
2107
+ frameDocument = frameContent.replace(
2108
+ "</body>", // i18n-ignore generated iframe HTML injection
2109
+ bridgeToInject + "</body>", // i18n-ignore generated iframe HTML injection
2110
+ ); // i18n-ignore generated iframe HTML injection
2111
+ } else if (frameContent.includes("</html>")) {
2112
+ frameDocument = frameContent.replace(
2113
+ "</html>", // i18n-ignore generated iframe HTML injection
2114
+ bridgeToInject + "</html>", // i18n-ignore generated iframe HTML injection
2115
+ ); // i18n-ignore generated iframe HTML injection
2116
+ } else {
2117
+ // No body/html tags — wrap it
2118
+ const frameStyle = [
2119
+ getEmbeddedFrameBackgroundStyle({
2120
+ embeddedFrameBackground,
2121
+ transparentBackground,
2122
+ }),
2123
+ embeddedContentOffsetStyle(
2124
+ embeddedFrame?.contentOffsetX ?? 0,
2125
+ embeddedFrame?.contentOffsetY ?? 0,
2126
+ ),
2127
+ ].join("");
2128
+ frameDocument = `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">${frameStyle}</head><body>${iframeRenderContent}${bridgeToInject}</body></html>`;
2106
2129
  }
2107
- // No body/html tags — wrap it
2108
- const frameStyle = [
2109
- getEmbeddedFrameBackgroundStyle({
2110
- embeddedFrameBackground,
2111
- transparentBackground,
2112
- }),
2113
- embeddedContentOffsetStyle(
2114
- embeddedFrame?.contentOffsetX ?? 0,
2115
- embeddedFrame?.contentOffsetY ?? 0,
2116
- ),
2117
- ].join("");
2118
- return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">${frameStyle}</head><body>${iframeRenderContent}${bridgeToInject}</body></html>`;
2130
+ return injectSessionReplayIframeBootstrap(frameDocument);
2119
2131
  // editorChromeScaleX/Y are intentionally NOT deps: they only seed the initial
2120
2132
  // baked chrome scale. Live zoom updates flow through the set-editor-chrome-scale
2121
2133
  // postMessage above. Including them here rebuilds srcdoc on every zoom commit,
@@ -4081,6 +4093,11 @@ export function DesignCanvas({
4081
4093
  readOnly,
4082
4094
  })}
4083
4095
  data-design-preview-iframe
4096
+ {...{
4097
+ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: !externalPreviewUrl
4098
+ ? ""
4099
+ : undefined,
4100
+ }}
4084
4101
  data-screen-iframe-id={
4085
4102
  boardSurface ? undefined : (previewFrameId ?? screenId ?? undefined)
4086
4103
  }
@@ -1,4 +1,8 @@
1
1
  import { useT } from "@agent-native/core/client";
2
+ import {
3
+ injectSessionReplayIframeBootstrap,
4
+ SESSION_REPLAY_IFRAME_ATTRIBUTE,
5
+ } from "@agent-native/core/client";
2
6
  import {
3
7
  DEFAULT_CANVAS_MAX_ZOOM,
4
8
  DEFAULT_CANVAS_MIN_ZOOM,
@@ -9048,7 +9052,10 @@ const Screen = memo(function Screen({
9048
9052
  // rebuild the string every render (that would reload the iframe).
9049
9053
  // Keyed only on screen.content; the hit-test script itself is constant.
9050
9054
  const srcdocWithHitTest = useMemo(
9051
- () => appendHitTestResponder(screen.content),
9055
+ () =>
9056
+ injectSessionReplayIframeBootstrap(
9057
+ appendHitTestResponder(screen.content),
9058
+ ),
9052
9059
  // eslint-disable-next-line react-hooks/exhaustive-deps
9053
9060
  [screen.content],
9054
9061
  );
@@ -9331,6 +9338,11 @@ const Screen = memo(function Screen({
9331
9338
  ) : (
9332
9339
  (screenContent ?? (
9333
9340
  <iframe
9341
+ {...{
9342
+ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: previewUrl
9343
+ ? undefined
9344
+ : "",
9345
+ }}
9334
9346
  data-screen-iframe-id={screen.id}
9335
9347
  src={previewUrl}
9336
9348
  srcDoc={previewUrl ? undefined : srcdocWithHitTest}
@@ -9989,6 +10001,11 @@ function BreakpointPreviewRow({
9989
10001
  screen.id,
9990
10002
  widthPx,
9991
10003
  )}
10004
+ {...{
10005
+ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: previewUrl
10006
+ ? undefined
10007
+ : "",
10008
+ }}
9992
10009
  src={previewUrl}
9993
10010
  srcDoc={previewUrl ? undefined : srcdocWithHitTest}
9994
10011
  sandbox="allow-scripts"
@@ -23,7 +23,7 @@ import {
23
23
  IconExternalLink,
24
24
  } from "@tabler/icons-react";
25
25
  import { useState, useCallback, useRef, useMemo, useEffect } from "react";
26
- import { useNavigate, useSearchParams } from "react-router";
26
+ import { Link, useNavigate, useSearchParams } from "react-router";
27
27
  import { toast } from "sonner";
28
28
 
29
29
  import { Button } from "@/components/ui/button";
@@ -504,13 +504,13 @@ export default function DesignSystemSetup() {
504
504
 
505
505
  useSetPageTitle(
506
506
  <div className="flex items-center gap-2 min-w-0">
507
- <button
508
- onClick={() => navigate("/design-systems")}
507
+ <Link
508
+ to="/design-systems"
509
509
  className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground/90"
510
510
  aria-label={t("designSystemSetup.backToDesignSystems")}
511
511
  >
512
512
  <IconArrowLeft className="w-4 h-4" />
513
- </button>
513
+ </Link>
514
514
  <h1 className="text-lg font-semibold tracking-tight truncate">
515
515
  {t("navigation.setupDesignSystem")}
516
516
  </h1>
@@ -412,13 +412,11 @@ export default function DesignSystems() {
412
412
  : t("designSystems.actions.select")}
413
413
  </Button>
414
414
  ) : null}
415
- <Button
416
- size="sm"
417
- onClick={() => navigate("/design-systems/setup")}
418
- className="cursor-pointer"
419
- >
420
- <IconPlus className="w-3.5 h-3.5" />
421
- {t("designSystems.actions.new")}
415
+ <Button asChild size="sm" className="cursor-pointer">
416
+ <Link to="/design-systems/setup">
417
+ <IconPlus className="w-3.5 h-3.5" />
418
+ {t("designSystems.actions.new")}
419
+ </Link>
422
420
  </Button>
423
421
  </div>,
424
422
  );
@@ -509,8 +507,8 @@ export default function DesignSystems() {
509
507
  </h2>
510
508
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
511
509
  {/* New design system card */}
512
- <button
513
- onClick={() => navigate("/design-systems/setup")}
510
+ <Link
511
+ to="/design-systems/setup"
514
512
  className="group relative rounded-xl border border-dashed border-border bg-card hover:border-foreground/15 overflow-hidden text-start cursor-pointer"
515
513
  >
516
514
  <div className="aspect-video flex items-center justify-center bg-muted/30">
@@ -526,7 +524,7 @@ export default function DesignSystems() {
526
524
  {t("designSystems.newCardDescription")}
527
525
  </div>
528
526
  </div>
529
- </button>
527
+ </Link>
530
528
 
531
529
  {/* Design system cards */}
532
530
  {designSystems.map((ds) => {
@@ -4,6 +4,10 @@ import {
4
4
  useT,
5
5
  } from "@agent-native/core/client";
6
6
  import type { PromptComposerSubmitOptions } from "@agent-native/core/client";
7
+ import {
8
+ injectSessionReplayIframeBootstrap,
9
+ SESSION_REPLAY_IFRAME_ATTRIBUTE,
10
+ } from "@agent-native/core/client";
7
11
  import {
8
12
  useSetHeaderActions,
9
13
  useSetPageTitle,
@@ -954,7 +958,8 @@ function DesignThumbnail({ html }: { html: string | null }) {
954
958
  className="aspect-video relative overflow-hidden bg-white"
955
959
  >
956
960
  <iframe
957
- srcDoc={html}
961
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
962
+ srcDoc={injectSessionReplayIframeBootstrap(html)}
958
963
  sandbox="allow-scripts"
959
964
  loading="lazy"
960
965
  tabIndex={-1}
@@ -1,6 +1,11 @@
1
- import { useActionQuery, useT } from "@agent-native/core/client";
1
+ import {
2
+ injectSessionReplayIframeBootstrap,
3
+ SESSION_REPLAY_IFRAME_ATTRIBUTE,
4
+ useActionQuery,
5
+ useT,
6
+ } from "@agent-native/core/client";
2
7
  import { useState, useEffect, useCallback } from "react";
3
- import { useParams, useNavigate } from "react-router";
8
+ import { Link, useParams, useNavigate } from "react-router";
4
9
 
5
10
  import { QueryErrorState } from "@/components/QueryErrorState";
6
11
  import { Skeleton } from "@/components/ui/skeleton";
@@ -84,12 +89,12 @@ export default function Present() {
84
89
  return (
85
90
  <div className="h-screen w-screen bg-black flex flex-col items-center justify-center gap-4">
86
91
  <p className="text-white/50 text-sm">{t("pages.presentEmpty")}</p>
87
- <button
88
- onClick={() => navigate(`/design/${id}`)}
92
+ <Link
93
+ to={`/design/${id}`}
89
94
  className="text-sm text-white/40 hover:text-white/60 underline cursor-pointer"
90
95
  >
91
96
  {t("pages.presentBackToEditor")}
92
- </button>
97
+ </Link>
93
98
  </div>
94
99
  );
95
100
  }
@@ -99,7 +104,8 @@ export default function Present() {
99
104
  return (
100
105
  <div className="h-screen w-screen bg-black overflow-hidden">
101
106
  <iframe
102
- srcDoc={activeFile.content}
107
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
108
+ srcDoc={injectSessionReplayIframeBootstrap(activeFile.content)}
103
109
  sandbox="allow-scripts"
104
110
  className="w-full h-full border-0"
105
111
  title={`${design.title} — ${activeFile.filename}`}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Design navigation links now support opening in a new tab.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Design session replays now include activity inside the preview canvas and presentation frames.
@@ -41,7 +41,7 @@ import {
41
41
  import { format } from "date-fns";
42
42
  import { nanoid } from "nanoid";
43
43
  import { useState, useCallback, useRef, useEffect } from "react";
44
- import { useParams, useNavigate, useSearchParams } from "react-router";
44
+ import { Link, useParams, useNavigate, useSearchParams } from "react-router";
45
45
  import { toast } from "sonner";
46
46
 
47
47
  import { FieldPropertiesPanel } from "@/components/builder/FieldPropertiesPanel";
@@ -338,13 +338,15 @@ export function FormBuilderPage() {
338
338
  <Tooltip>
339
339
  <TooltipTrigger asChild>
340
340
  <Button
341
+ asChild
341
342
  variant="ghost"
342
343
  size="icon"
343
344
  className="size-10 shrink-0 active:scale-[0.96]"
344
- onClick={() => navigate("/forms")}
345
345
  aria-label={t("builder.backToForms")}
346
346
  >
347
- <IconArrowLeft className="h-4 w-4" />
347
+ <Link to="/forms">
348
+ <IconArrowLeft className="h-4 w-4" />
349
+ </Link>
348
350
  </Button>
349
351
  </TooltipTrigger>
350
352
  <TooltipContent>{t("builder.backToForms")}</TooltipContent>
@@ -399,12 +401,8 @@ export function FormBuilderPage() {
399
401
  {isAccessIssue ? t("builder.accessDenied") : t("builder.loadFailed")}
400
402
  </p>
401
403
  <div className="flex gap-2">
402
- <Button
403
- variant="outline"
404
- size="sm"
405
- onClick={() => navigate("/forms")}
406
- >
407
- {t("builder.backToForms")}
404
+ <Button asChild variant="outline" size="sm">
405
+ <Link to="/forms">{t("builder.backToForms")}</Link>
408
406
  </Button>
409
407
  {!isAccessIssue && (
410
408
  <Button variant="outline" size="sm" onClick={() => refetch()}>
@@ -557,13 +555,15 @@ export function FormBuilderPage() {
557
555
  <Tooltip>
558
556
  <TooltipTrigger asChild>
559
557
  <Button
558
+ asChild
560
559
  variant="ghost"
561
560
  size="icon"
562
561
  className="size-10 shrink-0 active:scale-[0.96]"
563
- onClick={() => navigate("/forms")}
564
562
  aria-label={t("builder.backToForms")}
565
563
  >
566
- <IconArrowLeft className="h-4 w-4" />
564
+ <Link to="/forms">
565
+ <IconArrowLeft className="h-4 w-4" />
566
+ </Link>
567
567
  </Button>
568
568
  </TooltipTrigger>
569
569
  <TooltipContent>{t("builder.backToForms")}</TooltipContent>
@@ -22,7 +22,7 @@ import {
22
22
  IconX,
23
23
  } from "@tabler/icons-react";
24
24
  import { useEffect, useMemo, useState } from "react";
25
- import { useNavigate } from "react-router";
25
+ import { Link, useNavigate } from "react-router";
26
26
  import { toast } from "sonner";
27
27
 
28
28
  import { CloudUpgrade } from "@/components/CloudUpgrade";
@@ -294,23 +294,21 @@ export function FormsListPage() {
294
294
  if (error && !forms?.length) {
295
295
  const status = (error as { status?: number })?.status;
296
296
  if (status === 401) {
297
+ const next = encodeURIComponent(
298
+ window.location.pathname + window.location.search,
299
+ );
297
300
  return (
298
301
  <div className="flex flex-col items-center justify-center h-full gap-3">
299
302
  <p className="text-sm text-muted-foreground">
300
303
  {t("forms.signInPrompt")}
301
304
  </p>
302
305
  <Button
306
+ asChild
303
307
  variant="outline"
304
308
  size="sm"
305
309
  className="min-h-10 active:scale-[0.96] transition-[background-color,box-shadow,transform]"
306
- onClick={() => {
307
- const next = encodeURIComponent(
308
- window.location.pathname + window.location.search,
309
- );
310
- window.location.href = `/login?next=${next}`;
311
- }}
312
310
  >
313
- {t("common.signIn")}
311
+ <Link to={`/login?next=${next}`}>{t("common.signIn")}</Link>
314
312
  </Button>
315
313
  </div>
316
314
  );
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Form navigation links now support opening in a new tab.
@@ -10,7 +10,7 @@ import {
10
10
  IconX,
11
11
  } from "@tabler/icons-react";
12
12
  import { useEffect, useMemo, useState } from "react";
13
- import { useNavigate, useParams, useSearchParams } from "react-router";
13
+ import { Link, useNavigate, useParams, useSearchParams } from "react-router";
14
14
  import { toast } from "sonner";
15
15
 
16
16
  import { Button } from "@/components/ui/button";
@@ -732,13 +732,8 @@ export function DraftQueuePage() {
732
732
  <p className="text-sm font-medium text-foreground">
733
733
  {t("mail.draftQueue.needsOrg")}
734
734
  </p>
735
- <Button
736
- variant="outline"
737
- size="sm"
738
- className="mt-3"
739
- onClick={() => navigate("/settings")}
740
- >
741
- {t("mail.draftQueue.openSettings")}
735
+ <Button asChild variant="outline" size="sm" className="mt-3">
736
+ <Link to="/settings">{t("mail.draftQueue.openSettings")}</Link>
742
737
  </Button>
743
738
  </div>
744
739
  </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Settings links now support opening in a new tab.