@agent-native/core 0.0.0-beta-20260820171000 → 0.0.0-beta-20260820181038

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 (59) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +37 -3
  3. package/corpus/templates/analytics/changelog/2026-08-20-staged-data-limit-recovery.md +1 -0
  4. package/corpus/templates/assets/CHANGELOG.md +36 -2
  5. package/corpus/templates/brain/CHANGELOG.md +33 -3
  6. package/corpus/templates/calendar/CHANGELOG.md +45 -2
  7. package/corpus/templates/chat/CHANGELOG.md +29 -3
  8. package/corpus/templates/clips/CHANGELOG.md +55 -2
  9. package/corpus/templates/clips/app/i18n/en-US.ts +6 -11
  10. package/corpus/templates/clips/app/root.tsx +2 -1
  11. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +3 -3
  12. package/corpus/templates/clips/app/routes/download.tsx +111 -17
  13. package/corpus/templates/clips/changelog/2026-08-20-cross-tab-recording-controls.md +1 -0
  14. package/corpus/templates/clips/changelog/2026-08-20-overlay-follow-review-fixes.md +1 -0
  15. package/corpus/templates/clips/changelog/2026-08-20-provider-key-recovery.md +1 -0
  16. package/corpus/templates/clips/server/routes/api/clips-latest.json.get.ts +109 -46
  17. package/corpus/templates/content/CHANGELOG.md +45 -2
  18. package/corpus/templates/crm/CHANGELOG.md +28 -16
  19. package/corpus/templates/design/CHANGELOG.md +54 -2
  20. package/corpus/templates/dispatch/CHANGELOG.md +51 -2
  21. package/corpus/templates/factory/CHANGELOG.md +28 -2
  22. package/corpus/templates/forms/CHANGELOG.md +39 -3
  23. package/corpus/templates/macros/CHANGELOG.md +30 -2
  24. package/corpus/templates/mail/CHANGELOG.md +34 -3
  25. package/corpus/templates/plan/CHANGELOG.md +34 -3
  26. package/corpus/templates/slides/CHANGELOG.md +73 -2
  27. package/corpus/templates/tasks/CHANGELOG.md +35 -0
  28. package/corpus/templates/tasks/app/root.tsx +8 -1
  29. package/dist/changelog/parse.d.ts +12 -4
  30. package/dist/changelog/parse.js +61 -23
  31. package/dist/cli/changelog.js +9 -11
  32. package/dist/client/blocks/library/diagram.js +1 -1
  33. package/dist/collab/awareness.d.ts +2 -2
  34. package/dist/collab/struct-routes.d.ts +1 -1
  35. package/dist/deploy/workspace-deploy.js +7 -0
  36. package/dist/mcp-client/oauth-routes.d.ts +1 -0
  37. package/dist/mcp-client/oauth-routes.js +15 -2
  38. package/dist/mcp-client/remote-store.js +83 -43
  39. package/dist/notifications/routes.d.ts +3 -3
  40. package/dist/observability/routes.d.ts +3 -3
  41. package/dist/progress/routes.d.ts +1 -1
  42. package/dist/secrets/routes.d.ts +9 -9
  43. package/dist/server/google-oauth-credentials.js +14 -1
  44. package/dist/settings/index.d.ts +1 -1
  45. package/dist/settings/index.js +1 -1
  46. package/dist/settings/store.d.ts +7 -1
  47. package/dist/settings/store.js +25 -3
  48. package/dist/settings/user-settings.d.ts +2 -0
  49. package/dist/settings/user-settings.js +65 -2
  50. package/dist/templates/chat/CHANGELOG.md +29 -3
  51. package/docs/content/deployment.mdx +89 -14
  52. package/package.json +1 -1
  53. package/src/templates/chat/CHANGELOG.md +29 -3
  54. package/corpus/templates/.retired/issues/package.json +0 -7
  55. package/corpus/templates/.retired/meeting-notes/package.json +0 -7
  56. package/corpus/templates/.retired/recruiting/package.json +0 -7
  57. package/corpus/templates/.retired/scheduling/package.json +0 -7
  58. package/corpus/templates/.retired/voice/package.json +0 -7
  59. package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +0 -87
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 8490
34
+ - template files: 8485
@@ -3,8 +3,42 @@
3
3
  All notable user-facing changes to Agent-Native Analytics are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
7
 
8
- ### Added
8
+ ## 2026-08-20
9
9
 
10
- - See what's new right inside Agent-Native Analytics — a changelog now lives in the command menu (Cmd+K) and in Settings.
10
+ ### Improved
11
+
12
+ - Analytics now explains how to recover when staged data reaches its size limit.
13
+
14
+ ## 2026-08-18
15
+
16
+ ### Fixed
17
+
18
+ - Analytics no longer carries a previous dashboard into a new Ask chat.
19
+ - Feature flag changes now preserve actionable failures and verify the target app's persisted state.
20
+
21
+ ## 2026-08-17
22
+
23
+ ### Fixed
24
+
25
+ - Fixed dashboard editing focus, history recovery, panel setup focus, and repeated failed warehouse queries.
26
+
27
+ ## 2026-08-13
28
+
29
+ ### Fixed
30
+
31
+ - Account health readouts now verify customer identity, completed usage periods,
32
+ contract metrics, and product adoption before summarizing.
33
+
34
+ ## 2026-08-12
35
+
36
+ ### Improved
37
+
38
+ - Ask now toggles chat history directly, and the collapsed sidebar uses a more compact navigation rhythm.
39
+ - Data source statuses now distinguish workspace access from credentials configured in Analytics.
40
+
41
+ ### Fixed
42
+
43
+ - Feature flags can be managed across apps whose workspace records use different local IDs
44
+ - Kept feature flag details readable by stacking rollout controls at narrow widths.
@@ -2,4 +2,5 @@
2
2
  type: improved
3
3
  date: 2026-08-20
4
4
  ---
5
+
5
6
  Analytics now explains how to recover when staged data reaches its size limit.
@@ -3,8 +3,42 @@
3
3
  All notable user-facing changes to Assets are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
+
8
+ ## 2026-08-11
9
+
10
+ ### Improved
11
+
12
+ - Full-page chat composers stay at a focused 750px width.
13
+
14
+ ### Fixed
15
+
16
+ - Chrome no longer offers to install Assets as a desktop app.
17
+
18
+ ## 2026-08-10
19
+
20
+ ### Improved
21
+
22
+ - Full-page chat now uses the available width up to 1000px for more comfortable prompts and responses.
23
+
24
+ ## 2026-08-05
7
25
 
8
26
  ### Added
9
27
 
10
- - See what's new right inside Assets — a changelog now lives in the command menu (Cmd+K) and in Settings.
28
+ - Brand kits can import a website's hydrated visual language and reuse it in generated imagery.
29
+
30
+ ### Fixed
31
+
32
+ - Generated images now hand off embeddable previews to other workspace apps.
33
+
34
+ ## 2026-08-01
35
+
36
+ ### Added
37
+
38
+ - Get an email when a generation you started finishes or fails, with a new toggle in Settings
39
+
40
+ ## 2026-07-31
41
+
42
+ ### Improved
43
+
44
+ - The Agent Native logo stays visible when the sidebar is collapsed and toggles the sidebar when clicked.
@@ -3,8 +3,38 @@
3
3
  All notable user-facing changes to Agent-Native Brain are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
7
 
8
- ### Added
8
+ ## 2026-08-11
9
9
 
10
- - See what's new right inside Agent-Native Brain — a changelog now lives in the command menu (Cmd+K) and in Settings.
10
+ ### Improved
11
+
12
+ - Full-page chat composers stay at a focused 750px width.
13
+
14
+ ### Fixed
15
+
16
+ - Chrome no longer offers to install Brain as a desktop app.
17
+
18
+ ## 2026-08-10
19
+
20
+ ### Improved
21
+
22
+ - Full-page chat now uses the available width up to 1000px for more comfortable prompts and responses.
23
+
24
+ ## 2026-08-06
25
+
26
+ ### Fixed
27
+
28
+ - Brain provider setup links open Dispatch correctly in standalone and workspace deployments.
29
+
30
+ ## 2026-08-03
31
+
32
+ ### Fixed
33
+
34
+ - Brain now avoids unsupported company facts when verified sources are unavailable
35
+
36
+ ## 2026-07-31
37
+
38
+ ### Improved
39
+
40
+ - Clicking the Agent Native logo now toggles the app sidebar.
@@ -3,8 +3,51 @@
3
3
  All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
+
8
+ ## 2026-08-19
9
+
10
+ ### Improved
11
+
12
+ - Calendar pages stay fast after periods of inactivity.
13
+
14
+ ## 2026-08-18
15
+
16
+ ### Added
17
+
18
+ - The agent can now remove many meetings at once, such as every Saturday and Sunday meeting in a range, instead of failing partway through
19
+
20
+ ### Fixed
21
+
22
+ - Calendar event time editing now respects the event's timezone.
23
+ - Calendar stays responsive in the desktop app without focus-triggered reloads
24
+
25
+ ## 2026-08-17
26
+
27
+ ### Fixed
28
+
29
+ - Booking links now respect each required host's saved availability
30
+
31
+ ## 2026-08-14
32
+
33
+ ### Fixed
34
+
35
+ - Choosing Office or Other when adding a working location creates that type, and adding one on a day that already has a location updates that day instead of extending Home.
36
+ - Creating an Other working location now keeps the custom name instead of saving it as Working.
37
+ - Timed working locations keep a Home, Office, or custom title instead of the generated Working location label.
38
+ - Timed working locations now keep a Home, Office, or custom title instead of showing as Untitled.
39
+ - Turning a timed working location that ends at midnight back to all-day no longer adds an extra day.
40
+
41
+ ## 2026-08-13
7
42
 
8
43
  ### Added
9
44
 
10
- - See what's new right inside Agent-Native Calendar — a changelog now lives in the command menu (Cmd+K) and in Settings.
45
+ - Working locations can be added from calendar days, with a full-day first entry and timed same-day additions
46
+
47
+ ### Fixed
48
+
49
+ - The Find a time window now closes from a clear header action.
50
+
51
+ ### Changed
52
+
53
+ - Calendar stays pinned to the saved timezone and asks before adopting a changed browser timezone
@@ -3,8 +3,34 @@
3
3
  All notable user-facing changes to Chat are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new").
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
7
 
8
- ### Added
8
+ ## 2026-08-11
9
9
 
10
- - See what's new right inside Chat — a changelog now lives in the command menu (Cmd+K).
10
+ ### Fixed
11
+
12
+ - Chrome no longer offers to install Chat as a desktop app.
13
+
14
+ ## 2026-08-10
15
+
16
+ ### Improved
17
+
18
+ - Full-page chat now uses the available width up to 1000px for more comfortable prompts and responses.
19
+
20
+ ## 2026-07-31
21
+
22
+ ### Improved
23
+
24
+ - Clicking the Agent Native logo now toggles the app sidebar.
25
+
26
+ ## 2026-07-29
27
+
28
+ ### Improved
29
+
30
+ - Sidebar footers now keep Feedback, Search, and Collapse together without a separate language shortcut.
31
+
32
+ ## 2026-07-25
33
+
34
+ ### Improved
35
+
36
+ - Settings navigation now keeps Manage agent as a dedicated linked destination at the bottom.
@@ -3,8 +3,61 @@
3
3
  All notable user-facing changes to Clips are documented here. Open it any time
4
4
  from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
- ## 2026-06-23
6
+ Older updates live in [the changelog folder](./changelog/) and are included in the in-app "What's new" view.
7
+
8
+ ## 2026-08-20
9
+
10
+ ### Improved
11
+
12
+ - Recording controls now follow you across browser tabs and page navigations.
13
+
14
+ ### Fixed
15
+
16
+ - Clips overlays now follow tab switches during the recording countdown and recover cleanly on tabs opened before Clips.
17
+ - Clips now opens provider setup instead of retrying a rejected key in a loop.
18
+
19
+ ## 2026-08-19
7
20
 
8
21
  ### Added
9
22
 
10
- - See what's new right inside Clips — a changelog now lives in the command menu (Cmd+K) and in Settings.
23
+ - Clips Nightly builds are available for trying the latest updates.
24
+
25
+ ### Fixed
26
+
27
+ - Shared clips now show a video frame in social previews when no thumbnail is stored.
28
+
29
+ ## 2026-08-18
30
+
31
+ ### Improved
32
+
33
+ - Meeting notes support rich editing for personal notes, summaries, and action items.
34
+ - Meeting notifications no longer show decorative left-side lines.
35
+
36
+ ### Fixed
37
+
38
+ - Centered the clip play button and corrected the empty comment-panel hint.
39
+ - Clips no longer crashes when a camera bubble starts at a tiny size.
40
+ - Clips now recovers interrupted uploads and reliably restarts after installing desktop updates.
41
+ - Deleting a recording no longer freezes Clips or blocks starting a new recording.
42
+ - Pending recording files now use a Clips-prefixed name instead of a feature-ambiguous stem.
43
+
44
+ ### Removed
45
+
46
+ - Clips no longer opens a welcome window on first launch.
47
+
48
+ ## 2026-08-17
49
+
50
+ ### Fixed
51
+
52
+ - Shared clips now clearly show sign-in, let signed-in viewers comment, and use neutral messaging for confirmed no-audio transcripts.
53
+
54
+ ## 2026-08-14
55
+
56
+ ### Improved
57
+
58
+ - Meetings now opens on your history instead of a wall of upcoming cards: past meetings with notes but no linked recording are back in the list, older ones keep loading as you go, and search reaches attendee names and transcript text so you can find a call by what was said in it.
59
+
60
+ ### Fixed
61
+
62
+ - Long desktop recordings now complete or abort resumable uploads cleanly, preserve local recovery copies, and show the actual upload error when saving fails.
63
+ - Clips now uses consistent text-only share controls with compact copy actions and an expandable Share with agents section across recordings and meetings.
@@ -615,12 +615,16 @@ const messages = {
615
615
  alsoFor: "Also available for {{platform}}",
616
616
  backToLibrary: "Back to library",
617
617
  clipsDesktop: "Clips Desktop",
618
+ stable: "Stable",
619
+ nightly: "Nightly",
620
+ switchToNightly: "Switch to Nightly builds",
621
+ switchToStable: "Switch to stable builds",
622
+ retry: "Try again",
618
623
  heroDescription:
619
624
  "A menu-bar recorder for screen, camera, and screen + camera. One-click start, draggable camera bubble, instant-share link when you stop.",
620
625
  versionReleased: "Version {{version}} — released {{date}}",
621
626
  version: "Version {{version}}",
622
- manifestError:
623
- "Could not load release manifest — pick an installer from the releases page.",
627
+ manifestError: "Could not load release manifest. Try again.",
624
628
  loadingRelease: "Loading latest release…",
625
629
  chromeTitle: "Chrome extension for browser logs",
626
630
  chromeDescription:
@@ -683,15 +687,6 @@ const messages = {
683
687
  viewAllUpdates: "View all updates",
684
688
  expand: "Expand",
685
689
  collapse: "Collapse",
686
- changelogMarkdown: `# Changelog
687
-
688
- All notable user-facing changes to Clips are documented here. Open it any time from the command menu (Cmd K -> "What's new") or from Settings.
689
-
690
- ## 2026-06-23
691
-
692
- ### Added
693
-
694
- - See what's new right inside Clips. A changelog now lives in the command menu (Cmd K) and in Settings.`,
695
690
  playback: "Playback",
696
691
  defaultPlaybackSpeed: "Default playback speed",
697
692
  playbackDescription: "Applied automatically when you open a recording.",
@@ -56,6 +56,7 @@ import { AppToolkitProvider } from "@/components/ui/toolkit-provider";
56
56
  import { useNavigationState } from "@/hooks/use-navigation-state";
57
57
  import { SEARCH_FOCUS_PATH } from "@/lib/search-focus";
58
58
 
59
+ import changelog from "../CHANGELOG.md?raw";
59
60
  import { i18nCatalog, loadI18nMessages } from "./i18n";
60
61
 
61
62
  import stylesheet from "./global.css?url";
@@ -366,7 +367,7 @@ function AppContent() {
366
367
  <CommandMenu
367
368
  open={cmdkOpen}
368
369
  onOpenChange={setCmdkOpen}
369
- changelog={t("settings.changelogMarkdown")}
370
+ changelog={changelog}
370
371
  changelogLabel={t("settings.whatsNew")}
371
372
  changelogKey="clips"
372
373
  >
@@ -37,6 +37,8 @@ import { useSecretStatus } from "@/hooks/use-secret-status";
37
37
  import { useVideoStorageStatus } from "@/hooks/use-video-storage-status";
38
38
  import enMessages from "@/i18n/en-US";
39
39
 
40
+ import changelog from "../../CHANGELOG.md?raw";
41
+
40
42
  export function meta() {
41
43
  return [{ title: enMessages.settings.pageTitle }];
42
44
  }
@@ -205,8 +207,6 @@ export default function SettingsIndexRoute() {
205
207
  }
206
208
  }
207
209
 
208
- const localizedChangelog = t("settings.changelogMarkdown");
209
-
210
210
  // Hashes match the row ids below, so a search hit still scrolls to the
211
211
  // individual setting now that the one-control cards are rows in a group.
212
212
  const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
@@ -456,7 +456,7 @@ export default function SettingsIndexRoute() {
456
456
  whatsNew={
457
457
  <div className="mx-auto w-full max-w-3xl">
458
458
  <ChangelogSettingsCard
459
- markdown={localizedChangelog}
459
+ markdown={changelog}
460
460
  title={t("settings.whatsNew")}
461
461
  closeLabel={t("common.cancel")}
462
462
  emptyText={t("settings.changelogEmpty")}
@@ -29,6 +29,7 @@ export function meta() {
29
29
  }
30
30
 
31
31
  type PlatformId = "mac" | "windows" | "linux";
32
+ type ReleaseChannel = "production" | "nightly";
32
33
 
33
34
  interface PlatformVariant {
34
35
  id: PlatformId;
@@ -48,9 +49,6 @@ interface PlatformVariant {
48
49
 
49
50
  const LATEST_JSON_URL = `${appBasePath()}/api/clips-latest.json`;
50
51
 
51
- const RELEASE_PAGE_URL =
52
- "https://github.com/BuilderIO/agent-native/releases?q=clips-v";
53
-
54
52
  const VARIANTS: PlatformVariant[] = [
55
53
  {
56
54
  id: "mac",
@@ -114,12 +112,18 @@ function primaryDownloadButton(
114
112
  manifest: Manifest | null,
115
113
  manifestError: boolean,
116
114
  downloadLabel: string,
115
+ retryLabel: string,
116
+ onRetry: () => void,
117
117
  ) {
118
118
  const asset = pickAsset(manifest, variant);
119
119
  const Icon = variant.icon;
120
120
  if (asset) {
121
121
  return (
122
- <Button asChild size="lg" className="h-12 gap-2 px-6 text-base">
122
+ <Button
123
+ asChild
124
+ size="lg"
125
+ className="h-12 min-w-[252px] gap-2 px-6 text-base"
126
+ >
123
127
  <a href={asset.url} download onClick={markDesktopAppDownloaded}>
124
128
  <Icon className="h-5 w-5" />
125
129
  {downloadLabel}
@@ -130,17 +134,28 @@ function primaryDownloadButton(
130
134
  if (manifest === null && !manifestError) {
131
135
  return <Skeleton className="h-12 w-[252px] rounded-md" />;
132
136
  }
137
+ if (manifestError) {
138
+ return (
139
+ <Button
140
+ size="lg"
141
+ variant="outline"
142
+ className="h-12 min-w-[252px] gap-2 px-6 text-base"
143
+ onClick={onRetry}
144
+ >
145
+ <Icon className="h-5 w-5" />
146
+ {retryLabel}
147
+ </Button>
148
+ );
149
+ }
133
150
  return (
134
151
  <Button
135
- asChild
136
152
  size="lg"
137
153
  variant="outline"
138
- className="h-12 gap-2 px-6 text-base"
154
+ className="h-12 min-w-[252px] gap-2 px-6 text-base"
155
+ disabled
139
156
  >
140
- <a href={RELEASE_PAGE_URL} rel="noreferrer">
141
- <Icon className="h-5 w-5" />
142
- {downloadLabel}
143
- </a>
157
+ <Icon className="h-5 w-5" />
158
+ {downloadLabel}
144
159
  </Button>
145
160
  );
146
161
  }
@@ -150,6 +165,8 @@ function secondaryDownloadButton(
150
165
  manifest: Manifest | null,
151
166
  manifestError: boolean,
152
167
  downloadLabel: string,
168
+ retryLabel: string,
169
+ onRetry: () => void,
153
170
  ) {
154
171
  const asset = pickAsset(manifest, variant);
155
172
  const Icon = variant.icon;
@@ -168,12 +185,18 @@ function secondaryDownloadButton(
168
185
  if (manifest === null && !manifestError) {
169
186
  return <Skeleton className="h-7 w-[208px] rounded-md" />;
170
187
  }
171
- return (
172
- <Button asChild variant="ghost" className={className}>
173
- <a href={RELEASE_PAGE_URL} rel="noreferrer">
188
+ if (manifestError) {
189
+ return (
190
+ <Button variant="ghost" className={className} onClick={onRetry}>
174
191
  <Icon className="h-4 w-4" />
175
- {downloadLabel}
176
- </a>
192
+ {retryLabel}
193
+ </Button>
194
+ );
195
+ }
196
+ return (
197
+ <Button variant="ghost" className={className} disabled>
198
+ <Icon className="h-4 w-4" />
199
+ {downloadLabel}
177
200
  </Button>
178
201
  );
179
202
  }
@@ -181,9 +204,11 @@ function secondaryDownloadButton(
181
204
  export default function DownloadPage() {
182
205
  const chromeExtensionEnabled = useClipsChromeExtensionEnabled();
183
206
  const t = useT();
207
+ const [channel, setChannel] = useState<ReleaseChannel>("production");
184
208
  const [manifest, setManifest] = useState<Manifest | null>(null);
185
209
  const [manifestError, setManifestError] = useState(false);
186
210
  const [detected, setDetected] = useState<PlatformId | null>(null);
211
+ const [manifestRequest, setManifestRequest] = useState(0);
187
212
 
188
213
  useEffect(() => {
189
214
  setDetected(detectPlatform());
@@ -191,7 +216,13 @@ export default function DownloadPage() {
191
216
 
192
217
  useEffect(() => {
193
218
  let cancelled = false;
194
- fetch(LATEST_JSON_URL)
219
+ setManifest(null);
220
+ setManifestError(false);
221
+ const manifestUrl =
222
+ channel === "nightly"
223
+ ? `${LATEST_JSON_URL}?channel=nightly`
224
+ : LATEST_JSON_URL;
225
+ fetch(manifestUrl)
195
226
  .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`${r.status}`))))
196
227
  .then((json) => {
197
228
  if (!cancelled) setManifest(json as Manifest);
@@ -202,7 +233,17 @@ export default function DownloadPage() {
202
233
  return () => {
203
234
  cancelled = true;
204
235
  };
205
- }, []);
236
+ }, [channel, manifestRequest]);
237
+
238
+ const retryManifest = () => {
239
+ setManifestRequest((request) => request + 1);
240
+ };
241
+
242
+ const handleChannelChange = (nextChannel: ReleaseChannel) => {
243
+ setManifest(null);
244
+ setManifestError(false);
245
+ setChannel(nextChannel);
246
+ };
206
247
 
207
248
  const primary = VARIANTS.find((v) => v.id === detected) ?? VARIANTS[0];
208
249
  const secondary = VARIANTS.filter((v) => v.id !== primary.id);
@@ -242,6 +283,14 @@ export default function DownloadPage() {
242
283
  <div className="flex flex-col items-center text-center">
243
284
  <h1 className="text-4xl font-semibold tracking-tight sm:text-5xl">
244
285
  {t("downloadRoute.clipsDesktop")}
286
+ {channel === "nightly" && (
287
+ <>
288
+ {" "}
289
+ <span className="text-highlight">
290
+ {t("downloadRoute.nightly")}
291
+ </span>
292
+ </>
293
+ )}
245
294
  </h1>
246
295
  <p className="mt-4 max-w-xl text-base text-muted-foreground">
247
296
  {t("downloadRoute.heroDescription")}
@@ -253,6 +302,8 @@ export default function DownloadPage() {
253
302
  manifest,
254
303
  manifestError,
255
304
  t("downloadRoute.downloadFor", { platform: primary.label }),
305
+ t("downloadRoute.retry"),
306
+ retryManifest,
256
307
  )}
257
308
  {secondary.map((variant) => (
258
309
  <div key={variant.id}>
@@ -261,6 +312,8 @@ export default function DownloadPage() {
261
312
  manifest,
262
313
  manifestError,
263
314
  t("downloadRoute.alsoFor", { platform: variant.label }),
315
+ t("downloadRoute.retry"),
316
+ retryManifest,
264
317
  )}
265
318
  </div>
266
319
  ))}
@@ -282,6 +335,47 @@ export default function DownloadPage() {
282
335
  <>{t("downloadRoute.loadingRelease")}</>
283
336
  )}
284
337
  </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>
378
+ </div>
285
379
  </div>
286
380
 
287
381
  {chromeExtensionEnabled && (
@@ -2,4 +2,5 @@
2
2
  type: improved
3
3
  date: 2026-08-20
4
4
  ---
5
+
5
6
  Recording controls now follow you across browser tabs and page navigations.
@@ -2,4 +2,5 @@
2
2
  type: fixed
3
3
  date: 2026-08-20
4
4
  ---
5
+
5
6
  Clips overlays now follow tab switches during the recording countdown and recover cleanly on tabs opened before Clips.
@@ -2,4 +2,5 @@
2
2
  type: fixed
3
3
  date: 2026-08-20
4
4
  ---
5
+
5
6
  Clips now opens provider setup instead of retrying a rejected key in a loop.