@agent-native/core 0.149.4 → 0.149.6

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 (58) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +5 -0
  3. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +5 -0
  4. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +5 -0
  5. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +5 -0
  6. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
  7. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +5 -0
  8. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +5 -0
  9. package/corpus/templates/content/actions/_document-discovery-query.ts +127 -0
  10. package/corpus/templates/content/actions/list-documents.ts +189 -198
  11. package/corpus/templates/content/actions/search-documents.ts +95 -24
  12. package/corpus/templates/content/app/hooks/use-documents.ts +84 -6
  13. package/corpus/templates/content/shared/api.ts +10 -0
  14. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +5 -0
  15. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +5 -0
  16. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +5 -0
  17. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +5 -0
  18. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +5 -0
  19. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +5 -0
  20. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +5 -0
  21. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +5 -0
  22. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +23 -4
  23. package/corpus/templates/slides/actions/get-deck.ts +25 -9
  24. package/corpus/templates/slides/actions/patch-deck.ts +51 -0
  25. package/corpus/templates/slides/actions/update-slide.ts +144 -14
  26. package/corpus/templates/slides/app/lib/create-deck-generation.ts +12 -4
  27. package/corpus/templates/slides/changelog/2026-08-11-pdf-requests-to-restyle-and-preserve-a-source-deck-now-impor.md +6 -0
  28. package/corpus/templates/slides/changelog/2026-08-11-slide-edits-preserve-their-layout-without-introducing-hidden.md +6 -0
  29. package/corpus/templates/slides/changelog/2026-08-11-slides-reliably-imports-uploaded-pdfs-and-presentations.md +6 -0
  30. package/corpus/templates/slides/changelog/2026-08-11-slides-support-atomic-code-style-html-patches-without-regene.md +6 -0
  31. package/corpus/templates/slides/package.json +1 -0
  32. package/corpus/templates/slides/server/lib/slide-content-patch.ts +355 -0
  33. package/corpus/templates/slides/server/lib/uploaded-reference-storage.ts +28 -9
  34. package/corpus/templates/slides/server/plugins/agent-chat.ts +12 -3
  35. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +5 -0
  36. package/dist/cli/create.js +49 -0
  37. package/dist/client/chat-first/index.d.ts +1 -1
  38. package/dist/client/chat-first/index.js +1 -1
  39. package/dist/client/chat-first/primary-nav.d.ts +3 -1
  40. package/dist/client/chat-first/primary-nav.js +8 -2
  41. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  42. package/dist/notifications/routes.d.ts +3 -3
  43. package/dist/observability/routes.d.ts +3 -3
  44. package/dist/private-blob/registry.js +67 -4
  45. package/dist/resources/handlers.d.ts +1 -1
  46. package/dist/server/realtime-token.d.ts +1 -1
  47. package/dist/server/transcribe-voice.d.ts +1 -1
  48. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
  49. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
  50. package/dist/templates/default/pnpm-workspace.yaml +44 -0
  51. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
  52. package/dist/templates/workspace-root/pnpm-workspace.yaml +44 -0
  53. package/package.json +1 -1
  54. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
  55. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
  56. package/src/templates/default/pnpm-workspace.yaml +44 -0
  57. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
  58. package/src/templates/workspace-root/pnpm-workspace.yaml +44 -0
@@ -1,4 +1,5 @@
1
1
  import {
2
+ callAction,
2
3
  useActionQuery,
3
4
  useActionMutation,
4
5
  } from "@agent-native/core/client/hooks";
@@ -7,6 +8,7 @@ import type {
7
8
  ContentDatabaseItem,
8
9
  Document,
9
10
  DocumentCreateRequest,
11
+ DocumentListResponse,
10
12
  DocumentPropertiesResponse,
11
13
  DocumentUpdateRequest,
12
14
  DocumentUpdateResponse,
@@ -15,7 +17,7 @@ import type {
15
17
  DocumentTreeNode,
16
18
  } from "@shared/api";
17
19
  import type { QueryClient } from "@tanstack/react-query";
18
- import { useQueryClient } from "@tanstack/react-query";
20
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
19
21
  import { toast } from "sonner";
20
22
 
21
23
  import type { DocumentUpdateConflictResponse } from "../../actions/update-document";
@@ -63,6 +65,74 @@ export const LIST_DOCUMENTS_QUERY_KEY = [
63
65
  undefined,
64
66
  ] as const;
65
67
 
68
+ const DOCUMENT_LIST_PAGE_SIZE = 200;
69
+
70
+ export async function fetchCompleteDocumentList(
71
+ fetchPage: (offset: number, limit: number) => Promise<DocumentListResponse>,
72
+ ) {
73
+ const documents: Document[] = [];
74
+ const documentIds = new Set<string>();
75
+ let offset = 0;
76
+ let expectedTotal: number | null = null;
77
+
78
+ while (true) {
79
+ const page = await fetchPage(offset, DOCUMENT_LIST_PAGE_SIZE);
80
+ const { pagination } = page;
81
+ if (!pagination) {
82
+ throw new Error(
83
+ "list-documents returned no pagination boundary; refusing to treat the result as complete.",
84
+ );
85
+ }
86
+ if (
87
+ pagination.offset !== offset ||
88
+ pagination.limit !== DOCUMENT_LIST_PAGE_SIZE ||
89
+ pagination.returnedItems !== page.documents.length
90
+ ) {
91
+ throw new Error(
92
+ "list-documents returned inconsistent pagination metadata; retry the complete read.",
93
+ );
94
+ }
95
+ if (expectedTotal === null) expectedTotal = pagination.totalItems;
96
+ if (pagination.totalItems !== expectedTotal) {
97
+ throw new Error(
98
+ "Documents changed during paginated discovery; retry the complete read.",
99
+ );
100
+ }
101
+ for (const document of page.documents) {
102
+ if (documentIds.has(document.id)) {
103
+ throw new Error(
104
+ `list-documents repeated document "${document.id}" across pages; refusing an ambiguous result.`,
105
+ );
106
+ }
107
+ documentIds.add(document.id);
108
+ documents.push(document);
109
+ }
110
+
111
+ const expectedNextOffset = offset + page.documents.length;
112
+ if (!pagination.hasMore) {
113
+ if (
114
+ pagination.nextOffset !== null ||
115
+ expectedNextOffset !== expectedTotal ||
116
+ documents.length !== expectedTotal
117
+ ) {
118
+ throw new Error(
119
+ "list-documents claimed exhaustion before every declared document was returned.",
120
+ );
121
+ }
122
+ return documents;
123
+ }
124
+ if (
125
+ pagination.nextOffset !== expectedNextOffset ||
126
+ pagination.nextOffset <= offset
127
+ ) {
128
+ throw new Error(
129
+ "list-documents returned a non-advancing continuation; refusing a clipped result.",
130
+ );
131
+ }
132
+ offset = pagination.nextOffset;
133
+ }
134
+ }
135
+
66
136
  export function documentPropertiesQueryKey(
67
137
  documentId: string,
68
138
  databaseId: string,
@@ -317,11 +387,19 @@ export function seedDatabaseItemDocumentCaches(
317
387
  }
318
388
 
319
389
  export function useDocuments() {
320
- return useActionQuery<Document[]>("list-documents", undefined, {
321
- select: (data: any) => {
322
- const docs = data?.documents ?? data;
323
- return Array.isArray(docs) ? docs : [];
324
- },
390
+ return useQuery({
391
+ queryKey: LIST_DOCUMENTS_QUERY_KEY,
392
+ queryFn: async ({ signal }) => ({
393
+ documents: await fetchCompleteDocumentList((offset, limit) =>
394
+ callAction<DocumentListResponse>(
395
+ "list-documents",
396
+ { offset, limit },
397
+ { method: "GET", signal },
398
+ ),
399
+ ),
400
+ }),
401
+ select: (data) => data.documents,
402
+ retry: false,
325
403
  });
326
404
  }
327
405
 
@@ -128,6 +128,16 @@ export interface DocumentMoveRequest {
128
128
 
129
129
  export interface DocumentListResponse {
130
130
  documents: Document[];
131
+ pagination: DocumentDiscoveryPagination;
132
+ }
133
+
134
+ export interface DocumentDiscoveryPagination {
135
+ offset: number;
136
+ limit: number;
137
+ totalItems: number;
138
+ returnedItems: number;
139
+ hasMore: boolean;
140
+ nextOffset: number | null;
131
141
  }
132
142
 
133
143
  export interface DocumentTreeNode extends Document {
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
168
168
  - Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
169
169
  - Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
170
170
  - Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
171
+ - Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
172
+ plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
173
+ an icon you haven't used elsewhere in this app, confirm it exists by grepping
174
+ `node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
175
+ for the exact name, and pick the closest real match if your first guess isn't there.
171
176
  - Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
172
177
  - Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
173
178
  - Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
@@ -72,10 +72,17 @@ To edit a slide's content:
72
72
  3. **Modify the content** HTML string for the intended slide. Preserve an
73
73
  approved native template or component when it already fits; generate
74
74
  net-new structure only when the relevant corpus is empty.
75
- 4. **Update the slide** with the `update-slide` action using `deckId`,
76
- `slideId`, and `fullContent`. Do not write deck rows directly or add raw
77
- full-deck writes for normal slide edits; use `patch-deck` for browser/editor
78
- changes.
75
+ 4. **Update the slide** with `update-slide` using `deckId`, `slideId`, and
76
+ ordered `edits`. For code-style work, first read with `get-deck` using the
77
+ target `slideId`, `compact=false`, and `format=true`, then send the returned
78
+ `contentHash` as `baseContentHash`. Use exact replace, insert before/after,
79
+ replace between markers, or regex replace. Set `expectedMatches` whenever a
80
+ marker could be ambiguous. All edits are applied in memory under the deck
81
+ lock; if one required edit fails, nothing is written. Set `format=true` on
82
+ `update-slide` to persist readable Prettier line breaks. Use `fullContent`
83
+ only for an intentional full rewrite - do not regenerate a slide to make a
84
+ small change. Do not write deck rows directly or add raw full-deck writes;
85
+ use `patch-deck` for browser/editor changes.
79
86
  5. For browser/editor code, enqueue granular deck operations through
80
87
  `patch-deck` / `DeckContext.tsx` instead of replacing the whole deck JSON.
81
88
 
@@ -83,6 +90,18 @@ To edit a slide's content:
83
90
  preserve quote, speaker, date, metric, and uncertainty status. Existing HTML
84
91
  or visual similarity is not proof of source fidelity.
85
92
 
93
+ ## Click-to-reveal animations
94
+
95
+ Animations are metadata over the final slide HTML, not alternate slide markup.
96
+ Read the full target slide, keep its existing visual structure, and patch the
97
+ complete ordered `animations` list with `elementPath` values from that exact
98
+ HTML. Elements omitted from the list remain visible immediately, so labels and
99
+ headings need no duplicate markup. Do not add hidden duplicates, layout
100
+ spacers, absolute-positioned copies, transforms, or placeholder content to
101
+ simulate reveals. When content and reveals change together, send both fields in
102
+ one `patch-deck` operation. To remove reveals, send `animations: []` with the
103
+ existing content and verify the persisted slide afterward.
104
+
86
105
  If retrieval produces a new immutable context pack, keep its `contextPackId`
87
106
  and reuse labels with the deck provenance. Existing slide HTML is not proof of
88
107
  which source version influenced it.
@@ -4,7 +4,9 @@ import { getRequestUserEmail } from "@agent-native/core/server/request-context";
4
4
  import { resolveAccess } from "@agent-native/core/sharing";
5
5
  import { z } from "zod";
6
6
 
7
+ import { formatSlideHtml } from "../server/lib/slide-content-patch.js";
7
8
  import { summarizeSlideAnimationTargets } from "../server/lib/validate-slide-animations.js";
9
+ import { hashSlideContent } from "../shared/slide-fit.js";
8
10
  import "../server/db/index.js"; // ensure registerShareableResource runs
9
11
 
10
12
  function stripHtml(html: string): string {
@@ -76,6 +78,12 @@ export default defineAction({
76
78
  .describe(
77
79
  "Set to 'true' for compact slide summaries, or 'false' for full slide HTML. In-app agent calls without slideId default to compact output.",
78
80
  ),
81
+ format: z
82
+ .enum(["true", "false"])
83
+ .optional()
84
+ .describe(
85
+ "Set to 'true' to return full slide HTML formatted with Prettier for code-style patches. The contentHash still identifies the persisted source.",
86
+ ),
79
87
  }),
80
88
  http: { method: "GET" },
81
89
  mcpApp: {
@@ -169,6 +177,22 @@ export default defineAction({
169
177
  const deckMetadata = { ...data };
170
178
  delete deckMetadata.slides;
171
179
 
180
+ const formatHtml = args.format === "true";
181
+ const fullSlides = await Promise.all(
182
+ slideEntries.map(async ({ slide: s, index: i }) => ({
183
+ ...s,
184
+ slideNumber: i + 1,
185
+ zeroBasedIndex: i,
186
+ id: s.id,
187
+ layout: s.layout ?? null,
188
+ content: formatHtml
189
+ ? await formatSlideHtml(String(s.content ?? ""))
190
+ : s.content,
191
+ contentHash: hashSlideContent(String(s.content ?? "")),
192
+ notes: s.notes ?? null,
193
+ })),
194
+ );
195
+
172
196
  return {
173
197
  ...deckMetadata,
174
198
  id: row.id,
@@ -184,15 +208,7 @@ export default defineAction({
184
208
  updatedAt: row.updatedAt,
185
209
  deepLink: deckDeepLink(row.id),
186
210
  ...(selectedSlide ? { selectedSlideId: selectedSlide.id } : {}),
187
- slides: slideEntries.map(({ slide: s, index: i }) => ({
188
- ...s,
189
- slideNumber: i + 1,
190
- zeroBasedIndex: i,
191
- id: s.id,
192
- layout: s.layout ?? null,
193
- content: s.content,
194
- notes: s.notes ?? null,
195
- })),
211
+ slides: fullSlides,
196
212
  };
197
213
  },
198
214
  link: ({ result, args }) => {
@@ -434,6 +434,52 @@ export function applyOperation(deck: any, op: Operation): void {
434
434
  }
435
435
  }
436
436
 
437
+ /**
438
+ * Agent content rewrites must not inherit click-reveal paths implicitly. A
439
+ * caller that wants to revise both HTML and reveals sends `animations` in the
440
+ * same patch, including the complete ordered list. Source-preserving edits are
441
+ * the exception: they retain imported reveal metadata unless the caller opts
442
+ * into an explicit source rewrite.
443
+ */
444
+ export function clearOmittedAnimationsForAgentContentPatches(
445
+ deck: any,
446
+ operations: readonly Operation[],
447
+ options?: { sourceImport?: SourceImportMetadata | null },
448
+ ): void {
449
+ const explicitAnimationSlideIds = new Set(
450
+ operations.flatMap((operation) =>
451
+ operation.op === "patch-slide" &&
452
+ operation.fields.animations !== undefined
453
+ ? [operation.slideId]
454
+ : [],
455
+ ),
456
+ );
457
+ const sourceSlideIds = new Set(
458
+ options?.sourceImport?.slideIds ??
459
+ options?.sourceImport?.slides.map((slide) => slide.id) ??
460
+ [],
461
+ );
462
+ const slideIds = new Set(
463
+ operations.flatMap((operation) =>
464
+ operation.op === "patch-slide" &&
465
+ operation.fields.content !== undefined &&
466
+ operation.fields.animations === undefined &&
467
+ !explicitAnimationSlideIds.has(operation.slideId) &&
468
+ (operation.preserveSource === false ||
469
+ !sourceSlideIds.has(operation.slideId))
470
+ ? [operation.slideId]
471
+ : [],
472
+ ),
473
+ );
474
+ if (!slideIds.size) return;
475
+
476
+ for (const slide of Array.isArray(deck.slides) ? deck.slides : []) {
477
+ if (slideIds.has(slide?.id) && Array.isArray(slide.animations)) {
478
+ delete slide.animations;
479
+ }
480
+ }
481
+ }
482
+
437
483
  /**
438
484
  * Content and animation metadata are one contract. Validate only slides whose
439
485
  * content or animation list changed so unrelated note/title writes do not
@@ -620,6 +666,11 @@ export default defineAction({
620
666
  for (const op of operations) {
621
667
  applyOperation(deck, op);
622
668
  }
669
+ if (isAgentCaller) {
670
+ clearOmittedAnimationsForAgentContentPatches(deck, operations, {
671
+ sourceImport,
672
+ });
673
+ }
623
674
  assertPatchedSlideAnimationsResolve(deck, operations, {
624
675
  requireElementPaths: isAgentCaller,
625
676
  });