@agent-native/core 0.148.1 → 0.149.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/changelog/2026-08-10-wide-tables-in-analytics-chat-now-scroll-horizontally-within.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +13 -53
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -70
- package/corpus/templates/calendar/app/lib/event-layout.ts +122 -0
- package/corpus/templates/calendar/app/routes/_app.availability.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-08-10-opening-availability-settings-from-the-agent-lands-on-the-av.md +6 -0
- package/corpus/templates/calendar/vitest.config.ts +6 -1
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +3 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +44 -4
- package/corpus/templates/clips/changelog/2026-08-10-fixed-transcription-failures-for-recordings-without-captured.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-10-mobile-clips-can-now-enter-fullscreen-on-iphone-safari.md +6 -0
- package/corpus/templates/content/actions/_property-utils.ts +11 -1
- package/corpus/templates/content/actions/view-screen.ts +62 -12
- package/corpus/templates/content/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +22 -0
- package/corpus/templates/design/AGENTS.md +3 -0
- package/corpus/templates/design/actions/create-design-from-template.ts +19 -0
- package/corpus/templates/design/actions/get-design-snapshot.ts +18 -0
- package/corpus/templates/design/actions/get-design-template.ts +178 -0
- package/corpus/templates/design/actions/list-designs.ts +3 -1
- package/corpus/templates/design/actions/view-screen.ts +31 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +225 -214
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +78 -0
- package/corpus/templates/design/app/lib/design-authors.ts +64 -0
- package/corpus/templates/design/app/pages/Index.tsx +114 -4
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +1 -0
- package/corpus/templates/design/changelog/2026-08-07-alt-dragging-an-element-to-copy-it-now-keeps-the-copy-visibl.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-design-cards-now-show-who-created-each-design-with-a-filter-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-drawing-a-shape-on-the-overview-canvas-now-keeps-the-shape-s.md +6 -0
- package/corpus/templates/design/changelog/2026-08-07-hold-option-alt-while-dragging-a-frame-on-the-overview-canva.md +6 -0
- package/corpus/templates/design/server/lib/design-template-data.ts +143 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/AGENTS.md +2 -2
- package/corpus/templates/forms/actions/create-form.ts +1 -1
- package/corpus/templates/forms/actions/update-form.ts +5 -5
- package/corpus/templates/forms/changelog/2026-08-10-forms-now-keep-agent-applied-field-changes-visible-after-an-.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-10-published-form-links-always-use-the-working-public-form-url.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/slides/AGENTS.md +4 -3
- package/corpus/templates/slides/actions/import-google-slides-reference.ts +56 -10
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +12 -74
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +15 -4
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +116 -55
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +143 -18
- package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
- package/corpus/templates/slides/app/lib/generation-state.ts +7 -1
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +32 -14
- package/corpus/templates/slides/app/pages/Index.tsx +110 -128
- package/corpus/templates/slides/changelog/2026-08-10-imported-reference-decks-now-show-clear-success-and-stay-sel.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-pasted-google-slides-links-import-after-reconnecting-google-.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +4 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +13 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/dist/agent/engine/registry.d.ts +8 -2
- package/dist/agent/engine/registry.js +63 -29
- package/dist/agent/production-agent.js +7 -0
- package/dist/agent/run-manager.d.ts +5 -4
- package/dist/agent/run-manager.js +6 -5
- package/dist/cli/claude-code-participant.d.ts +2 -1
- package/dist/cli/claude-code-participant.js +19 -0
- package/dist/cli/code-agent-executor.js +223 -0
- package/dist/cli/create-workspace.js +3 -3
- package/dist/cli/create.d.ts +3 -2
- package/dist/cli/create.js +20 -24
- package/dist/client/AgentPanel.js +8 -4
- package/dist/client/AssistantChat.js +34 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -0
- package/dist/client/agent-chat-adapter.js +10 -2
- package/dist/client/chat/markdown-renderer.d.ts +1 -0
- package/dist/client/chat/markdown-renderer.js +4 -0
- package/dist/client/chat/message-components.d.ts +1 -0
- package/dist/client/chat/message-components.js +9 -1
- package/dist/client/chat/tool-call-display.d.ts +8 -0
- package/dist/client/chat/tool-call-display.js +30 -21
- package/dist/client/chat-first/app-pane.js +1 -1
- package/dist/client/chat-first/apps-rail.d.ts +1 -1
- package/dist/client/chat-first/apps-rail.js +11 -11
- package/dist/client/chat-first/chat-history.d.ts +1 -1
- package/dist/client/chat-first/chat-history.js +2 -0
- package/dist/client/chat-first/primary-nav.js +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +2 -2
- package/dist/client/settings/SettingsTabsPage.d.ts +3 -1
- package/dist/client/settings/SettingsTabsPage.js +2 -2
- package/dist/client/sse-event-processor.d.ts +8 -0
- package/dist/client/sse-event-processor.js +13 -6
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +5 -7
- package/dist/deploy/build.js +19 -12
- package/dist/localization/default-messages.js +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/call-agent.js +3 -3
- package/dist/scripts/describe-workspace-apps.js +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-capabilities.js +0 -0
- package/dist/server/agent-chat/context-tools.js +1 -1
- package/dist/server/agent-chat/prompt-resources.js +1 -1
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/auth.js +190 -42
- package/dist/server/better-auth-migrations.js +53 -0
- package/dist/server/http-response-telemetry.js +7 -1
- package/dist/server/onboarding-html.js +119 -33
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/password-policy.d.ts +2 -1
- package/dist/shared/password-policy.js +2 -1
- package/dist/styles/agent-conversation.css +20 -3
- package/dist/styles/agent-native.css +14 -2
- package/dist/templates/default/app/i18n/ar-SA.ts +1 -1
- package/dist/templates/default/app/i18n/de-DE.ts +1 -1
- package/dist/templates/default/app/i18n/en-US.ts +1 -1
- package/dist/templates/default/app/i18n/es-ES.ts +1 -1
- package/dist/templates/default/app/i18n/fr-FR.ts +1 -1
- package/dist/templates/default/app/i18n/hi-IN.ts +1 -1
- package/dist/templates/default/app/i18n/ja-JP.ts +1 -1
- package/dist/templates/default/app/i18n/ko-KR.ts +1 -1
- package/dist/templates/default/app/i18n/pt-BR.ts +1 -1
- package/dist/templates/default/app/i18n/zh-CN.ts +1 -1
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
- package/dist/templates/default/pnpm-workspace.yaml +1 -0
- package/dist/templates/workspace-root/pnpm-workspace.yaml +2 -0
- package/docs/content/cloneable-saas.mdx +6 -6
- package/docs/content/deployment.mdx +10 -8
- package/docs/content/environment-variables.mdx +4 -3
- package/package.json +2 -2
- package/src/templates/default/app/i18n/ar-SA.ts +1 -1
- package/src/templates/default/app/i18n/de-DE.ts +1 -1
- package/src/templates/default/app/i18n/en-US.ts +1 -1
- package/src/templates/default/app/i18n/es-ES.ts +1 -1
- package/src/templates/default/app/i18n/fr-FR.ts +1 -1
- package/src/templates/default/app/i18n/hi-IN.ts +1 -1
- package/src/templates/default/app/i18n/ja-JP.ts +1 -1
- package/src/templates/default/app/i18n/ko-KR.ts +1 -1
- package/src/templates/default/app/i18n/pt-BR.ts +1 -1
- package/src/templates/default/app/i18n/zh-CN.ts +1 -1
- package/src/templates/default/app/i18n/zh-TW.ts +1 -1
- package/src/templates/default/pnpm-workspace.yaml +1 -0
- package/src/templates/workspace-root/pnpm-workspace.yaml +2 -0
|
@@ -43,6 +43,8 @@ export default createAgentChatPlugin({
|
|
|
43
43
|
resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
|
|
44
44
|
systemPrompt: `You are an AI document assistant. You manage documents, comments, media blocks, sharing, and connected Notion content through actions and shared application state.
|
|
45
45
|
|
|
46
|
+
The current screen is already included as bounded context on every message. Do not call view-screen at the start of a turn or repeatedly; call it only when that context is stale. Its document body is a preview, so call get-document when the full page content is required.
|
|
47
|
+
|
|
46
48
|
Some less-common tool schemas are loaded on demand. Use tool-search with a specific query when you need a capability that is not already available as a direct tool.
|
|
47
49
|
|
|
48
50
|
Provider-specific Content actions are shortcuts, not limits. If a first-class action cannot express the exact Notion endpoint, page/database/comment object, filter, request body, pagination mode, markdown endpoint, payload shape, or API version needed, call provider-api-catalog and provider-api-docs as needed, then call provider-api-request against the real Notion API. Use the raw provider API escape hatch instead of weakening the answer, broadening filters, or claiming Content cannot do something the underlying Notion API can do.
|
|
@@ -38,6 +38,28 @@ description: >-
|
|
|
38
38
|
dimensions, linked design system, and locked-layer boundaries before
|
|
39
39
|
reporting completion.
|
|
40
40
|
|
|
41
|
+
## The Template On Follow-Up Requests
|
|
42
|
+
|
|
43
|
+
A copied screen is edited in place. After the first refinement saves, the
|
|
44
|
+
design's own files are the *result*, not the template — so a later turn that
|
|
45
|
+
reads only `get-design-snapshot` has no idea what the template specified, and
|
|
46
|
+
fonts and artboard dimensions drift a little further on each request.
|
|
47
|
+
|
|
48
|
+
The two facts that drift are cheap, so they arrive on their own. `view-screen`
|
|
49
|
+
reports `design.createdFromTemplate` on every turn for a template-created
|
|
50
|
+
design, carrying `lockedDimensions` per screen and `lockedFonts`. Both are
|
|
51
|
+
captured from the template at copy time, so they describe the template even
|
|
52
|
+
after the design has been edited many times. Honour them in every
|
|
53
|
+
`edit-design` pass: never resize the artboard, change a `canvasFrames` width or
|
|
54
|
+
height, switch the primary viewport, or substitute a typeface to fit new
|
|
55
|
+
content.
|
|
56
|
+
|
|
57
|
+
Call `get-design-template --designId="<id>"` when you need more than those two
|
|
58
|
+
facts — the template's original markup, or its locked layers — for example
|
|
59
|
+
before a structural edit or when the user asks how far the design has moved
|
|
60
|
+
from its template. The full template files are large, which is why they are a
|
|
61
|
+
deliberate second call rather than part of every turn.
|
|
62
|
+
|
|
41
63
|
## Locked Layers
|
|
42
64
|
|
|
43
65
|
`data-agent-native-locked="true"` is authoritative. Keep each locked element
|
|
@@ -42,6 +42,9 @@ ladder.
|
|
|
42
42
|
- Resolve templates or prior designs with `list-design-templates` and
|
|
43
43
|
`list-designs`, copy with `create-design-from-template`, then inspect and
|
|
44
44
|
adapt copied files with `get-design-snapshot` and `edit-design`.
|
|
45
|
+
- Copied template screens are edited in place. Preserve
|
|
46
|
+
`createdFromTemplate.lockedDimensions`/`lockedFonts` from `view-screen` in
|
|
47
|
+
every edit; `get-design-template` returns the original.
|
|
45
48
|
|
|
46
49
|
## Core Rules
|
|
47
50
|
|
|
@@ -11,8 +11,10 @@ import { z } from "zod";
|
|
|
11
11
|
|
|
12
12
|
import { getDb, schema } from "../server/db/index.js";
|
|
13
13
|
import {
|
|
14
|
+
extractTemplateFonts,
|
|
14
15
|
redactTemplateDesignData,
|
|
15
16
|
remapTemplateFileIds,
|
|
17
|
+
templateFileDimensions,
|
|
16
18
|
} from "../server/lib/design-template-data.js";
|
|
17
19
|
import { getDesignTemplatePreset } from "../shared/design-template-presets.js";
|
|
18
20
|
import { countLockedLayersAcrossFiles } from "../shared/locked-layers.js";
|
|
@@ -149,6 +151,11 @@ export default defineAction({
|
|
|
149
151
|
redactTemplateDesignData(templateData),
|
|
150
152
|
fileIdMap,
|
|
151
153
|
);
|
|
154
|
+
// The copied screens are edited in place, so the design's own files stop
|
|
155
|
+
// being evidence of what the template looked like after the first
|
|
156
|
+
// refinement. Capturing the small facts here — which template file backs
|
|
157
|
+
// each screen, its exact frame, and the declared fonts — is what lets
|
|
158
|
+
// every later turn restate them without re-reading the template.
|
|
152
159
|
data.templateSource = {
|
|
153
160
|
templateId,
|
|
154
161
|
title: templateTitle,
|
|
@@ -158,6 +165,18 @@ export default defineAction({
|
|
|
158
165
|
templateDesignSystemId,
|
|
159
166
|
appliedDesignSystemId: linkedDesignSystemId,
|
|
160
167
|
designSystemOverridden,
|
|
168
|
+
files: files.map((file) => {
|
|
169
|
+
const designFileId = fileIdMap.get(file.id)!;
|
|
170
|
+
const { width, height } = templateFileDimensions(data, designFileId);
|
|
171
|
+
return {
|
|
172
|
+
designFileId,
|
|
173
|
+
templateFileId: file.id,
|
|
174
|
+
filename: file.filename,
|
|
175
|
+
width,
|
|
176
|
+
height,
|
|
177
|
+
};
|
|
178
|
+
}),
|
|
179
|
+
fonts: extractTemplateFonts(files.map((file) => file.content).join("\n")),
|
|
161
180
|
};
|
|
162
181
|
if (prompt) data.templatePrompt = prompt;
|
|
163
182
|
|
|
@@ -5,6 +5,10 @@ import { z } from "zod";
|
|
|
5
5
|
|
|
6
6
|
import { schema } from "../server/db/index.js";
|
|
7
7
|
import { buildDesignSnapshot } from "../server/lib/design-snapshot.js";
|
|
8
|
+
import {
|
|
9
|
+
parseDesignTemplateData,
|
|
10
|
+
readDesignTemplateSource,
|
|
11
|
+
} from "../server/lib/design-template-data.js";
|
|
8
12
|
import { lockedLayerSnapshots } from "../shared/locked-layers.js";
|
|
9
13
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
10
14
|
|
|
@@ -66,6 +70,9 @@ export default defineAction({
|
|
|
66
70
|
const design = access.resource as typeof schema.designs.$inferSelect;
|
|
67
71
|
|
|
68
72
|
const snapshot = await buildDesignSnapshot(designId, design.data);
|
|
73
|
+
const templateSource = readDesignTemplateSource(
|
|
74
|
+
parseDesignTemplateData(design.data),
|
|
75
|
+
);
|
|
69
76
|
const requestedFileId = fileId?.trim();
|
|
70
77
|
const requestedFilename = filename?.trim();
|
|
71
78
|
const files = requestedFileId
|
|
@@ -97,6 +104,17 @@ export default defineAction({
|
|
|
97
104
|
projectType: design.projectType,
|
|
98
105
|
designSystemId: design.designSystemId ?? null,
|
|
99
106
|
updatedAt: design.updatedAt,
|
|
107
|
+
...(templateSource
|
|
108
|
+
? {
|
|
109
|
+
createdFromTemplate: {
|
|
110
|
+
templateId: templateSource.templateId,
|
|
111
|
+
title: templateSource.title,
|
|
112
|
+
note:
|
|
113
|
+
"These files are edited copies of the template, not the template itself. " +
|
|
114
|
+
`Call \`get-design-template --designId="${designId}"\` for the original canvas dimensions, typography, and locked layers, and preserve them in this edit.`,
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
: {}),
|
|
100
118
|
files: files.map((f) => ({
|
|
101
119
|
id: f.id,
|
|
102
120
|
filename: f.filename,
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { resolveAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { eq } from "drizzle-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import {
|
|
8
|
+
parseDesignTemplateData,
|
|
9
|
+
readDesignTemplateSource,
|
|
10
|
+
templateFileDimensions,
|
|
11
|
+
} from "../server/lib/design-template-data.js";
|
|
12
|
+
import { getDesignTemplatePreset } from "../shared/design-template-presets.js";
|
|
13
|
+
import { lockedLayerSnapshots } from "../shared/locked-layers.js";
|
|
14
|
+
|
|
15
|
+
interface OriginalTemplateFile {
|
|
16
|
+
templateFileId: string;
|
|
17
|
+
filename: string;
|
|
18
|
+
fileType: string;
|
|
19
|
+
content: string;
|
|
20
|
+
width: number | null;
|
|
21
|
+
height: number | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default defineAction({
|
|
25
|
+
description:
|
|
26
|
+
"Read the ORIGINAL, unmodified template a design was created from. " +
|
|
27
|
+
"Copied template screens are edited in place, so the design's own files stop showing what the template looked like as soon as the first refinement lands. " +
|
|
28
|
+
"Call this on any follow-up request against a template-created design to recover the template's exact canvas dimensions, typography, and markup before editing. " +
|
|
29
|
+
"Pass designId to resolve the template behind an open design, or templateId to read a template directly. Read-only.",
|
|
30
|
+
schema: z
|
|
31
|
+
.object({
|
|
32
|
+
designId: z
|
|
33
|
+
.string()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Design created from a template; resolves its template"),
|
|
36
|
+
templateId: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Template to read directly when the design id is unknown"),
|
|
40
|
+
})
|
|
41
|
+
.refine((input) => input.designId || input.templateId, {
|
|
42
|
+
message: "Pass designId or templateId",
|
|
43
|
+
}),
|
|
44
|
+
readOnly: true,
|
|
45
|
+
http: { method: "GET" },
|
|
46
|
+
run: async ({ designId, templateId }) => {
|
|
47
|
+
let resolvedTemplateId = templateId;
|
|
48
|
+
let designFileIdByTemplateFileId = new Map<string, string>();
|
|
49
|
+
let instantiatedAt: string | null = null;
|
|
50
|
+
|
|
51
|
+
if (designId) {
|
|
52
|
+
const designAccess = await resolveAccess("design", designId);
|
|
53
|
+
if (!designAccess) throw new Error("Design not found");
|
|
54
|
+
const design =
|
|
55
|
+
designAccess.resource as typeof schema.designs.$inferSelect;
|
|
56
|
+
const source = readDesignTemplateSource(
|
|
57
|
+
parseDesignTemplateData(design.data),
|
|
58
|
+
);
|
|
59
|
+
if (!source) {
|
|
60
|
+
return {
|
|
61
|
+
designId,
|
|
62
|
+
fromTemplate: false as const,
|
|
63
|
+
message:
|
|
64
|
+
"This design was not created from a template; there is no original template to compare against.",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (templateId && templateId !== source.templateId) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Design ${designId} was created from template "${source.templateId}", not "${templateId}"`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
resolvedTemplateId = source.templateId;
|
|
73
|
+
instantiatedAt = source.instantiatedAt;
|
|
74
|
+
designFileIdByTemplateFileId = new Map(
|
|
75
|
+
source.files.map(
|
|
76
|
+
(file) => [file.templateFileId, file.designFileId] as const,
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!resolvedTemplateId) throw new Error("Pass designId or templateId");
|
|
82
|
+
|
|
83
|
+
const preset = getDesignTemplatePreset(resolvedTemplateId);
|
|
84
|
+
let title: string;
|
|
85
|
+
let category: string;
|
|
86
|
+
let description: string | null;
|
|
87
|
+
let templateDesignSystemId: string | null;
|
|
88
|
+
let files: OriginalTemplateFile[];
|
|
89
|
+
|
|
90
|
+
if (preset) {
|
|
91
|
+
title = preset.title;
|
|
92
|
+
category = preset.category;
|
|
93
|
+
description = preset.description;
|
|
94
|
+
templateDesignSystemId = null;
|
|
95
|
+
files = [
|
|
96
|
+
{
|
|
97
|
+
templateFileId: `file:${preset.id}`,
|
|
98
|
+
filename: preset.filename,
|
|
99
|
+
fileType: "html",
|
|
100
|
+
content: preset.content,
|
|
101
|
+
width: preset.width,
|
|
102
|
+
height: preset.height,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
} else {
|
|
106
|
+
const access = await resolveAccess("design-template", resolvedTemplateId);
|
|
107
|
+
if (!access) throw new Error("Template not found");
|
|
108
|
+
const template = access.resource;
|
|
109
|
+
title = String(template.title ?? "Untitled template");
|
|
110
|
+
category = String(template.category ?? "other");
|
|
111
|
+
description =
|
|
112
|
+
typeof template.description === "string" ? template.description : null;
|
|
113
|
+
const rawDesignSystemId =
|
|
114
|
+
typeof template.designSystemId === "string"
|
|
115
|
+
? template.designSystemId
|
|
116
|
+
: null;
|
|
117
|
+
templateDesignSystemId = rawDesignSystemId
|
|
118
|
+
? (await resolveAccess("design-system", rawDesignSystemId))
|
|
119
|
+
? rawDesignSystemId
|
|
120
|
+
: null
|
|
121
|
+
: null;
|
|
122
|
+
|
|
123
|
+
const templateData = parseDesignTemplateData(
|
|
124
|
+
typeof template.data === "string" ? template.data : "{}",
|
|
125
|
+
);
|
|
126
|
+
const fallbackWidth =
|
|
127
|
+
typeof template.width === "number" ? template.width : null;
|
|
128
|
+
const fallbackHeight =
|
|
129
|
+
typeof template.height === "number" ? template.height : null;
|
|
130
|
+
|
|
131
|
+
const rows = await getDb()
|
|
132
|
+
.select({
|
|
133
|
+
id: schema.designTemplateFiles.id,
|
|
134
|
+
filename: schema.designTemplateFiles.filename,
|
|
135
|
+
fileType: schema.designTemplateFiles.fileType,
|
|
136
|
+
content: schema.designTemplateFiles.content,
|
|
137
|
+
})
|
|
138
|
+
.from(schema.designTemplateFiles)
|
|
139
|
+
.where(eq(schema.designTemplateFiles.templateId, resolvedTemplateId));
|
|
140
|
+
|
|
141
|
+
files = rows.map((row) => {
|
|
142
|
+
const frame = templateFileDimensions(templateData, row.id);
|
|
143
|
+
return {
|
|
144
|
+
templateFileId: row.id,
|
|
145
|
+
filename: row.filename,
|
|
146
|
+
fileType: row.fileType,
|
|
147
|
+
content: row.content,
|
|
148
|
+
width: frame.width ?? fallbackWidth,
|
|
149
|
+
height: frame.height ?? fallbackHeight,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
templateId: resolvedTemplateId,
|
|
156
|
+
title,
|
|
157
|
+
description,
|
|
158
|
+
category,
|
|
159
|
+
designSystemId: templateDesignSystemId,
|
|
160
|
+
isBuiltIn: Boolean(preset),
|
|
161
|
+
...(designId
|
|
162
|
+
? { designId, fromTemplate: true as const, instantiatedAt }
|
|
163
|
+
: {}),
|
|
164
|
+
files: files.map((file) => ({
|
|
165
|
+
...file,
|
|
166
|
+
designFileId:
|
|
167
|
+
designFileIdByTemplateFileId.get(file.templateFileId) ?? null,
|
|
168
|
+
lockedLayers: lockedLayerSnapshots(file.content).map((layer) => ({
|
|
169
|
+
nodeId: layer.id,
|
|
170
|
+
layerName: layer.label,
|
|
171
|
+
})),
|
|
172
|
+
})),
|
|
173
|
+
fileCount: files.length,
|
|
174
|
+
nextRequiredAction:
|
|
175
|
+
"Treat these dimensions, fonts, and locked layers as authoritative. Apply the user's request with edit-design on the design's own files; do not resize the artboard or call generate-design.",
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
});
|
|
@@ -13,7 +13,7 @@ const PREVIEW_MAX_BYTES = 50_000;
|
|
|
13
13
|
export default defineAction({
|
|
14
14
|
description:
|
|
15
15
|
"List all design projects accessible to the current user. " +
|
|
16
|
-
"Returns title, id, project type, and timestamps.",
|
|
16
|
+
"Returns title, id, project type, owner email, and timestamps.",
|
|
17
17
|
schema: z.object({
|
|
18
18
|
compact: z
|
|
19
19
|
.enum(["true", "false"])
|
|
@@ -43,6 +43,7 @@ export default defineAction({
|
|
|
43
43
|
projectType: schema.designs.projectType,
|
|
44
44
|
designSystemId: schema.designs.designSystemId,
|
|
45
45
|
visibility: schema.designs.visibility,
|
|
46
|
+
ownerEmail: schema.designs.ownerEmail,
|
|
46
47
|
createdAt: schema.designs.createdAt,
|
|
47
48
|
updatedAt: schema.designs.updatedAt,
|
|
48
49
|
})
|
|
@@ -106,6 +107,7 @@ export default defineAction({
|
|
|
106
107
|
projectType: row.projectType,
|
|
107
108
|
designSystemId: row.designSystemId,
|
|
108
109
|
visibility: row.visibility,
|
|
110
|
+
ownerEmail: row.ownerEmail,
|
|
109
111
|
createdAt: row.createdAt,
|
|
110
112
|
updatedAt: row.updatedAt,
|
|
111
113
|
};
|
|
@@ -28,6 +28,7 @@ import { eq } from "drizzle-orm";
|
|
|
28
28
|
import { z } from "zod";
|
|
29
29
|
|
|
30
30
|
import { getDb, schema } from "../server/db/index.js";
|
|
31
|
+
import { readDesignTemplateSource } from "../server/lib/design-template-data.js";
|
|
31
32
|
import { parseCanvasFrameGeometryById } from "../shared/canvas-frames.js";
|
|
32
33
|
import { getDesignTemplatePreset } from "../shared/design-template-presets.js";
|
|
33
34
|
import { designGenerationSessionKey } from "../shared/generation-session.js";
|
|
@@ -332,6 +333,36 @@ export default defineAction({
|
|
|
332
333
|
activeCodeFile: resolveActiveCodeFile(files, designSelection),
|
|
333
334
|
canvasFrames: parseCanvasFrameGeometryById(data.canvasFrames),
|
|
334
335
|
};
|
|
336
|
+
try {
|
|
337
|
+
const templateSource = readDesignTemplateSource(data);
|
|
338
|
+
if (templateSource) {
|
|
339
|
+
(screen.design as Record<string, unknown>).createdFromTemplate = {
|
|
340
|
+
templateId: templateSource.templateId,
|
|
341
|
+
title: templateSource.title,
|
|
342
|
+
category: templateSource.category,
|
|
343
|
+
instantiatedAt: templateSource.instantiatedAt,
|
|
344
|
+
designSystemId: templateSource.appliedDesignSystemId,
|
|
345
|
+
lockedDimensions: templateSource.files.map((file) => ({
|
|
346
|
+
designFileId: file.designFileId,
|
|
347
|
+
filename: file.filename,
|
|
348
|
+
width: file.width,
|
|
349
|
+
height: file.height,
|
|
350
|
+
})),
|
|
351
|
+
lockedFonts: templateSource.fonts,
|
|
352
|
+
note:
|
|
353
|
+
"The screens below are edited copies of this template, so their current content no longer shows what the template specified. " +
|
|
354
|
+
"The dimensions and fonts above come from the template and stay authoritative for every request, including this one: keep each screen at exactly those dimensions and keep those font families. " +
|
|
355
|
+
"Do not resize the artboard, change canvasFrames width or height, switch the primary viewport, or substitute a typeface to fit new content. " +
|
|
356
|
+
`Refine with edit-design; do not call generate-design. Call \`get-design-template --designId="${designId}"\` when you need the template's original markup or locked layers.`,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
} catch (error) {
|
|
360
|
+
(screen.design as Record<string, unknown>).createdFromTemplate = {
|
|
361
|
+
unreadable:
|
|
362
|
+
error instanceof Error ? error.message : "unknown parse failure",
|
|
363
|
+
note: "This design claims a template that could not be read. Ask the user which template it came from instead of editing dimensions or typography.",
|
|
364
|
+
};
|
|
365
|
+
}
|
|
335
366
|
const proposalPrefix = `${DESIGN_REPROMPT_PROPOSAL_STATE_PREFIX}${designId}:`;
|
|
336
367
|
const pendingPrefix = `${DESIGN_REPROMPT_PENDING_STATE_PREFIX}${designId}:`;
|
|
337
368
|
const [proposalEntries, pendingEntries] = await Promise.all([
|