@agent-native/core 0.165.4 → 0.167.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 (223) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +5 -1
  3. package/corpus/templates/analytics/.agents/skills/workspace-conventions/SKILL.md +4 -1
  4. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +93 -56
  5. package/corpus/templates/analytics/app/i18n-data.ts +23 -20
  6. package/corpus/templates/analytics/app/pages/Settings.tsx +0 -1
  7. package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +0 -1
  8. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +1 -1
  9. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +2 -1
  10. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +0 -1
  11. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +0 -32
  12. package/corpus/templates/analytics/server/lib/session-replay.ts +1 -5
  13. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +5 -1
  14. package/corpus/templates/assets/.agents/skills/workspace-conventions/SKILL.md +4 -1
  15. package/corpus/templates/assets/actions/navigate.ts +2 -2
  16. package/corpus/templates/assets/actions/save-generated-image.ts +0 -5
  17. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +2 -262
  18. package/corpus/templates/assets/app/routes/library.tsx +1 -1
  19. package/corpus/templates/assets/app/routes/settings.tsx +0 -3
  20. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +5 -1
  21. package/corpus/templates/brain/.agents/skills/workspace-conventions/SKILL.md +4 -1
  22. package/corpus/templates/brain/actions/ask-brain.ts +0 -1
  23. package/corpus/templates/brain/actions/navigate.ts +2 -2
  24. package/corpus/templates/brain/app/routes/sources.tsx +0 -4
  25. package/corpus/templates/brain/server/lib/capture-sanitization.ts +0 -11
  26. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +5 -1
  27. package/corpus/templates/calendar/.agents/skills/workspace-conventions/SKILL.md +4 -1
  28. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +0 -20
  29. package/corpus/templates/calendar/app/pages/CalendarView.tsx +0 -1
  30. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +5 -1
  31. package/corpus/templates/chat/.agents/skills/workspace-conventions/SKILL.md +4 -1
  32. package/corpus/templates/chat/actions/navigate.ts +2 -2
  33. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +5 -1
  34. package/corpus/templates/clips/.agents/skills/workspace-conventions/SKILL.md +4 -1
  35. package/corpus/templates/clips/CHANGELOG.md +1 -0
  36. package/corpus/templates/clips/actions/import-loom-recording.ts +16 -4
  37. package/corpus/templates/clips/actions/navigate.ts +2 -2
  38. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +0 -1
  39. package/corpus/templates/clips/app/components/library/space-dialogs.tsx +0 -1
  40. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +0 -1
  41. package/corpus/templates/clips/app/components/player/clips-share-trigger.tsx +17 -0
  42. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +3 -3
  43. package/corpus/templates/clips/app/components/player/video-player.tsx +2 -2
  44. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +0 -1
  45. package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +0 -1
  46. package/corpus/templates/clips/app/global.css +31 -0
  47. package/corpus/templates/clips/app/hooks/use-playback-position.ts +0 -2
  48. package/corpus/templates/clips/app/lib/download-release-channel.ts +10 -0
  49. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +1 -3
  50. package/corpus/templates/clips/app/routes/download.tsx +67 -44
  51. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -12
  52. package/corpus/templates/clips/app/routes/record.tsx +6 -6
  53. package/corpus/templates/clips/app/routes/share.$shareId.tsx +26 -29
  54. package/corpus/templates/clips/changelog/2026-08-20-clip-viewer-share-actions.md +6 -0
  55. package/corpus/templates/clips/changelog/2026-08-20-preparing-recording-countdown-overlay.md +1 -0
  56. package/corpus/templates/clips/chrome-extension/src/background.ts +0 -13
  57. package/corpus/templates/clips/chrome-extension/src/overlay.ts +0 -1
  58. package/corpus/templates/clips/chrome-extension/src/popup.ts +0 -20
  59. package/corpus/templates/clips/desktop/src/app.tsx +6 -18
  60. package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +0 -1
  61. package/corpus/templates/clips/desktop/src/lib/recorder.ts +0 -8
  62. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +5 -1
  63. package/corpus/templates/content/.agents/skills/workspace-conventions/SKILL.md +4 -1
  64. package/corpus/templates/content/actions/_database-source-utils.ts +0 -3
  65. package/corpus/templates/content/actions/attach-content-database-source.ts +1 -4
  66. package/corpus/templates/content/actions/navigate.ts +2 -2
  67. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +1 -1
  68. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +0 -6
  69. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +0 -580
  70. package/corpus/templates/content/app/components/editor/database/FormView.tsx +2 -2
  71. package/corpus/templates/content/app/components/editor/database/filter-sort.ts +1 -1
  72. package/corpus/templates/content/app/components/editor/database/settings.tsx +0 -23
  73. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +0 -1
  74. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +8 -304
  75. package/corpus/templates/content/app/hooks/use-documents.ts +0 -1
  76. package/corpus/templates/content/shared/api.ts +0 -1
  77. package/corpus/templates/content/shared/builder-mdx.ts +0 -1
  78. package/corpus/templates/content/shared/nfm.ts +1 -7
  79. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +5 -1
  80. package/corpus/templates/crm/.agents/skills/workspace-conventions/SKILL.md +4 -1
  81. package/corpus/templates/crm/actions/merge-crm-records.ts +0 -4
  82. package/corpus/templates/crm/app/components/crm/record/RecordLists.tsx +0 -1
  83. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +0 -1
  84. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +0 -1
  85. package/corpus/templates/crm/server/db/crm-store.ts +1 -1
  86. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +5 -1
  87. package/corpus/templates/design/.agents/skills/workspace-conventions/SKILL.md +4 -1
  88. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -14
  89. package/corpus/templates/design/AGENTS.md +2 -1
  90. package/corpus/templates/design/actions/apply-component-prop-edit.ts +1 -5
  91. package/corpus/templates/design/actions/generate-design.ts +0 -1
  92. package/corpus/templates/design/actions/generate-screens.ts +5 -2
  93. package/corpus/templates/design/actions/go-to-main-component.ts +2 -2
  94. package/corpus/templates/design/actions/list-design-systems.ts +10 -0
  95. package/corpus/templates/design/actions/navigate.ts +2 -2
  96. package/corpus/templates/design/actions/open-component-source.ts +4 -4
  97. package/corpus/templates/design/actions/present-design-variants.ts +1 -2
  98. package/corpus/templates/design/actions/run-design-audit.ts +0 -22
  99. package/corpus/templates/design/actions/show-design-questions.ts +5 -2
  100. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +19 -8
  101. package/corpus/templates/design/app/components/design/EditPanel.tsx +11 -183
  102. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +21 -4
  103. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +1 -5
  104. package/corpus/templates/design/app/components/design/bridge/codegen.ts +1 -1
  105. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +10 -19
  106. package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +1 -1
  107. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +13 -3
  108. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +38 -32
  109. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +1 -4
  110. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +0 -4
  111. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +15 -6
  112. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +2 -2
  113. package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +0 -1
  114. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +1 -1
  115. package/corpus/templates/design/app/i18n-data.ts +122 -0
  116. package/corpus/templates/design/app/lib/clipboard-content-lineage.ts +11 -1
  117. package/corpus/templates/design/app/pages/DesignEditor.tsx +50 -254
  118. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +163 -8
  119. package/corpus/templates/design/app/pages/Index.tsx +17 -0
  120. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +44 -32
  121. package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +10 -0
  122. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +49 -3
  123. package/corpus/templates/design/app/pages/design-editor/clone-idrefs.ts +31 -0
  124. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +28 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +3 -3
  126. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +44 -14
  127. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +16 -5
  128. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +1 -1
  129. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +1 -1
  130. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +1 -1
  131. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +1 -1
  132. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +142 -17
  133. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +1 -0
  134. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +1 -1
  135. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +1 -0
  136. package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +25 -9
  137. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +1 -0
  138. package/corpus/templates/design/app/pages/design-editor/measure-child-rects.ts +83 -0
  139. package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +66 -0
  140. package/corpus/templates/design/server/routes/[...page].get.ts +0 -1
  141. package/corpus/templates/design/shared/code-layer.ts +120 -70
  142. package/corpus/templates/design/shared/design-surface-index.ts +0 -1
  143. package/corpus/templates/design/shared/pen-path.ts +0 -4
  144. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +5 -1
  145. package/corpus/templates/dispatch/.agents/skills/workspace-conventions/SKILL.md +4 -1
  146. package/corpus/templates/dispatch/app/routes/integrations.tsx +0 -109
  147. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +5 -1
  148. package/corpus/templates/factory/.agents/skills/workspace-conventions/SKILL.md +4 -1
  149. package/corpus/templates/factory/actions/navigate.ts +2 -2
  150. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +0 -13
  151. package/corpus/templates/factory/app/routes/factory.tsx +0 -1
  152. package/corpus/templates/factory/server/factory-graph/store.ts +0 -1
  153. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +5 -1
  154. package/corpus/templates/forms/.agents/skills/workspace-conventions/SKILL.md +4 -1
  155. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +5 -1
  156. package/corpus/templates/macros/.agents/skills/workspace-conventions/SKILL.md +4 -1
  157. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +0 -1
  158. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +5 -1
  159. package/corpus/templates/mail/.agents/skills/workspace-conventions/SKILL.md +4 -1
  160. package/corpus/templates/mail/app/components/email/EmailList.tsx +0 -1
  161. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  162. package/corpus/templates/mail/shared/markdown.ts +3 -0
  163. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +5 -1
  164. package/corpus/templates/plan/.agents/skills/workspace-conventions/SKILL.md +4 -1
  165. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +5 -1
  166. package/corpus/templates/slides/.agents/skills/workspace-conventions/SKILL.md +4 -1
  167. package/corpus/templates/slides/actions/add-slide.ts +0 -1
  168. package/corpus/templates/slides/actions/list-decks.ts +1 -1
  169. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +1 -4
  170. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +0 -1
  171. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
  172. package/corpus/templates/slides/app/pages/DeckEditor.tsx +1 -6
  173. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +5 -1
  174. package/corpus/templates/tasks/.agents/skills/workspace-conventions/SKILL.md +4 -1
  175. package/corpus/templates/tasks/app/components/layout/Layout.tsx +0 -1
  176. package/corpus/templates/tasks/app/hooks/use-visible-task-fields.ts +1 -4
  177. package/corpus/templates/tasks/server/custom-fields/store.ts +1 -6
  178. package/corpus/templates/tasks/shared/list-screen-snapshot.ts +2 -2
  179. package/dist/agent/engine/registry.js +27 -14
  180. package/dist/agent/index.d.ts +1 -1
  181. package/dist/agent/production-agent.d.ts +19 -6
  182. package/dist/agent/production-agent.js +57 -16
  183. package/dist/agent/types.d.ts +3 -0
  184. package/dist/client/EnvironmentBadge.d.ts +1 -0
  185. package/dist/client/EnvironmentBadge.js +7 -0
  186. package/dist/collab/awareness.d.ts +2 -2
  187. package/dist/collab/routes.d.ts +1 -1
  188. package/dist/config.d.ts +11 -0
  189. package/dist/config.js +248 -0
  190. package/dist/deploy/build.js +12 -1
  191. package/dist/index.d.ts +1 -1
  192. package/dist/notifications/routes.d.ts +3 -3
  193. package/dist/observability/routes.d.ts +2 -2
  194. package/dist/progress/routes.d.ts +1 -1
  195. package/dist/resources/handlers.d.ts +2 -2
  196. package/dist/server/agent-chat/plugin-options.d.ts +3 -2
  197. package/dist/server/agent-chat-plugin.js +5 -2
  198. package/dist/server/index.d.ts +1 -1
  199. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +5 -1
  200. package/dist/templates/chat/.agents/skills/workspace-conventions/SKILL.md +4 -1
  201. package/dist/templates/chat/actions/navigate.ts +2 -2
  202. package/dist/templates/default/.agents/skills/secrets/SKILL.md +5 -1
  203. package/dist/templates/default/.agents/skills/workspace-conventions/SKILL.md +4 -1
  204. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +5 -1
  205. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +5 -1
  206. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -1
  207. package/dist/vite/agent-native-config-loader.d.ts +1 -0
  208. package/dist/vite/agent-native-config-loader.js +3 -3
  209. package/dist/vite/agents-bundle-plugin.d.ts +1 -1
  210. package/dist/vite/agents-bundle-plugin.js +13 -1
  211. package/dist/vite/client.js +14 -14
  212. package/docs/content/agent-native-config.mdx +62 -11
  213. package/docs/content/agent-surfaces.mdx +6 -0
  214. package/docs/content/environment-variables.mdx +5 -2
  215. package/package.json +3 -3
  216. package/src/templates/chat/.agents/skills/secrets/SKILL.md +5 -1
  217. package/src/templates/chat/.agents/skills/workspace-conventions/SKILL.md +4 -1
  218. package/src/templates/chat/actions/navigate.ts +2 -2
  219. package/src/templates/default/.agents/skills/secrets/SKILL.md +5 -1
  220. package/src/templates/default/.agents/skills/workspace-conventions/SKILL.md +4 -1
  221. package/src/templates/headless/.agents/skills/secrets/SKILL.md +5 -1
  222. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +5 -1
  223. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +4 -1
@@ -1,6 +1,6 @@
1
1
  import { useActionMutation } from "@agent-native/core/client/hooks";
2
2
  import { useT } from "@agent-native/core/client/i18n";
3
- import { IconDots, IconDownload, IconTrash } from "@tabler/icons-react";
3
+ import { IconDotsVertical, IconDownload, IconTrash } from "@tabler/icons-react";
4
4
  import { useCallback, useRef, useState } from "react";
5
5
  import { toast } from "sonner";
6
6
 
@@ -93,10 +93,10 @@ export function RecordingOptionsMenu({
93
93
  <Button
94
94
  variant="ghost"
95
95
  size="icon"
96
- className="shrink-0"
96
+ className="-mx-1.5 h-auto w-auto shrink-0 px-0.5 py-1.5"
97
97
  aria-label={t("deleteRecordingMenu.clipOptions")}
98
98
  >
99
- <IconDots className="h-4 w-4" />
99
+ <IconDotsVertical className="h-4 w-4" />
100
100
  </Button>
101
101
  </DropdownMenuTrigger>
102
102
  <DropdownMenuContent align="end" className="w-44">
@@ -399,7 +399,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
399
399
  const [isFullscreen, setIsFullscreen] = useState(false);
400
400
  const nativeFullscreenRef = useRef(false);
401
401
  const [isPip, setIsPip] = useState(false);
402
- const [canPlay, setCanPlay] = useState(false);
402
+ const [, setCanPlay] = useState(false);
403
403
  const [isPlayPending, setIsPlayPending] = useState(false);
404
404
  const [isBuffering, setIsBuffering] = useState(false);
405
405
  const [playError, setPlayError] = useState<string | null>(null);
@@ -467,7 +467,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
467
467
  // first frame of a freshly-finalized clip so the user doesn't see a blank
468
468
  // black rectangle. Hidden on loadeddata / canplay / currentTime > 0, or
469
469
  // after a 10s safety timeout.
470
- const [isPreparing, setIsPreparing] = useState<boolean>(!!videoUrl);
470
+ const [, setIsPreparing] = useState<boolean>(!!videoUrl);
471
471
  const edits = useMemo(() => parseEdits(editsJson), [editsJson]);
472
472
  const hasEditorThumbnail = Boolean(edits.thumbnail);
473
473
  const [shouldRefreshAutoThumbnail, setShouldRefreshAutoThumbnail] =
@@ -11,7 +11,6 @@ import {
11
11
  import {
12
12
  SCREEN_CAPTURE_FRAME_RATE,
13
13
  screenCaptureDisplayOptions,
14
- screenCaptureVideoConstraints,
15
14
  } from "@shared/recording-capture";
16
15
  import {
17
16
  chunkUploadUrl,
@@ -15,7 +15,6 @@ import {
15
15
  IconBolt,
16
16
  IconCheck,
17
17
  IconExternalLink,
18
- IconKey,
19
18
  IconLoader2,
20
19
  } from "@tabler/icons-react";
21
20
  import { useState } from "react";
@@ -73,6 +73,10 @@
73
73
  --highlight-foreground: 0 0% 10%;
74
74
  }
75
75
 
76
+ .dark .clips-share-trigger {
77
+ --primary: 0 0% 100%;
78
+ }
79
+
76
80
  @theme inline {
77
81
  --color-highlight: hsl(var(--highlight));
78
82
  --color-highlight-foreground: hsl(var(--highlight-foreground));
@@ -148,6 +152,33 @@
148
152
  animation: clips-collapsible-up 120ms ease-out;
149
153
  }
150
154
 
155
+ .clips-share-content {
156
+ container: clips-share-content / inline-size;
157
+ }
158
+
159
+ .clips-share-metadata-description {
160
+ order: 2;
161
+ }
162
+
163
+ .clips-share-metadata-actions {
164
+ order: 1;
165
+ }
166
+
167
+ @container clips-share-content (min-width: 860px) {
168
+ .clips-share-metadata {
169
+ align-items: flex-start;
170
+ flex-direction: row;
171
+ }
172
+
173
+ .clips-share-metadata-description {
174
+ order: 1;
175
+ }
176
+
177
+ .clips-share-metadata-actions {
178
+ order: 2;
179
+ }
180
+ }
181
+
151
182
  @media (prefers-reduced-motion: reduce) {
152
183
  .clips-collapsible-content[data-state] {
153
184
  animation-duration: 1ms;
@@ -48,7 +48,6 @@ export function usePlaybackPosition({
48
48
  let restoreApplied = false;
49
49
  let saveInFlight = false;
50
50
  let pendingSave: { positionMs: number; keepalive: boolean } | null = null;
51
- let lastSavedPositionMs = -1;
52
51
  let lastSavedAt = -SAVE_INTERVAL_MS;
53
52
  let removePendingRestoreListeners: (() => void) | null = null;
54
53
 
@@ -80,7 +79,6 @@ export function usePlaybackPosition({
80
79
  }
81
80
 
82
81
  saveInFlight = true;
83
- lastSavedPositionMs = positionMs;
84
82
  lastSavedAt = now;
85
83
  void savePlaybackPosition(recordingId, positionMs, { keepalive })
86
84
  .catch((error) => {
@@ -0,0 +1,10 @@
1
+ export type DownloadReleaseChannel = "production" | "nightly";
2
+
3
+ export const BETA_CLIPS_HOSTNAME = "beta.clips.agent-native.com";
4
+
5
+ export function getDefaultDownloadChannel(
6
+ hostname: string | undefined,
7
+ ): DownloadReleaseChannel {
8
+ const normalized = hostname?.trim().toLowerCase().replace(/\.$/, "");
9
+ return normalized === BETA_CLIPS_HOSTNAME ? "nightly" : "production";
10
+ }
@@ -28,7 +28,6 @@ import { useEffect, useMemo, useRef, useState } from "react";
28
28
  import { NavLink, useNavigate, useParams } from "react-router";
29
29
  import { toast } from "sonner";
30
30
 
31
- import { CaptureInstallButton } from "@/components/capture-install-options";
32
31
  import { PageHeader } from "@/components/library/page-header";
33
32
  import {
34
33
  AttendeeStack,
@@ -69,7 +68,6 @@ import {
69
68
  TooltipContent,
70
69
  TooltipTrigger,
71
70
  } from "@/components/ui/tooltip";
72
- import { useDesktopPromo } from "@/hooks/use-desktop-promo";
73
71
  import enMessages from "@/i18n/en-US";
74
72
  import { cn } from "@/lib/utils";
75
73
 
@@ -499,7 +497,7 @@ export default function MeetingDetailRoute() {
499
497
  const stopMeetingRecording = useActionMutation<any, any>(
500
498
  "stop-meeting-recording",
501
499
  );
502
- const { isDesktopApp } = useDesktopPromo();
500
+
503
501
  const [notesJustArrived, setNotesJustArrived] = useState(false);
504
502
  const [deleteOpen, setDeleteOpen] = useState(false);
505
503
  const [endMeetingOpen, setEndMeetingOpen] = useState(false);
@@ -4,12 +4,20 @@ import {
4
4
  IconBrandChrome,
5
5
  IconBrandApple,
6
6
  IconBrandWindows,
7
+ IconChevronDown,
7
8
  IconDeviceDesktop,
8
9
  IconExternalLink,
9
10
  } from "@tabler/icons-react";
10
11
  import { useEffect, useState } from "react";
11
12
 
12
13
  import { Button } from "@/components/ui/button";
14
+ import {
15
+ DropdownMenu,
16
+ DropdownMenuContent,
17
+ DropdownMenuRadioGroup,
18
+ DropdownMenuRadioItem,
19
+ DropdownMenuTrigger,
20
+ } from "@/components/ui/dropdown-menu";
13
21
  import { Skeleton } from "@/components/ui/skeleton";
14
22
  import enMessages from "@/i18n/en-US";
15
23
  import {
@@ -17,6 +25,10 @@ import {
17
25
  markDesktopAppDownloaded,
18
26
  useClipsChromeExtensionEnabled,
19
27
  } from "@/lib/capture-install-options";
28
+ import {
29
+ getDefaultDownloadChannel,
30
+ type DownloadReleaseChannel,
31
+ } from "@/lib/download-release-channel";
20
32
 
21
33
  export function meta() {
22
34
  return [
@@ -29,7 +41,6 @@ export function meta() {
29
41
  }
30
42
 
31
43
  type PlatformId = "mac" | "windows" | "linux";
32
- type ReleaseChannel = "production" | "nightly";
33
44
 
34
45
  interface PlatformVariant {
35
46
  id: PlatformId;
@@ -204,7 +215,8 @@ function secondaryDownloadButton(
204
215
  export default function DownloadPage() {
205
216
  const chromeExtensionEnabled = useClipsChromeExtensionEnabled();
206
217
  const t = useT();
207
- const [channel, setChannel] = useState<ReleaseChannel>("production");
218
+ const [channel, setChannel] = useState<DownloadReleaseChannel>("production");
219
+ const [hostResolved, setHostResolved] = useState(false);
208
220
  const [manifest, setManifest] = useState<Manifest | null>(null);
209
221
  const [manifestError, setManifestError] = useState(false);
210
222
  const [detected, setDetected] = useState<PlatformId | null>(null);
@@ -215,6 +227,13 @@ export default function DownloadPage() {
215
227
  }, []);
216
228
 
217
229
  useEffect(() => {
230
+ setChannel(getDefaultDownloadChannel(window.location.hostname));
231
+ setHostResolved(true);
232
+ }, []);
233
+
234
+ useEffect(() => {
235
+ if (!hostResolved) return;
236
+
218
237
  let cancelled = false;
219
238
  setManifest(null);
220
239
  setManifestError(false);
@@ -233,13 +252,15 @@ export default function DownloadPage() {
233
252
  return () => {
234
253
  cancelled = true;
235
254
  };
236
- }, [channel, manifestRequest]);
255
+ }, [channel, hostResolved, manifestRequest]);
237
256
 
238
257
  const retryManifest = () => {
239
258
  setManifestRequest((request) => request + 1);
240
259
  };
241
260
 
242
- const handleChannelChange = (nextChannel: ReleaseChannel) => {
261
+ const handleChannelChange = (nextChannel: DownloadReleaseChannel) => {
262
+ if (nextChannel === channel) return;
263
+
243
264
  setManifest(null);
244
265
  setManifestError(false);
245
266
  setChannel(nextChannel);
@@ -335,46 +356,48 @@ export default function DownloadPage() {
335
356
  <>{t("downloadRoute.loadingRelease")}</>
336
357
  )}
337
358
  </div>
338
- <div className="mt-2 flex items-center gap-2 text-xs text-muted-foreground">
339
- <span>{t("downloadRoute.stable")}</span>
340
- <button
341
- type="button"
342
- role="switch"
343
- aria-checked={channel === "nightly"}
344
- aria-label={t(
345
- channel === "nightly"
346
- ? "downloadRoute.switchToStable"
347
- : "downloadRoute.switchToNightly",
348
- )}
349
- onClick={() =>
350
- handleChannelChange(
351
- channel === "nightly" ? "production" : "nightly",
352
- )
353
- }
354
- className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 ${
355
- channel === "nightly"
356
- ? "bg-foreground"
357
- : "bg-muted-foreground/20"
358
- }`}
359
- >
360
- <span
361
- aria-hidden="true"
362
- className={`block size-3.5 rounded-full bg-primary-foreground shadow-sm transition-transform ${
363
- channel === "nightly"
364
- ? "translate-x-[18px]"
365
- : "translate-x-[2px]"
366
- }`}
367
- />
368
- </button>
369
- <span
370
- className={
371
- channel === "nightly"
372
- ? "font-medium text-foreground"
373
- : "text-muted-foreground"
374
- }
375
- >
376
- {t("downloadRoute.nightly")}
377
- </span>
359
+ <div className="mt-2 flex items-center justify-center text-xs text-muted-foreground">
360
+ <DropdownMenu>
361
+ <DropdownMenuTrigger asChild>
362
+ <Button
363
+ type="button"
364
+ variant="ghost"
365
+ size="sm"
366
+ className="h-7 gap-1.5 px-2 font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground"
367
+ data-release-channel={channel}
368
+ >
369
+ <span
370
+ className={
371
+ channel === "nightly"
372
+ ? "font-medium text-foreground"
373
+ : undefined
374
+ }
375
+ >
376
+ {channel === "nightly"
377
+ ? t("downloadRoute.nightly")
378
+ : t("downloadRoute.stable")}
379
+ </span>
380
+ <IconChevronDown className="size-3.5" aria-hidden="true" />
381
+ </Button>
382
+ </DropdownMenuTrigger>
383
+ <DropdownMenuContent align="center" className="w-44">
384
+ <DropdownMenuRadioGroup
385
+ value={channel}
386
+ onValueChange={(value) => {
387
+ if (value === "production" || value === "nightly") {
388
+ handleChannelChange(value);
389
+ }
390
+ }}
391
+ >
392
+ <DropdownMenuRadioItem value="production">
393
+ {t("downloadRoute.stable")}
394
+ </DropdownMenuRadioItem>
395
+ <DropdownMenuRadioItem value="nightly">
396
+ {t("downloadRoute.nightly")}
397
+ </DropdownMenuRadioItem>
398
+ </DropdownMenuRadioGroup>
399
+ </DropdownMenuContent>
400
+ </DropdownMenu>
378
401
  </div>
379
402
  </div>
380
403
 
@@ -1,5 +1,5 @@
1
1
  import { AgentPanel } from "@agent-native/core/client/agent-chat";
2
- import { appPath, agentNativePath } from "@agent-native/core/client/api-path";
2
+ import { agentNativePath } from "@agent-native/core/client/api-path";
3
3
  import { writeClipboardText } from "@agent-native/core/client/clipboard";
4
4
  import {
5
5
  useActionMutation,
@@ -16,7 +16,7 @@ import {
16
16
  isHumanReadableDocumentTitle,
17
17
  normalizeDocumentTitle,
18
18
  } from "@agent-native/core/shared";
19
- import { ShareCopyRow, ShareTrigger } from "@agent-native/toolkit/sharing";
19
+ import { ShareCopyRow } from "@agent-native/toolkit/sharing";
20
20
  import {
21
21
  BUILDER_CREDITS_UPGRADE_URL,
22
22
  type BuilderCreditsStatus,
@@ -59,6 +59,7 @@ import { toast } from "sonner";
59
59
 
60
60
  import { EditableRecordingTitle } from "@/components/editable-recording-title";
61
61
  import { EditorLayout } from "@/components/editor/editor-layout";
62
+ import { ClipsShareTrigger } from "@/components/player/clips-share-trigger";
62
63
  import { CommentsPanel } from "@/components/player/comments-panel";
63
64
  import { RecordingOptionsMenu } from "@/components/player/delete-recording-menu";
64
65
  import { InsightsPanel } from "@/components/player/insights-panel";
@@ -1051,7 +1052,7 @@ export default function RecordingPage() {
1051
1052
  if (!showRecoveryState) {
1052
1053
  return (
1053
1054
  <div className="flex min-h-screen w-full flex-col bg-background">
1054
- <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">
1055
+ <header className="flex min-w-0 shrink-0 items-center gap-2 border-b border-border px-3 py-2 sm:px-4 sm:py-3">
1055
1056
  <BackToLibraryButton />
1056
1057
  <div className="min-w-0 flex-1">
1057
1058
  <p className="truncate text-sm font-medium">{visibleTitle}</p>
@@ -1070,10 +1071,7 @@ export default function RecordingPage() {
1070
1071
  hasPassword={Boolean(recording.hasPassword)}
1071
1072
  viewerReshareOnly={viewerReshareOnly}
1072
1073
  >
1073
- <ShareTrigger
1074
- label={t("recordingPage.share")}
1075
- className="shrink-0"
1076
- />
1074
+ <ClipsShareTrigger label={t("recordingPage.share")} />
1077
1075
  </ShareRecordingPopover>
1078
1076
  </header>
1079
1077
 
@@ -1370,7 +1368,7 @@ export default function RecordingPage() {
1370
1368
  <div className="flex min-h-screen w-full max-w-full flex-col overflow-x-hidden bg-background xl:h-screen xl:flex-row xl:overflow-hidden">
1371
1369
  {/* Main video column */}
1372
1370
  <div className="flex w-full min-w-0 flex-col xl:flex-1">
1373
- <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">
1371
+ <header className="flex min-w-0 shrink-0 items-center gap-2 border-b border-border px-3 py-2 sm:px-4 sm:py-3">
1374
1372
  <BackToLibraryButton />
1375
1373
  <div className="flex-1 min-w-0">
1376
1374
  <EditableRecordingTitle
@@ -1609,10 +1607,7 @@ export default function RecordingPage() {
1609
1607
  hasPassword={Boolean(recording.hasPassword)}
1610
1608
  viewerReshareOnly={viewerReshareOnly}
1611
1609
  >
1612
- <ShareTrigger
1613
- label={t("recordingPage.share")}
1614
- className="shrink-0"
1615
- />
1610
+ <ClipsShareTrigger label={t("recordingPage.share")} />
1616
1611
  </ShareRecordingPopover>
1617
1612
  ) : null}
1618
1613
 
@@ -3,7 +3,7 @@ import {
3
3
  agentNativePath,
4
4
  appBasePath,
5
5
  } from "@agent-native/core/client/api-path";
6
- import { callAction } from "@agent-native/core/client/hooks";
6
+ import { callAction, getBrowserTabId } from "@agent-native/core/client/hooks";
7
7
  import { useT } from "@agent-native/core/client/i18n";
8
8
  import { useLiveTranscription } from "@agent-native/core/client/transcription/use-live-transcription";
9
9
  import type { BrowserDiagnosticsData } from "@shared/browser-diagnostics";
@@ -31,7 +31,7 @@ import {
31
31
  import { useQueryClient } from "@tanstack/react-query";
32
32
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
33
33
  import { flushSync } from "react-dom";
34
- import { Link, useLocation, useNavigate } from "react-router";
34
+ import { useLocation, useNavigate } from "react-router";
35
35
 
36
36
  import { Skeleton } from "@/components/ui/skeleton";
37
37
  import { useDesktopPromo } from "@/hooks/use-desktop-promo";
@@ -1783,7 +1783,7 @@ export default function RecordRoute() {
1783
1783
  }
1784
1784
  if (reportContext && createdId) {
1785
1785
  const path = bugReportDonePath(createdId, reportContext);
1786
- await writeAppState("navigate", {
1786
+ await writeAppState(`navigate:${getBrowserTabId()}`, {
1787
1787
  view: "bug-report-done",
1788
1788
  recordingId: createdId,
1789
1789
  path,
@@ -1792,7 +1792,7 @@ export default function RecordRoute() {
1792
1792
  navigate(path);
1793
1793
  }, 50);
1794
1794
  } else {
1795
- await writeAppState("navigate", {
1795
+ await writeAppState(`navigate:${getBrowserTabId()}`, {
1796
1796
  view: "recording",
1797
1797
  recordingId: createdId,
1798
1798
  });
@@ -1980,7 +1980,7 @@ export default function RecordRoute() {
1980
1980
 
1981
1981
  if (reportContext) {
1982
1982
  const path = bugReportDonePath(recordingId, reportContext);
1983
- await writeAppState("navigate", {
1983
+ await writeAppState(`navigate:${getBrowserTabId()}`, {
1984
1984
  view: "bug-report-done",
1985
1985
  recordingId,
1986
1986
  path,
@@ -1991,7 +1991,7 @@ export default function RecordRoute() {
1991
1991
  return;
1992
1992
  }
1993
1993
 
1994
- await writeAppState("navigate", {
1994
+ await writeAppState(`navigate:${getBrowserTabId()}`, {
1995
1995
  view: "recording",
1996
1996
  recordingId,
1997
1997
  }).catch(() => {});
@@ -13,13 +13,12 @@ import {
13
13
  import { useT } from "@agent-native/core/client/i18n";
14
14
  import { buildSignInReturnHref } from "@agent-native/core/client/ui";
15
15
  import { docsUrl } from "@agent-native/core/shared";
16
- import { ShareTrigger } from "@agent-native/toolkit/sharing";
17
16
  import {
18
17
  IconAlertTriangle,
19
18
  IconArrowLeft,
20
19
  IconDeviceDesktop,
21
20
  IconDownload,
22
- IconDots,
21
+ IconDotsVertical,
23
22
  IconLock,
24
23
  IconLogin2,
25
24
  } from "@tabler/icons-react";
@@ -51,6 +50,7 @@ import { toast } from "sonner";
51
50
 
52
51
  import { CaptureInstallButton } from "@/components/capture-install-options";
53
52
  import { AccessPasswordPrompt } from "@/components/player/access-password-prompt";
53
+ import { ClipsShareTrigger } from "@/components/player/clips-share-trigger";
54
54
  import { CommentsPanel } from "@/components/player/comments-panel";
55
55
  import { RecordingOptionsMenu } from "@/components/player/delete-recording-menu";
56
56
  import { InsightsPanel } from "@/components/player/insights-panel";
@@ -1110,8 +1110,8 @@ export default function ShareRoute() {
1110
1110
  return (
1111
1111
  <div className="flex min-h-screen max-w-full flex-col overflow-x-hidden bg-background text-foreground lg:h-screen lg:flex-row lg:overflow-hidden">
1112
1112
  {agentDiscovery}
1113
- <div className="flex w-full min-w-0 flex-col lg:flex-1">
1114
- <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">
1113
+ <div className="clips-share-content flex w-full min-w-0 flex-col lg:flex-1">
1114
+ <header className="flex min-w-0 shrink-0 flex-wrap items-center gap-2 border-b border-border px-3 py-2 sm:px-4 sm:py-3 lg:flex-nowrap">
1115
1115
  {session ? (
1116
1116
  <Button
1117
1117
  asChild
@@ -1147,7 +1147,7 @@ export default function ShareRoute() {
1147
1147
  )}
1148
1148
  </div>
1149
1149
 
1150
- <div className="flex w-full min-w-0 flex-wrap items-center justify-between gap-2 sm:w-auto sm:justify-end">
1150
+ <div className="flex w-full min-w-0 flex-wrap items-center justify-between gap-1 sm:w-auto sm:justify-end">
1151
1151
  <RecordingViewsBadge
1152
1152
  recordingId={recording.id}
1153
1153
  viewCount={viewCount}
@@ -1161,6 +1161,22 @@ export default function ShareRoute() {
1161
1161
  onCtaClick={fireShareCtaClick}
1162
1162
  />
1163
1163
  )}
1164
+ {viewerCanEdit || canReshareLink ? (
1165
+ <ShareRecordingPopover
1166
+ recordingId={recording.id}
1167
+ recordingTitle={recording.title}
1168
+ initialVisibility={recording.visibility}
1169
+ initialRole={viewerIsOwner ? "owner" : undefined}
1170
+ videoUrl={shareVideoUrl}
1171
+ thumbnailUrl={recording.thumbnailUrl}
1172
+ animatedThumbnailUrl={recording.animatedThumbnailUrl}
1173
+ isLoomRecording={isLoomEmbedBacked}
1174
+ hasPassword={Boolean(recording.hasPassword)}
1175
+ viewerReshareOnly={viewerReshareOnly}
1176
+ >
1177
+ <ClipsShareTrigger label={t("sharePage.share")} />
1178
+ </ShareRecordingPopover>
1179
+ ) : null}
1164
1180
  {!viewerCanEdit && canDownloadRecording ? (
1165
1181
  <DropdownMenu
1166
1182
  open={downloadMenuOpen}
@@ -1170,10 +1186,10 @@ export default function ShareRoute() {
1170
1186
  <Button
1171
1187
  variant="ghost"
1172
1188
  size="sm"
1173
- className="h-9 w-9 shrink-0 px-0"
1189
+ className="-mx-1.5 h-auto w-auto shrink-0 px-0.5 py-1.5"
1174
1190
  aria-label={t("sharePage.clipOptions")}
1175
1191
  >
1176
- <IconDots className="h-4 w-4" />
1192
+ <IconDotsVertical className="h-4 w-4" />
1177
1193
  </Button>
1178
1194
  </DropdownMenuTrigger>
1179
1195
  <DropdownMenuContent align="end" className="w-44">
@@ -1206,25 +1222,6 @@ export default function ShareRoute() {
1206
1222
  onDeleted={() => navigate("/library", { replace: true })}
1207
1223
  />
1208
1224
  ) : null}
1209
- {viewerCanEdit || canReshareLink ? (
1210
- <ShareRecordingPopover
1211
- recordingId={recording.id}
1212
- recordingTitle={recording.title}
1213
- initialVisibility={recording.visibility}
1214
- initialRole={viewerIsOwner ? "owner" : undefined}
1215
- videoUrl={shareVideoUrl}
1216
- thumbnailUrl={recording.thumbnailUrl}
1217
- animatedThumbnailUrl={recording.animatedThumbnailUrl}
1218
- isLoomRecording={isLoomEmbedBacked}
1219
- hasPassword={Boolean(recording.hasPassword)}
1220
- viewerReshareOnly={viewerReshareOnly}
1221
- >
1222
- <ShareTrigger
1223
- label={t("sharePage.share")}
1224
- className="shrink-0"
1225
- />
1226
- </ShareRecordingPopover>
1227
- ) : null}
1228
1225
  </div>
1229
1226
  </header>
1230
1227
 
@@ -1361,15 +1358,15 @@ export default function ShareRoute() {
1361
1358
  : null}
1362
1359
  </div>
1363
1360
 
1364
- <div className="flex shrink-0 flex-col gap-3 px-4 pb-4 sm:flex-row sm:items-start sm:px-0 sm:pb-0">
1365
- <div className="min-w-0 flex-1">
1361
+ <div className="clips-share-metadata flex shrink-0 flex-col gap-3 px-4 pb-4 sm:px-0 sm:pb-0">
1362
+ <div className="clips-share-metadata-description min-w-0 flex-1">
1366
1363
  {recording.description ? (
1367
1364
  <p className="whitespace-pre-wrap break-words text-sm text-muted-foreground">
1368
1365
  {recording.description}
1369
1366
  </p>
1370
1367
  ) : null}
1371
1368
  </div>
1372
- <div className="flex max-w-full flex-col items-stretch gap-2 sm:items-end">
1369
+ <div className="clips-share-metadata-actions flex max-w-full flex-col items-stretch gap-2 sm:items-end">
1373
1370
  <div className="flex flex-wrap items-center gap-2 sm:justify-end">
1374
1371
  {recording.enableComments ? (
1375
1372
  <TimestampedCommentButton
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-20
4
+ ---
5
+
6
+ Clip viewers now make Share the primary action and keep the overflow control compact and vertical.
@@ -2,4 +2,5 @@
2
2
  type: improved
3
3
  date: 2026-08-20
4
4
  ---
5
+
5
6
  Recording preparation now uses a centered full-screen overlay that transitions smoothly into the 3-2-1 countdown.
@@ -61,19 +61,6 @@ type PopupStartMessage = {
61
61
  settings?: Partial<ExtensionSettings>;
62
62
  };
63
63
 
64
- type PopupMessage =
65
- | PopupStartMessage
66
- | { type: "CLIPS_POPUP_STATUS" }
67
- | { type: "CLIPS_POPUP_STOP" }
68
- | { type: "CLIPS_POPUP_CANCEL" }
69
- | { type: "CLIPS_POPUP_OPEN" }
70
- | { type: "CLIPS_POPUP_SIGN_IN"; settings?: Partial<ExtensionSettings> }
71
- | {
72
- type: "CLIPS_POPUP_PREPARE_PERMISSION_START";
73
- settings?: Partial<ExtensionSettings>;
74
- targetTabId?: number;
75
- };
76
-
77
64
  type ExternalMessage =
78
65
  | {
79
66
  type: "CLIPS_CAPTURE_START";
@@ -117,7 +117,6 @@ type OverlayState = {
117
117
  countdownEndsAtMs: number;
118
118
  };
119
119
 
120
- const COUNTDOWN_FALLBACK = 3;
121
120
  const params = new URLSearchParams(location.search);
122
121
  const part = params.get("part");
123
122
  const root = document.getElementById("root") as HTMLDivElement;
@@ -574,26 +574,6 @@ function isUnsupportedPage(url: string | undefined | null): boolean {
574
574
  );
575
575
  }
576
576
 
577
- function targetCopy(tab: chrome.tabs.Tab | null): {
578
- title: string;
579
- subtitle: string;
580
- } {
581
- const title = tab?.title?.trim() || "Current tab";
582
- const host = hostnameLabel(tab?.url);
583
- if (!host) return { title, subtitle: "Ready to record" };
584
- const titleKey = comparableLabel(title);
585
- const hostKey = comparableLabel(host);
586
- return {
587
- title,
588
- subtitle:
589
- titleKey &&
590
- hostKey &&
591
- (titleKey === hostKey || hostKey.includes(titleKey))
592
- ? ""
593
- : host,
594
- };
595
- }
596
-
597
577
  function isSignInError(message: string | undefined): boolean {
598
578
  return Boolean(
599
579
  message && /sign in to clips|unauthorized|unauthenticated/i.test(message),