@agent-native/core-corpus 0.201.0 → 0.201.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +6 -0
  3. package/corpus/templates/analytics/actions/save-dashboard-view.ts +10 -1
  4. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +136 -4
  5. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +4 -0
  6. package/corpus/templates/analytics/app/i18n/en-US.ts +7 -0
  7. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +86 -23
  8. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +4 -3
  9. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +55 -1
  10. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewsMenu.tsx +44 -7
  11. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-filter-restore.ts +196 -0
  12. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/filter-vars.ts +2 -0
  13. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +158 -47
  14. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
  15. package/corpus/templates/analytics/changelog/2026-10-05-custom-date-controls-stay-beside-the-range-selector-and-dash.md +6 -0
  16. package/corpus/templates/analytics/server/db/schema.ts +20 -8
  17. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +50 -3
  18. package/corpus/templates/analytics/server/lib/dashboard-view-remap.ts +52 -0
  19. package/corpus/templates/analytics/server/lib/dashboards-store.ts +77 -42
  20. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +23 -8
  21. package/corpus/templates/analytics/server/plugins/db.ts +7 -0
  22. package/corpus/templates/clips/CHANGELOG.md +4 -0
  23. package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
  24. package/corpus/templates/clips/changelog/2026-10-05-the-agent-composer-is-easier-to-distinguish-from-the-shared-.md +6 -0
  25. package/corpus/templates/design/CHANGELOG.md +1 -0
  26. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +1 -1
  27. package/corpus/templates/design/changelog/2026-10-05-design-frame-labels-apply-truncation-as-soon-as-resizing-end.md +6 -0
  28. package/corpus/templates/slides/CHANGELOG.md +7 -0
  29. package/corpus/templates/slides/agent-native.app-skill.json +2 -2
  30. package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +11 -11
  31. package/corpus/templates/slides/app/context/DeckContext.tsx +16 -12
  32. package/corpus/templates/slides/app/hooks/use-new-deck-generation.ts +129 -6
  33. package/corpus/templates/slides/app/lib/create-deck-generation.ts +4 -1
  34. package/corpus/templates/slides/app/pages/DeckEditor.tsx +25 -8
  35. package/corpus/templates/slides/app/pages/Index.tsx +85 -42
  36. package/corpus/templates/slides/changelog/2026-10-05-file-uploads-explain-the-free-builder-io-option-and-how-to-c.md +6 -0
  37. package/corpus/templates/slides/changelog/2026-10-05-slides-restores-pending-generation-questions-when-reopened.md +6 -0
  38. package/corpus/templates/slides/changelog/2026-10-05-the-home-page-shows-both-library-tabs-and-starter-prompts-im.md +6 -0
  39. package/corpus/templates/slides/changelog/2026-10-05-undo-stops-at-generated-deck.md +6 -0
  40. package/package.json +1 -1
@@ -8,6 +8,7 @@ import {
8
8
  createSharesTable,
9
9
  uniqueIndex,
10
10
  } from "@agent-native/core/db/schema";
11
+ import { sql } from "drizzle-orm";
11
12
  import { boolean } from "drizzle-orm/pg-core";
12
13
 
13
14
  export * from "./schema-monitoring.js";
@@ -76,14 +77,25 @@ export const dashboardRevisions = table(
76
77
  }),
77
78
  );
78
79
 
79
- export const dashboardViews = table("dashboard_views", {
80
- id: text("id").primaryKey(),
81
- dashboardId: text("dashboard_id").notNull(),
82
- name: text("name").notNull(),
83
- filters: text("filters").notNull().default("{}"),
84
- createdBy: text("created_by"),
85
- createdAt: text("created_at").notNull().default(now()),
86
- });
80
+ export const dashboardViews = table(
81
+ "dashboard_views",
82
+ {
83
+ id: text("id").primaryKey(),
84
+ dashboardId: text("dashboard_id").notNull(),
85
+ name: text("name").notNull(),
86
+ filters: text("filters").notNull().default("{}"),
87
+ isDefault: boolean("is_default").notNull().default(false),
88
+ createdBy: text("created_by"),
89
+ createdAt: text("created_at").notNull().default(now()),
90
+ },
91
+ (t) => ({
92
+ defaultDashboardViewIdx: uniqueIndex(
93
+ "dashboard_views_default_per_dashboard_idx",
94
+ )
95
+ .on(t.dashboardId)
96
+ .where(sql`${t.isDefault} = true`),
97
+ }),
98
+ );
87
99
 
88
100
  export const dashboardReportSubscriptions = table(
89
101
  "dashboard_report_subscriptions",
@@ -14,6 +14,7 @@ import {
14
14
  PRE_CAPPED_SIGNUPS_OVER_TIME_SQL,
15
15
  PRE_CUSTOM_SPINE_SIGNUPS_OVER_TIME_SQL,
16
16
  SIGNUPS_OVER_TIME_SQL,
17
+ buildFirstPartyDashboardFilters,
17
18
  type ExactFirstPartyPanelReplacement,
18
19
  repairFirstPartyObservedRetentionPanels,
19
20
  } from "./first-party-metric-catalog";
@@ -800,12 +801,58 @@ export function repairKnownFirstPartyDashboardQueries(
800
801
  const repaired = repairFirstPartyBigQueryDashboardQueries(
801
802
  historical.config,
802
803
  );
803
- return historical.changed && !repaired.changed
804
- ? { ...repaired, changed: true }
805
- : repaired;
804
+ const defaultsRepaired = repairFirstPartyBigQueryDashboardFilterDefaults(
805
+ repaired.config,
806
+ );
807
+ return {
808
+ ...defaultsRepaired,
809
+ changed:
810
+ historical.changed || repaired.changed || defaultsRepaired.changed,
811
+ };
806
812
  }
807
813
  if (dashboardId === FIRST_PARTY_DASHBOARD_ID) {
808
814
  return repairCanonicalFirstPartyDashboardQueries(config);
809
815
  }
810
816
  return { config, changed: false };
811
817
  }
818
+
819
+ function repairFirstPartyBigQueryDashboardFilterDefaults(
820
+ config: Record<string, unknown>,
821
+ ): { config: Record<string, unknown>; changed: boolean } {
822
+ if (!Array.isArray(config.filters)) return { config, changed: false };
823
+
824
+ const canonicalDefaults = new Map(
825
+ buildFirstPartyDashboardFilters()
826
+ .filter(
827
+ (filter) => filter.id === "timeRange" || filter.id === "emailFilter",
828
+ )
829
+ .map((filter) => [filter.id, filter.default]),
830
+ );
831
+ const legacyDefaults = new Map<string, Set<unknown>>([
832
+ ["timeRange", new Set(["all"])],
833
+ ["emailFilter", new Set(["all"])],
834
+ ]);
835
+ let changed = false;
836
+ const filters = config.filters.map((filter) => {
837
+ if (!filter || typeof filter !== "object" || Array.isArray(filter)) {
838
+ return filter;
839
+ }
840
+ const record = filter as Record<string, unknown>;
841
+ const expected =
842
+ typeof record.id === "string" ? canonicalDefaults.get(record.id) : null;
843
+ const legacy =
844
+ typeof record.id === "string" ? legacyDefaults.get(record.id) : null;
845
+ if (
846
+ !expected ||
847
+ record.default === expected ||
848
+ !legacy?.has(record.default)
849
+ )
850
+ return filter;
851
+ changed = true;
852
+ return { ...record, default: expected };
853
+ });
854
+
855
+ return changed
856
+ ? { config: { ...config, filters }, changed: true }
857
+ : { config, changed: false };
858
+ }
@@ -0,0 +1,52 @@
1
+ import { and, eq } from "drizzle-orm";
2
+
3
+ export async function remapDashboardViews(
4
+ tx: any,
5
+ dashboards: { id: any; orgId: any },
6
+ dashboardViews: { id: any; dashboardId: any; isDefault: any },
7
+ orgId: string,
8
+ duplicateId: string,
9
+ canonicalId: string,
10
+ ): Promise<void> {
11
+ for (const dashboardId of [duplicateId, canonicalId].sort()) {
12
+ const [dashboard] = await tx
13
+ .select({ id: dashboards.id })
14
+ .from(dashboards)
15
+ .where(and(eq(dashboards.id, dashboardId), eq(dashboards.orgId, orgId)))
16
+ .for("update");
17
+
18
+ if (!dashboard) {
19
+ throw new Error(
20
+ `Dashboard ${dashboardId} was not available to lock in organization ${orgId}`,
21
+ );
22
+ }
23
+ }
24
+
25
+ const [canonicalDefault] = await tx
26
+ .select({ id: dashboardViews.id })
27
+ .from(dashboardViews)
28
+ .where(
29
+ and(
30
+ eq(dashboardViews.dashboardId, canonicalId),
31
+ eq(dashboardViews.isDefault, true),
32
+ ),
33
+ )
34
+ .limit(1);
35
+
36
+ if (canonicalDefault) {
37
+ await tx
38
+ .update(dashboardViews)
39
+ .set({ isDefault: false })
40
+ .where(
41
+ and(
42
+ eq(dashboardViews.dashboardId, duplicateId),
43
+ eq(dashboardViews.isDefault, true),
44
+ ),
45
+ );
46
+ }
47
+
48
+ await tx
49
+ .update(dashboardViews)
50
+ .set({ dashboardId: canonicalId })
51
+ .where(eq(dashboardViews.dashboardId, duplicateId));
52
+ }
@@ -3150,16 +3150,21 @@ export interface DashboardViewRecord {
3150
3150
  dashboardId: string;
3151
3151
  name: string;
3152
3152
  filters: Record<string, string>;
3153
+ isDefault: boolean;
3153
3154
  createdBy: string | null;
3154
3155
  createdAt: string;
3155
3156
  }
3156
3157
 
3157
3158
  function rowToView(row: any): DashboardViewRecord {
3159
+ if (typeof row.isDefault !== "boolean") {
3160
+ throw new Error("Dashboard view is missing its default status");
3161
+ }
3158
3162
  return {
3159
3163
  id: row.id,
3160
3164
  dashboardId: row.dashboardId,
3161
3165
  name: row.name,
3162
3166
  filters: safeJsonParse(row.filters, {} as Record<string, string>),
3167
+ isDefault: row.isDefault,
3163
3168
  createdBy: row.createdBy ?? null,
3164
3169
  createdAt: row.createdAt,
3165
3170
  };
@@ -3213,7 +3218,12 @@ export async function listDashboardViews(
3213
3218
 
3214
3219
  export async function saveDashboardView(
3215
3220
  dashboardId: string,
3216
- view: { id?: string; name: string; filters: Record<string, string> },
3221
+ view: {
3222
+ id?: string;
3223
+ name: string;
3224
+ filters: Record<string, string>;
3225
+ isDefault?: boolean;
3226
+ },
3217
3227
  ctx: AccessCtx,
3218
3228
  ): Promise<DashboardViewRecord> {
3219
3229
  await assertAccess("dashboard", dashboardId, "editor", {
@@ -3221,55 +3231,80 @@ export async function saveDashboardView(
3221
3231
  orgId: ctx.orgId ?? undefined,
3222
3232
  });
3223
3233
  const db = getDb() as any;
3224
- let id = view.id ?? nanoidFallback();
3225
- let existing = false;
3226
- if (view.id) {
3227
- const [existingRow] = await db
3228
- .select({
3229
- id: schema.dashboardViews.id,
3230
- dashboardId: schema.dashboardViews.dashboardId,
3231
- })
3232
- .from(schema.dashboardViews)
3233
- .where(eq(schema.dashboardViews.id, view.id))
3234
- .limit(1);
3235
- if (existingRow?.dashboardId === dashboardId) {
3236
- existing = true;
3237
- } else if (existingRow) {
3238
- id = nanoidFallback();
3234
+ const row = await db.transaction(async (tx: any) => {
3235
+ if (view.isDefault) {
3236
+ await tx
3237
+ .select({ id: schema.dashboards.id })
3238
+ .from(schema.dashboards)
3239
+ .where(eq(schema.dashboards.id, dashboardId))
3240
+ .for("update");
3241
+ await tx
3242
+ .update(schema.dashboardViews)
3243
+ .set({ isDefault: false })
3244
+ .where(
3245
+ and(
3246
+ eq(schema.dashboardViews.dashboardId, dashboardId),
3247
+ eq(schema.dashboardViews.isDefault, true),
3248
+ ),
3249
+ );
3239
3250
  }
3240
- }
3241
3251
 
3242
- if (existing) {
3243
- await db
3244
- .update(schema.dashboardViews)
3245
- .set({ name: view.name, filters: JSON.stringify(view.filters) })
3252
+ let id = view.id ?? nanoidFallback();
3253
+ let existing = false;
3254
+ if (view.id) {
3255
+ const [existingRow] = await tx
3256
+ .select({
3257
+ id: schema.dashboardViews.id,
3258
+ dashboardId: schema.dashboardViews.dashboardId,
3259
+ })
3260
+ .from(schema.dashboardViews)
3261
+ .where(eq(schema.dashboardViews.id, view.id))
3262
+ .limit(1);
3263
+ if (existingRow?.dashboardId === dashboardId) {
3264
+ existing = true;
3265
+ } else if (existingRow) {
3266
+ id = nanoidFallback();
3267
+ }
3268
+ }
3269
+
3270
+ if (existing) {
3271
+ await tx
3272
+ .update(schema.dashboardViews)
3273
+ .set({
3274
+ name: view.name,
3275
+ filters: JSON.stringify(view.filters),
3276
+ ...(view.isDefault ? { isDefault: true } : {}),
3277
+ })
3278
+ .where(
3279
+ and(
3280
+ eq(schema.dashboardViews.id, id),
3281
+ eq(schema.dashboardViews.dashboardId, dashboardId),
3282
+ ),
3283
+ );
3284
+ } else {
3285
+ await tx.insert(schema.dashboardViews).values({
3286
+ id,
3287
+ dashboardId,
3288
+ name: view.name,
3289
+ filters: JSON.stringify(view.filters),
3290
+ isDefault: view.isDefault === true,
3291
+ createdBy: ctx.email || null,
3292
+ });
3293
+ }
3294
+ const [saved] = await tx
3295
+ .select()
3296
+ .from(schema.dashboardViews)
3246
3297
  .where(
3247
3298
  and(
3248
3299
  eq(schema.dashboardViews.id, id),
3249
3300
  eq(schema.dashboardViews.dashboardId, dashboardId),
3250
3301
  ),
3251
3302
  );
3252
- } else {
3253
- await db.insert(schema.dashboardViews).values({
3254
- id,
3255
- dashboardId,
3256
- name: view.name,
3257
- filters: JSON.stringify(view.filters),
3258
- createdBy: ctx.email || null,
3259
- });
3260
- }
3261
- const [row] = await db
3262
- .select()
3263
- .from(schema.dashboardViews)
3264
- .where(
3265
- and(
3266
- eq(schema.dashboardViews.id, id),
3267
- eq(schema.dashboardViews.dashboardId, dashboardId),
3268
- ),
3269
- );
3270
- if (!row) {
3271
- throw new Error("Dashboard view was not persisted");
3272
- }
3303
+ if (!saved) {
3304
+ throw new Error("Dashboard view was not persisted");
3305
+ }
3306
+ return saved;
3307
+ });
3273
3308
  const dash = await getDashboard(dashboardId, ctx);
3274
3309
  if (dash) {
3275
3310
  recordScopedChange(
@@ -12,6 +12,7 @@ import { and, eq, inArray, isNull } from "drizzle-orm";
12
12
 
13
13
  import { normalizeDashboardConfig } from "../../shared/dashboard-config-normalization";
14
14
  import { getDb, schema } from "../db/index.js";
15
+ import { remapDashboardViews } from "./dashboard-view-remap.js";
15
16
 
16
17
  const migrationExtensions = table("tools", {
17
18
  id: text("id").primaryKey(),
@@ -684,9 +685,14 @@ export async function migrateAnalyticsArtifacts(
684
685
 
685
686
  for (const group of dashboardDuplicates) {
686
687
  const canonical = oldest(group);
687
- for (const row of group) {
688
- if (row.id !== canonical.id)
689
- duplicateDashboardMap.set(row.id, canonical.id);
688
+ const duplicates = group
689
+ .filter((row) => row.id !== canonical.id)
690
+ .sort(
691
+ (a, b) =>
692
+ a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id),
693
+ );
694
+ for (const row of duplicates) {
695
+ duplicateDashboardMap.set(row.id, canonical.id);
690
696
  }
691
697
  }
692
698
  for (const group of analysisDuplicates) {
@@ -820,10 +826,14 @@ export async function migrateAnalyticsArtifacts(
820
826
  [{ sourceId: duplicateId, targetId: canonicalId }],
821
827
  runId,
822
828
  );
823
- await tx
824
- .update(schema.dashboardViews)
825
- .set({ dashboardId: canonicalId })
826
- .where(eq(schema.dashboardViews.dashboardId, duplicateId));
829
+ await remapDashboardViews(
830
+ tx,
831
+ schema.dashboards,
832
+ schema.dashboardViews,
833
+ ctx.orgId,
834
+ duplicateId,
835
+ canonicalId,
836
+ );
827
837
  await tx
828
838
  .update(schema.dashboardReportSubscriptions)
829
839
  .set({ dashboardId: canonicalId, updatedAt: now })
@@ -833,7 +843,12 @@ export async function migrateAnalyticsArtifacts(
833
843
  await tx
834
844
  .update(schema.dashboards)
835
845
  .set({ archivedAt: now, updatedAt: now, updatedBy: ctx.userEmail })
836
- .where(eq(schema.dashboards.id, duplicateId));
846
+ .where(
847
+ and(
848
+ eq(schema.dashboards.id, duplicateId),
849
+ eq(schema.dashboards.orgId, ctx.orgId),
850
+ ),
851
+ );
837
852
  summary.duplicateDashboardsArchived += 1;
838
853
  }
839
854
 
@@ -1546,6 +1546,13 @@ ALTER TABLE analysis_revisions ADD COLUMN IF NOT EXISTS chat_context TEXT`,
1546
1546
  sql: `ALTER TABLE error_issues ADD COLUMN IF NOT EXISTS test_identity_only BOOLEAN NOT NULL DEFAULT false;
1547
1547
  ALTER TABLE error_events ADD COLUMN IF NOT EXISTS test_identity BOOLEAN NOT NULL DEFAULT false`,
1548
1548
  },
1549
+ {
1550
+ version: 155,
1551
+ name: "dashboard-views-default",
1552
+ sql: `ALTER TABLE dashboard_views ADD COLUMN IF NOT EXISTS is_default BOOLEAN NOT NULL DEFAULT false;
1553
+ CREATE UNIQUE INDEX IF NOT EXISTS dashboard_views_default_per_dashboard_idx
1554
+ ON dashboard_views (dashboard_id) WHERE is_default = true`,
1555
+ },
1549
1556
  ],
1550
1557
  { table: "analytics_migrations" },
1551
1558
  );
@@ -5,6 +5,10 @@ from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
6
  ## 2026-10-05
7
7
 
8
+ ### Improved
9
+
10
+ - Shared recording pages give the agent composer its own background.
11
+
8
12
  ### Fixed
9
13
 
10
14
  - Confirming Discard recording now returns you to your library.
@@ -1564,7 +1564,7 @@ export default function ShareRoute() {
1564
1564
  return (
1565
1565
  <div
1566
1566
  className={cn(
1567
- "clips-recording-view relative flex h-[var(--agent-native-viewport-height,100vh)] min-h-0 w-full max-w-full flex-col overflow-y-auto bg-background lg:grid lg:grid-cols-[minmax(0,1fr)_360px] lg:grid-rows-[auto_minmax(0,1fr)] lg:overflow-hidden xl:grid-cols-[minmax(0,1fr)_420px] [&_.agent-composer-root]:!border-0 [&_.agent-composer-root]:!bg-background",
1567
+ "clips-recording-view relative flex h-[var(--agent-native-viewport-height,100vh)] min-h-0 w-full max-w-full flex-col overflow-y-auto bg-background lg:grid lg:grid-cols-[minmax(0,1fr)_360px] lg:grid-rows-[auto_minmax(0,1fr)] lg:overflow-hidden xl:grid-cols-[minmax(0,1fr)_420px] [&_.agent-composer-root]:!border-0",
1568
1568
  sidePanelCollapsed &&
1569
1569
  "lg:grid-cols-[minmax(0,1fr)_40px] xl:grid-cols-[minmax(0,1fr)_40px]",
1570
1570
  )}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-10-05
4
+ ---
5
+
6
+ Shared recording pages give the agent composer its own background.
@@ -7,6 +7,7 @@ from the command menu (Cmd+K → "What's new") or from Settings.
7
7
 
8
8
  ### Fixed
9
9
 
10
+ - Design frame labels apply truncation as soon as resizing ends.
10
11
  - The Recent tab shows loading placeholders until your designs are ready.
11
12
 
12
13
  ## 2026-10-03
@@ -3,7 +3,7 @@ const CHROME_OPACITY_TRANSITION = "opacity 150ms ease-out";
3
3
  const CHROME_BORDER_SETTLE_TRANSITION = `inset ${CHROME_SETTLE_MS}ms ease-out, border-width ${CHROME_SETTLE_MS}ms ease-out, border-radius ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
4
4
  const SELECTION_BOX_SETTLE_TRANSITION = `border-width ${CHROME_SETTLE_MS}ms ease-out, border-radius ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
5
5
  const CHROME_HANDLE_SETTLE_TRANSITION = `width ${CHROME_SETTLE_MS}ms ease-out, height ${CHROME_SETTLE_MS}ms ease-out, border-width ${CHROME_SETTLE_MS}ms ease-out, top ${CHROME_SETTLE_MS}ms ease-out, bottom ${CHROME_SETTLE_MS}ms ease-out, left ${CHROME_SETTLE_MS}ms ease-out, right ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
6
- const CHROME_LABEL_SETTLE_TRANSITION = `all ${CHROME_SETTLE_MS}ms ease-out`;
6
+ const CHROME_LABEL_SETTLE_TRANSITION = `transform ${CHROME_SETTLE_MS}ms ease-out, ${CHROME_OPACITY_TRANSITION}`;
7
7
 
8
8
  export function getChromeBorderTransition(chromeSettling: boolean) {
9
9
  return chromeSettling
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-10-05
4
+ ---
5
+
6
+ Design frame labels apply truncation as soon as resizing ends.
@@ -5,8 +5,15 @@ time from the command menu (Cmd+K → "What's new").
5
5
 
6
6
  ## 2026-10-05
7
7
 
8
+ ### Improved
9
+
10
+ - The home page shows both library tabs and starter prompts immediately while content loads.
11
+
8
12
  ### Fixed
9
13
 
14
+ - File uploads explain the free Builder.io option and how to connect S3-compatible storage.
15
+ - Slides keeps a pending generation question and its chat available when you leave and reopen a deck.
16
+ - Prompt-generated Slides decks remain when Cmd+Z reaches deck creation.
10
17
  - The Recent tab shows loading placeholders until your decks are ready.
11
18
 
12
19
  ## 2026-10-03
@@ -71,13 +71,13 @@
71
71
  "generic-mcp"
72
72
  ],
73
73
  "chatgpt": {
74
- "version": "1.0.0",
74
+ "version": "1.0.1",
75
75
  "interface": {
76
76
  "displayName": "Agent-Native Slides",
77
77
  "shortDescription": "On-brand presentations",
78
78
  "longDescription": "Create and revise on-brand presentations in your Agent-Native Slides workspace. Start from a brief, inspect decks and design systems, add slides, update existing slide content, and duplicate a deck for a new draft. This connection edits presentations in Agent-Native Slides; it does not directly change PowerPoint or Google Slides files. It can access only decks and design systems available to your connected account.",
79
79
  "developerName": "Builder.io",
80
- "category": "Productivity",
80
+ "category": "Creativity",
81
81
  "capabilities": [
82
82
  "Create presentations from a brief",
83
83
  "Edit slides and decks",
@@ -13,7 +13,6 @@ interface SlidesHomeLibraryProps {
13
13
  recentActions?: ReactNode;
14
14
  templates: ReactNode;
15
15
  recent?: ReactNode;
16
- recentVisible: boolean;
17
16
  }
18
17
 
19
18
  export function SlidesHomeLibrary({
@@ -25,9 +24,8 @@ export function SlidesHomeLibrary({
25
24
  recentActions,
26
25
  templates,
27
26
  recent,
28
- recentVisible,
29
27
  }: SlidesHomeLibraryProps) {
30
- const activeValue = recentVisible ? value : "templates";
28
+ const activeValue = value;
31
29
 
32
30
  return (
33
31
  <section
@@ -45,11 +43,15 @@ export function SlidesHomeLibrary({
45
43
  >
46
44
  <div className="flex flex-wrap items-center justify-between gap-3">
47
45
  <TabsList variant="line">
48
- {recentVisible ? (
49
- <TabsTrigger value="recent" className="flex-none">
50
- {labels.recent}
51
- </TabsTrigger>
52
- ) : null}
46
+ <TabsTrigger
47
+ value="recent"
48
+ className="flex-none"
49
+ onClick={() => {
50
+ if (activeValue === "recent") onValueChange("recent");
51
+ }}
52
+ >
53
+ {labels.recent}
54
+ </TabsTrigger>
53
55
  <TabsTrigger
54
56
  value="templates"
55
57
  className="flex-none"
@@ -70,9 +72,7 @@ export function SlidesHomeLibrary({
70
72
  )}
71
73
  </div>
72
74
  <TabsContent value="templates">{templates}</TabsContent>
73
- {recentVisible ? (
74
- <TabsContent value="recent">{recent}</TabsContent>
75
- ) : null}
75
+ <TabsContent value="recent">{recent}</TabsContent>
76
76
  </Tabs>
77
77
  </section>
78
78
  );
@@ -476,6 +476,7 @@ interface DeckContextType {
476
476
  noDefaultSlides?: boolean;
477
477
  designSystemId?: string | null;
478
478
  deferPersistence?: boolean;
479
+ undoableCreation?: boolean;
479
480
  },
480
481
  ) => Deck;
481
482
  ensureDeckPersisted: (id: string) => Promise<DeckPersistenceResult>;
@@ -5432,6 +5433,7 @@ export function DeckProvider({
5432
5433
  noDefaultSlides?: boolean;
5433
5434
  designSystemId?: string | null;
5434
5435
  deferPersistence?: boolean;
5436
+ undoableCreation?: boolean;
5435
5437
  },
5436
5438
  ): Deck => {
5437
5439
  const insertIndex = decksRef.current.length;
@@ -5482,18 +5484,20 @@ export function DeckProvider({
5482
5484
  });
5483
5485
  }
5484
5486
  setDecksLocal((prev) => [...prev, newDeck]);
5485
- undoControllerForDeck(newDeck.id).push({
5486
- undo: [{ op: "delete-deck", deckId: newDeck.id }],
5487
- redo: [
5488
- {
5489
- op: "restore-deck",
5490
- deckId: newDeck.id,
5491
- deck: newDeck,
5492
- index: insertIndex,
5493
- },
5494
- ],
5495
- label: "Create deck",
5496
- });
5487
+ if (options?.undoableCreation !== false) {
5488
+ undoControllerForDeck(newDeck.id).push({
5489
+ undo: [{ op: "delete-deck", deckId: newDeck.id }],
5490
+ redo: [
5491
+ {
5492
+ op: "restore-deck",
5493
+ deckId: newDeck.id,
5494
+ deck: newDeck,
5495
+ index: insertIndex,
5496
+ },
5497
+ ],
5498
+ label: "Create deck",
5499
+ });
5500
+ }
5497
5501
  return newDeck;
5498
5502
  },
5499
5503
  [noteLocalCreate, setDecksLocal, undoControllerForDeck],