@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/content/actions/_document-discovery-query.ts +127 -0
- package/corpus/templates/content/actions/list-documents.ts +189 -198
- package/corpus/templates/content/actions/search-documents.ts +95 -24
- package/corpus/templates/content/app/hooks/use-documents.ts +84 -6
- package/corpus/templates/content/shared/api.ts +10 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +23 -4
- package/corpus/templates/slides/actions/get-deck.ts +25 -9
- package/corpus/templates/slides/actions/patch-deck.ts +51 -0
- package/corpus/templates/slides/actions/update-slide.ts +144 -14
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +12 -4
- package/corpus/templates/slides/changelog/2026-08-11-pdf-requests-to-restyle-and-preserve-a-source-deck-now-impor.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slide-edits-preserve-their-layout-without-introducing-hidden.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-reliably-imports-uploaded-pdfs-and-presentations.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-support-atomic-code-style-html-patches-without-regene.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/lib/slide-content-patch.ts +355 -0
- package/corpus/templates/slides/server/lib/uploaded-reference-storage.ts +28 -9
- package/corpus/templates/slides/server/plugins/agent-chat.ts +12 -3
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/cli/create.js +49 -0
- package/dist/client/chat-first/index.d.ts +1 -1
- package/dist/client/chat-first/index.js +1 -1
- package/dist/client/chat-first/primary-nav.d.ts +3 -1
- package/dist/client/chat-first/primary-nav.js +8 -2
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/private-blob/registry.js +67 -4
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/default/pnpm-workspace.yaml +44 -0
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/workspace-root/pnpm-workspace.yaml +44 -0
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/default/pnpm-workspace.yaml +44 -0
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- 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
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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:
|
|
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
|
});
|