@agent-native/core 0.145.8 → 0.146.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/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +20 -4
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +59 -24
- package/corpus/templates/analytics/changelog/2026-08-07-analytics-migrations-now-use-bounded-pressure-aware-backgrou.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-07-template-activity-charts-now-show-only-core-agent-native-app.md +6 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +110 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +13 -13
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +448 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +2 -2
- package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +4 -5
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +35 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +3 -5
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +10 -4
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +4 -11
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +74 -28
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +2 -5
- package/corpus/templates/analytics/server/plugins/db.ts +42 -0
- package/corpus/templates/analytics/server/routes/api/analytics-bigquery/backfill.post.ts +55 -0
- package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +22 -4
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/brain/server/lib/connectors.ts +38 -14
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +13 -0
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +5 -0
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +5 -0
- package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +5 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
- package/corpus/templates/slides/app/pages/Presentation.tsx +3 -0
- package/corpus/templates/slides/app/pages/SharedPresentation.tsx +5 -0
- package/corpus/templates/slides/app/routes/slide.tsx +10 -5
- package/corpus/templates/slides/changelog/2026-08-07-slide-previews-and-present-now-keep-deck-colors-consistent.md +6 -0
- package/corpus/templates/slides/server/db/schema.ts +1 -0
- package/corpus/templates/slides/server/handlers/share.ts +51 -3
- package/corpus/templates/slides/server/plugins/db.ts +5 -0
- package/corpus/templates/slides/shared/api.ts +2 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/dist/cli/code-agent-executor.js +8 -3
- package/dist/client/ConnectBuilderCard.d.ts +7 -7
- package/dist/client/ConnectBuilderCard.js +45 -20
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +9 -2
- package/dist/config.js +38 -2
- package/dist/db/client.d.ts +13 -1
- package/dist/db/client.js +76 -2
- package/dist/db/create-get-db.js +2 -2
- package/dist/deploy/build.js +5 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/docs/search.js +3 -2
- package/dist/server/agent-chat/prompt-resources.js +4 -3
- package/dist/server/agents-bundle.d.ts +20 -3
- package/dist/server/agents-bundle.js +57 -30
- package/dist/server/better-auth-instance.js +2 -2
- package/dist/shared/runtime-config.js +1 -1
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/dist/vite/agent-native-config-loader.d.ts +10 -0
- package/dist/vite/agent-native-config-loader.js +56 -0
- package/dist/vite/agents-bundle-plugin.d.ts +5 -1
- package/dist/vite/agents-bundle-plugin.js +29 -6
- package/dist/vite/client.d.ts +4 -2
- package/dist/vite/client.js +4 -49
- package/dist/vite/index.d.ts +2 -2
- package/dist/vite/index.js +1 -1
- package/docs/content/agent-native-config.mdx +43 -17
- package/docs/content/environment-variables.mdx +1 -1
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +37 -11
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +13 -2
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Turn visible project context, a proven thread, skill, or workflow into a
|
|
5
5
|
runnable Agent-Native app with simple buttons, visible agent steps, preview,
|
|
6
6
|
and deployment handoff. Use when a user invokes `/turn-into-app` or asks to
|
|
7
|
-
make a workflow into an app.
|
|
7
|
+
make a workflow into an app, including from Claude or ChatGPT on the web.
|
|
8
8
|
user-invocable: true
|
|
9
9
|
scope: both
|
|
10
10
|
metadata:
|
|
@@ -13,9 +13,32 @@ metadata:
|
|
|
13
13
|
|
|
14
14
|
# Turn Into App
|
|
15
15
|
|
|
16
|
+
## Host execution boundary
|
|
17
|
+
|
|
18
|
+
The build location depends on the host. Treat this as a hard routing rule:
|
|
19
|
+
|
|
20
|
+
- In Claude Web, ChatGPT Web, or a Claude/ChatGPT Project on the web, you are
|
|
21
|
+
the source analyst and handoff orchestrator. You must not build the app in
|
|
22
|
+
the host sandbox. Do not run `npm`, `pnpm`, `npx`, `agent-native create`, or
|
|
23
|
+
`add-app`; do not edit files, create artifacts, or start a local dev server.
|
|
24
|
+
After writing the bounded source brief, call the connected Dispatch action
|
|
25
|
+
`start-workspace-app-creation`. Pass the brief and repeatable workflow in
|
|
26
|
+
`prompt`, plus the inferred `appId`, `description`, `template`, and selected
|
|
27
|
+
`resourceIds` when available. This is the Builder handoff.
|
|
28
|
+
- Do not substitute the generic `create_workspace_app` MCP tool in an online
|
|
29
|
+
host. That tool is a local workspace scaffolder, not the Builder handoff.
|
|
30
|
+
- If `start-workspace-app-creation` is not available or Dispatch is not
|
|
31
|
+
authenticated, stop with the connector setup needed. Do not fall back to a
|
|
32
|
+
local build or claim that the app exists.
|
|
33
|
+
- In Claude Code, Codex Code, or another local code-agent runtime with a target
|
|
34
|
+
workspace, follow the local implementation steps below. The local agent may
|
|
35
|
+
scaffold, edit, run, and verify the app there.
|
|
36
|
+
|
|
16
37
|
## Default behavior
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
For a local code-agent runtime this is an end-to-end build skill, not a request
|
|
40
|
+
for an app proposal. For an online host, the end-to-end result is a verified
|
|
41
|
+
Builder handoff and the resulting workspace app, not code written in the host.
|
|
19
42
|
|
|
20
43
|
- With no argument, choose the source in this order: visible project context,
|
|
21
44
|
then the current thread. A fresh Claude or ChatGPT Project is a valid source
|
|
@@ -47,9 +70,12 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
|
|
|
47
70
|
page. If the needed context is not visible, ask for an export, transcript, or
|
|
48
71
|
attachment and treat that artifact as imported source material.
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
buttons and agent handoffs, start its dev
|
|
52
|
-
continue through build/deployment handoff. Do
|
|
73
|
+
For local code-agent runtimes, deliver a fresh app in a new directory,
|
|
74
|
+
implement the repeatable workflow with buttons and agent handoffs, start its dev
|
|
75
|
+
server, verify the main path, and continue through build/deployment handoff. Do
|
|
76
|
+
not stop at a plan. For online hosts, call Dispatch first after the source brief,
|
|
77
|
+
then report the returned Builder branch/path and verify the workspace app through
|
|
78
|
+
Dispatch when it becomes available.
|
|
53
79
|
|
|
54
80
|
## Fresh project context mode
|
|
55
81
|
|
|
@@ -190,12 +216,12 @@ Do not use `create` for an existing workspace; it scaffolds a new standalone
|
|
|
190
216
|
workspace rather than adding an app to the current one.
|
|
191
217
|
|
|
192
218
|
When the source came from a fresh external Project and the target is a Builder
|
|
193
|
-
workspace,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
219
|
+
workspace, the online host path is mandatory: after writing the source brief,
|
|
220
|
+
call `start-workspace-app-creation` with a concise prompt, the inferred app id,
|
|
221
|
+
and the brief's repeatable workflow. Pass selected workspace resource IDs when
|
|
222
|
+
they are available, rather than pasting entire knowledge files. Continue from
|
|
223
|
+
the returned workspace path or Builder branch handoff and report the actual
|
|
224
|
+
verification result. Do not run the local scaffold commands in this host mode.
|
|
199
225
|
|
|
200
226
|
Use a first-party template only when it materially fits the workflow. Keep the
|
|
201
227
|
new app independent from the source thread's working tree unless the user
|
|
@@ -51,13 +51,24 @@ also place the skill instructions or this reference in the Project
|
|
|
51
51
|
instructions/knowledge files. Then add and authenticate the Dispatch MCP
|
|
52
52
|
connector from the packaged `adapters/chatgpt-mcp/connector.json`.
|
|
53
53
|
|
|
54
|
+
For Claude Web, ChatGPT Web, and their web Projects, the host is an
|
|
55
|
+
orchestrator, not the build environment. After forming the source brief, call
|
|
56
|
+
the Dispatch `start-workspace-app-creation` action so Builder creates the app
|
|
57
|
+
in the connected workspace. Do not use the host's code interpreter, shell,
|
|
58
|
+
artifact editor, `create_workspace_app`, or local `pnpm`/`npm` commands. If the
|
|
59
|
+
handoff action is unavailable, stop and ask the user to authenticate Dispatch;
|
|
60
|
+
do not fall back to a local sandbox build. Claude Code and Codex Code are the
|
|
61
|
+
local-agent exception and may follow the implementation steps in the main
|
|
62
|
+
skill.
|
|
63
|
+
|
|
54
64
|
In a new Project chat, say:
|
|
55
65
|
|
|
56
66
|
```text
|
|
57
67
|
Turn this project into an app. Use the visible Project instructions,
|
|
58
68
|
knowledge files, and any selected successful runs as the source. Create the
|
|
59
|
-
app in the connected Agent-Native workspace
|
|
60
|
-
and report the real path and
|
|
69
|
+
app in the connected Agent-Native workspace through Dispatch and Builder, keep
|
|
70
|
+
the source brief bounded, and report the real Builder branch/path and
|
|
71
|
+
verification result. Do not build it in this chat's sandbox.
|
|
61
72
|
```
|
|
62
73
|
|
|
63
74
|
If the host does not show the Project instructions or files to the model, stop
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Turn visible project context, a proven thread, skill, or workflow into a
|
|
5
5
|
runnable Agent-Native app with simple buttons, visible agent steps, preview,
|
|
6
6
|
and deployment handoff. Use when a user invokes `/turn-into-app` or asks to
|
|
7
|
-
make a workflow into an app.
|
|
7
|
+
make a workflow into an app, including from Claude or ChatGPT on the web.
|
|
8
8
|
user-invocable: true
|
|
9
9
|
scope: both
|
|
10
10
|
metadata:
|
|
@@ -13,9 +13,32 @@ metadata:
|
|
|
13
13
|
|
|
14
14
|
# Turn Into App
|
|
15
15
|
|
|
16
|
+
## Host execution boundary
|
|
17
|
+
|
|
18
|
+
The build location depends on the host. Treat this as a hard routing rule:
|
|
19
|
+
|
|
20
|
+
- In Claude Web, ChatGPT Web, or a Claude/ChatGPT Project on the web, you are
|
|
21
|
+
the source analyst and handoff orchestrator. You must not build the app in
|
|
22
|
+
the host sandbox. Do not run `npm`, `pnpm`, `npx`, `agent-native create`, or
|
|
23
|
+
`add-app`; do not edit files, create artifacts, or start a local dev server.
|
|
24
|
+
After writing the bounded source brief, call the connected Dispatch action
|
|
25
|
+
`start-workspace-app-creation`. Pass the brief and repeatable workflow in
|
|
26
|
+
`prompt`, plus the inferred `appId`, `description`, `template`, and selected
|
|
27
|
+
`resourceIds` when available. This is the Builder handoff.
|
|
28
|
+
- Do not substitute the generic `create_workspace_app` MCP tool in an online
|
|
29
|
+
host. That tool is a local workspace scaffolder, not the Builder handoff.
|
|
30
|
+
- If `start-workspace-app-creation` is not available or Dispatch is not
|
|
31
|
+
authenticated, stop with the connector setup needed. Do not fall back to a
|
|
32
|
+
local build or claim that the app exists.
|
|
33
|
+
- In Claude Code, Codex Code, or another local code-agent runtime with a target
|
|
34
|
+
workspace, follow the local implementation steps below. The local agent may
|
|
35
|
+
scaffold, edit, run, and verify the app there.
|
|
36
|
+
|
|
16
37
|
## Default behavior
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
For a local code-agent runtime this is an end-to-end build skill, not a request
|
|
40
|
+
for an app proposal. For an online host, the end-to-end result is a verified
|
|
41
|
+
Builder handoff and the resulting workspace app, not code written in the host.
|
|
19
42
|
|
|
20
43
|
- With no argument, choose the source in this order: visible project context,
|
|
21
44
|
then the current thread. A fresh Claude or ChatGPT Project is a valid source
|
|
@@ -47,9 +70,12 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
|
|
|
47
70
|
page. If the needed context is not visible, ask for an export, transcript, or
|
|
48
71
|
attachment and treat that artifact as imported source material.
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
buttons and agent handoffs, start its dev
|
|
52
|
-
continue through build/deployment handoff. Do
|
|
73
|
+
For local code-agent runtimes, deliver a fresh app in a new directory,
|
|
74
|
+
implement the repeatable workflow with buttons and agent handoffs, start its dev
|
|
75
|
+
server, verify the main path, and continue through build/deployment handoff. Do
|
|
76
|
+
not stop at a plan. For online hosts, call Dispatch first after the source brief,
|
|
77
|
+
then report the returned Builder branch/path and verify the workspace app through
|
|
78
|
+
Dispatch when it becomes available.
|
|
53
79
|
|
|
54
80
|
## Fresh project context mode
|
|
55
81
|
|
|
@@ -190,12 +216,12 @@ Do not use `create` for an existing workspace; it scaffolds a new standalone
|
|
|
190
216
|
workspace rather than adding an app to the current one.
|
|
191
217
|
|
|
192
218
|
When the source came from a fresh external Project and the target is a Builder
|
|
193
|
-
workspace,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
219
|
+
workspace, the online host path is mandatory: after writing the source brief,
|
|
220
|
+
call `start-workspace-app-creation` with a concise prompt, the inferred app id,
|
|
221
|
+
and the brief's repeatable workflow. Pass selected workspace resource IDs when
|
|
222
|
+
they are available, rather than pasting entire knowledge files. Continue from
|
|
223
|
+
the returned workspace path or Builder branch handoff and report the actual
|
|
224
|
+
verification result. Do not run the local scaffold commands in this host mode.
|
|
199
225
|
|
|
200
226
|
Use a first-party template only when it materially fits the workflow. Keep the
|
|
201
227
|
new app independent from the source thread's working tree unless the user
|
|
@@ -51,13 +51,24 @@ also place the skill instructions or this reference in the Project
|
|
|
51
51
|
instructions/knowledge files. Then add and authenticate the Dispatch MCP
|
|
52
52
|
connector from the packaged `adapters/chatgpt-mcp/connector.json`.
|
|
53
53
|
|
|
54
|
+
For Claude Web, ChatGPT Web, and their web Projects, the host is an
|
|
55
|
+
orchestrator, not the build environment. After forming the source brief, call
|
|
56
|
+
the Dispatch `start-workspace-app-creation` action so Builder creates the app
|
|
57
|
+
in the connected workspace. Do not use the host's code interpreter, shell,
|
|
58
|
+
artifact editor, `create_workspace_app`, or local `pnpm`/`npm` commands. If the
|
|
59
|
+
handoff action is unavailable, stop and ask the user to authenticate Dispatch;
|
|
60
|
+
do not fall back to a local sandbox build. Claude Code and Codex Code are the
|
|
61
|
+
local-agent exception and may follow the implementation steps in the main
|
|
62
|
+
skill.
|
|
63
|
+
|
|
54
64
|
In a new Project chat, say:
|
|
55
65
|
|
|
56
66
|
```text
|
|
57
67
|
Turn this project into an app. Use the visible Project instructions,
|
|
58
68
|
knowledge files, and any selected successful runs as the source. Create the
|
|
59
|
-
app in the connected Agent-Native workspace
|
|
60
|
-
and report the real path and
|
|
69
|
+
app in the connected Agent-Native workspace through Dispatch and Builder, keep
|
|
70
|
+
the source brief bounded, and report the real Builder branch/path and
|
|
71
|
+
verification result. Do not build it in this chat's sandbox.
|
|
61
72
|
```
|
|
62
73
|
|
|
63
74
|
If the host does not show the Project instructions or files to the model, stop
|
|
@@ -38,6 +38,8 @@ import type { Slide } from "@/context/DeckContext";
|
|
|
38
38
|
import type { AspectRatio } from "@/lib/aspect-ratios";
|
|
39
39
|
import { TAB_ID } from "@/lib/tab-id";
|
|
40
40
|
|
|
41
|
+
import type { DesignSystemData } from "../../../shared/api";
|
|
42
|
+
|
|
41
43
|
interface EditorSidebarProps {
|
|
42
44
|
slides: Slide[];
|
|
43
45
|
activeSlideId: string;
|
|
@@ -53,6 +55,8 @@ interface EditorSidebarProps {
|
|
|
53
55
|
recentEdits?: AttributedRecentEdit[];
|
|
54
56
|
/** Deck aspect ratio (defaults to 16:9 when omitted) */
|
|
55
57
|
aspectRatio?: AspectRatio;
|
|
58
|
+
/** Active deck design system used by slide content tokens. */
|
|
59
|
+
designSystem?: DesignSystemData;
|
|
56
60
|
/** The next slide while the agent is preparing its HTML. */
|
|
57
61
|
generatingSlide?: { index: number; content?: string | null };
|
|
58
62
|
generatingSlideSelected?: boolean;
|
|
@@ -154,6 +158,7 @@ function SortableSlideThumb({
|
|
|
154
158
|
registerButtonRef,
|
|
155
159
|
presenceUsers = [],
|
|
156
160
|
aspectRatio,
|
|
161
|
+
designSystem,
|
|
157
162
|
onOverflowChange,
|
|
158
163
|
readOnly = false,
|
|
159
164
|
}: {
|
|
@@ -167,6 +172,7 @@ function SortableSlideThumb({
|
|
|
167
172
|
registerButtonRef: (slideId: string, node: HTMLButtonElement | null) => void;
|
|
168
173
|
presenceUsers?: CollabUser[];
|
|
169
174
|
aspectRatio?: AspectRatio;
|
|
175
|
+
designSystem?: DesignSystemData;
|
|
170
176
|
onOverflowChange: (info: SlideOverflowInfo) => void;
|
|
171
177
|
}) {
|
|
172
178
|
const t = useT();
|
|
@@ -234,6 +240,7 @@ function SortableSlideThumb({
|
|
|
234
240
|
<SlideRenderer
|
|
235
241
|
slide={slide}
|
|
236
242
|
aspectRatio={aspectRatio}
|
|
243
|
+
designSystem={designSystem}
|
|
237
244
|
onOverflowChange={onOverflowChange}
|
|
238
245
|
/>
|
|
239
246
|
</div>
|
|
@@ -290,12 +297,14 @@ function SortableSlideThumb({
|
|
|
290
297
|
function GeneratingSlideSkeleton({
|
|
291
298
|
index,
|
|
292
299
|
aspectRatio,
|
|
300
|
+
designSystem,
|
|
293
301
|
content,
|
|
294
302
|
selected,
|
|
295
303
|
onSelect,
|
|
296
304
|
}: {
|
|
297
305
|
index: number;
|
|
298
306
|
aspectRatio?: AspectRatio;
|
|
307
|
+
designSystem?: DesignSystemData;
|
|
299
308
|
content?: string | null;
|
|
300
309
|
selected?: boolean;
|
|
301
310
|
onSelect?: () => void;
|
|
@@ -319,6 +328,7 @@ function GeneratingSlideSkeleton({
|
|
|
319
328
|
<GeneratingSlidePreview
|
|
320
329
|
content={content}
|
|
321
330
|
aspectRatio={aspectRatio}
|
|
331
|
+
designSystem={designSystem}
|
|
322
332
|
thumbnail
|
|
323
333
|
/>
|
|
324
334
|
</div>
|
|
@@ -338,6 +348,7 @@ export default function EditorSidebar({
|
|
|
338
348
|
slidePresence,
|
|
339
349
|
recentEdits,
|
|
340
350
|
aspectRatio,
|
|
351
|
+
designSystem,
|
|
341
352
|
generatingSlide,
|
|
342
353
|
generatingSlideSelected = false,
|
|
343
354
|
onSelectGeneratingSlide,
|
|
@@ -508,6 +519,7 @@ export default function EditorSidebar({
|
|
|
508
519
|
registerButtonRef={registerSlideButton}
|
|
509
520
|
presenceUsers={slidePresence?.get(slide.id) ?? []}
|
|
510
521
|
aspectRatio={aspectRatio}
|
|
522
|
+
designSystem={designSystem}
|
|
511
523
|
onOverflowChange={(info) =>
|
|
512
524
|
handleSlideOverflowChange(slide, info)
|
|
513
525
|
}
|
|
@@ -518,6 +530,7 @@ export default function EditorSidebar({
|
|
|
518
530
|
<GeneratingSlideSkeleton
|
|
519
531
|
index={generatingSlide.index}
|
|
520
532
|
aspectRatio={aspectRatio}
|
|
533
|
+
designSystem={designSystem}
|
|
521
534
|
content={generatingSlide.content}
|
|
522
535
|
selected={generatingSlideSelected}
|
|
523
536
|
onSelect={onSelectGeneratingSlide}
|
|
@@ -7,6 +7,8 @@ import type { Slide } from "@/context/DeckContext";
|
|
|
7
7
|
import type { AspectRatio } from "@/lib/aspect-ratios";
|
|
8
8
|
import { cn } from "@/lib/utils";
|
|
9
9
|
|
|
10
|
+
import type { DesignSystemData } from "../../../shared/api";
|
|
11
|
+
|
|
10
12
|
function SlideLoadingArtwork() {
|
|
11
13
|
return (
|
|
12
14
|
<div className="absolute inset-0 flex flex-col justify-center gap-4 bg-muted/30 p-[14%]">
|
|
@@ -25,11 +27,13 @@ export default function GeneratingSlidePreview({
|
|
|
25
27
|
aspectRatio,
|
|
26
28
|
thumbnail = true,
|
|
27
29
|
className,
|
|
30
|
+
designSystem,
|
|
28
31
|
}: {
|
|
29
32
|
content?: string | null;
|
|
30
33
|
aspectRatio?: AspectRatio;
|
|
31
34
|
thumbnail?: boolean;
|
|
32
35
|
className?: string;
|
|
36
|
+
designSystem?: DesignSystemData;
|
|
33
37
|
}) {
|
|
34
38
|
const t = useT();
|
|
35
39
|
const cssRatio = (aspectRatio ?? "16:9").replace(":", " / ");
|
|
@@ -55,6 +59,7 @@ export default function GeneratingSlidePreview({
|
|
|
55
59
|
slide={previewSlide}
|
|
56
60
|
aspectRatio={aspectRatio}
|
|
57
61
|
thumbnail={thumbnail}
|
|
62
|
+
designSystem={designSystem}
|
|
58
63
|
className="h-full w-full"
|
|
59
64
|
/>
|
|
60
65
|
) : (
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
resolveSlideAnimationElement,
|
|
23
23
|
} from "@/lib/slide-animation-elements";
|
|
24
24
|
|
|
25
|
+
import type { DesignSystemData } from "../../../shared/api";
|
|
25
26
|
import { openPresentChannel, type PresentMessage } from "./present-channel";
|
|
26
27
|
|
|
27
28
|
interface PresentationViewProps {
|
|
@@ -29,6 +30,7 @@ interface PresentationViewProps {
|
|
|
29
30
|
deckId: string;
|
|
30
31
|
startIndex?: number;
|
|
31
32
|
aspectRatio?: AspectRatio;
|
|
33
|
+
designSystem?: DesignSystemData;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
// ─── Element animation helpers ────────────────────────────────────────────────
|
|
@@ -182,6 +184,7 @@ export default function PresentationView({
|
|
|
182
184
|
deckId,
|
|
183
185
|
startIndex = 0,
|
|
184
186
|
aspectRatio,
|
|
187
|
+
designSystem,
|
|
185
188
|
}: PresentationViewProps) {
|
|
186
189
|
const t = useT();
|
|
187
190
|
const safeSlides = useMemo(
|
|
@@ -534,6 +537,7 @@ export default function PresentationView({
|
|
|
534
537
|
slide={safeSlides[prevIndex]}
|
|
535
538
|
thumbnail={false}
|
|
536
539
|
aspectRatio={aspectRatio}
|
|
540
|
+
designSystem={designSystem}
|
|
537
541
|
/>
|
|
538
542
|
</div>
|
|
539
543
|
)}
|
|
@@ -548,6 +552,7 @@ export default function PresentationView({
|
|
|
548
552
|
slide={displaySlide}
|
|
549
553
|
thumbnail={false}
|
|
550
554
|
aspectRatio={aspectRatio}
|
|
555
|
+
designSystem={designSystem}
|
|
551
556
|
/>
|
|
552
557
|
</div>
|
|
553
558
|
|
|
@@ -6,6 +6,7 @@ import SlideRenderer from "@/components/deck/SlideRenderer";
|
|
|
6
6
|
import type { Slide } from "@/context/DeckContext";
|
|
7
7
|
import type { AspectRatio } from "@/lib/aspect-ratios";
|
|
8
8
|
|
|
9
|
+
import type { DesignSystemData } from "../../../shared/api";
|
|
9
10
|
import { openPresentChannel, type PresentMessage } from "./present-channel";
|
|
10
11
|
|
|
11
12
|
interface PresenterViewProps {
|
|
@@ -13,6 +14,7 @@ interface PresenterViewProps {
|
|
|
13
14
|
deckId: string;
|
|
14
15
|
startIndex?: number;
|
|
15
16
|
aspectRatio?: AspectRatio;
|
|
17
|
+
designSystem?: DesignSystemData;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
function formatElapsed(seconds: number) {
|
|
@@ -26,6 +28,7 @@ export default function PresenterView({
|
|
|
26
28
|
deckId,
|
|
27
29
|
startIndex = 0,
|
|
28
30
|
aspectRatio,
|
|
31
|
+
designSystem,
|
|
29
32
|
}: PresenterViewProps) {
|
|
30
33
|
const t = useT();
|
|
31
34
|
const [index, setIndex] = useState(startIndex);
|
|
@@ -136,6 +139,7 @@ export default function PresenterView({
|
|
|
136
139
|
slide={current}
|
|
137
140
|
thumbnail
|
|
138
141
|
aspectRatio={aspectRatio}
|
|
142
|
+
designSystem={designSystem}
|
|
139
143
|
/>
|
|
140
144
|
)}
|
|
141
145
|
</div>
|
|
@@ -149,6 +153,7 @@ export default function PresenterView({
|
|
|
149
153
|
slide={next}
|
|
150
154
|
thumbnail
|
|
151
155
|
aspectRatio={aspectRatio}
|
|
156
|
+
designSystem={designSystem}
|
|
152
157
|
/>
|
|
153
158
|
</div>
|
|
154
159
|
) : (
|
|
@@ -1128,6 +1128,7 @@ export default function DeckEditor() {
|
|
|
1128
1128
|
slidePresence={slidePresence}
|
|
1129
1129
|
recentEdits={deckRecentEdits}
|
|
1130
1130
|
aspectRatio={deck.aspectRatio}
|
|
1131
|
+
designSystem={designSystem}
|
|
1131
1132
|
generatingSlide={
|
|
1132
1133
|
generatingSlideVisible
|
|
1133
1134
|
? {
|
|
@@ -1166,6 +1167,7 @@ export default function DeckEditor() {
|
|
|
1166
1167
|
<GeneratingSlidePreview
|
|
1167
1168
|
content={streamedGeneratingSlideContent}
|
|
1168
1169
|
aspectRatio={deck.aspectRatio}
|
|
1170
|
+
designSystem={designSystem}
|
|
1169
1171
|
thumbnail={false}
|
|
1170
1172
|
/>
|
|
1171
1173
|
</div>
|
|
@@ -1181,6 +1183,7 @@ export default function DeckEditor() {
|
|
|
1181
1183
|
<GeneratingSlidePreview
|
|
1182
1184
|
content={streamedGeneratingSlideContent}
|
|
1183
1185
|
aspectRatio={deck.aspectRatio}
|
|
1186
|
+
designSystem={designSystem}
|
|
1184
1187
|
thumbnail={false}
|
|
1185
1188
|
/>
|
|
1186
1189
|
</div>
|
|
@@ -7,6 +7,7 @@ import PresentationView from "@/components/presentation/PresentationView";
|
|
|
7
7
|
import PresenterView from "@/components/presentation/PresenterView";
|
|
8
8
|
import { useDecks } from "@/context/DeckContext";
|
|
9
9
|
import type { Deck } from "@/context/DeckContext";
|
|
10
|
+
import { useDeckDesignSystem } from "@/hooks/use-deck-design-system";
|
|
10
11
|
|
|
11
12
|
export default function Presentation() {
|
|
12
13
|
const { id } = useParams<{ id: string }>();
|
|
@@ -25,6 +26,7 @@ export default function Presentation() {
|
|
|
25
26
|
const [searchParams] = useSearchParams();
|
|
26
27
|
const contextDeck = getDeck(id || "");
|
|
27
28
|
const deck = contextDeck ?? fallbackDeck;
|
|
29
|
+
const { designSystem } = useDeckDesignSystem(deck?.designSystemId);
|
|
28
30
|
|
|
29
31
|
useEffect(() => {
|
|
30
32
|
if (!id || loading || contextDeck) {
|
|
@@ -104,6 +106,7 @@ export default function Presentation() {
|
|
|
104
106
|
deckId={id}
|
|
105
107
|
startIndex={startSlide}
|
|
106
108
|
aspectRatio={deck.aspectRatio}
|
|
109
|
+
designSystem={designSystem}
|
|
107
110
|
/>
|
|
108
111
|
);
|
|
109
112
|
}
|
|
@@ -7,6 +7,7 @@ import { useParams } from "react-router";
|
|
|
7
7
|
|
|
8
8
|
import PresentationView from "@/components/presentation/PresentationView";
|
|
9
9
|
import type { Slide } from "@/context/DeckContext";
|
|
10
|
+
import { mergeDesignSystemData } from "@/hooks/use-deck-design-system";
|
|
10
11
|
|
|
11
12
|
interface SharedPresentationProps {
|
|
12
13
|
initialDeck?: SharedDeckResponse | null;
|
|
@@ -81,6 +82,9 @@ export default function SharedPresentation({
|
|
|
81
82
|
...s,
|
|
82
83
|
layout: s.layout as Slide["layout"],
|
|
83
84
|
}));
|
|
85
|
+
const designSystem = deck.designSystem
|
|
86
|
+
? mergeDesignSystemData(deck.designSystem)
|
|
87
|
+
: undefined;
|
|
84
88
|
|
|
85
89
|
// Use a fake deckId that routes "exit" back to the share page itself
|
|
86
90
|
return (
|
|
@@ -88,6 +92,7 @@ export default function SharedPresentation({
|
|
|
88
92
|
slides={slides}
|
|
89
93
|
deckId={`__shared__/${token}`}
|
|
90
94
|
aspectRatio={deck.aspectRatio}
|
|
95
|
+
designSystem={designSystem}
|
|
91
96
|
/>
|
|
92
97
|
);
|
|
93
98
|
}
|
|
@@ -10,6 +10,7 @@ import { useSearchParams } from "react-router";
|
|
|
10
10
|
|
|
11
11
|
import SlideRenderer from "@/components/deck/SlideRenderer";
|
|
12
12
|
import type { Slide } from "@/context/DeckContext";
|
|
13
|
+
import { useDeckDesignSystem } from "@/hooks/use-deck-design-system";
|
|
13
14
|
import messages from "@/i18n/en-US";
|
|
14
15
|
import type { AspectRatio } from "@/lib/aspect-ratios";
|
|
15
16
|
|
|
@@ -42,8 +43,10 @@ export default function SlideRoute() {
|
|
|
42
43
|
const [aspectRatio, setAspectRatio] = useState<AspectRatio | undefined>(
|
|
43
44
|
undefined,
|
|
44
45
|
);
|
|
46
|
+
const [designSystemId, setDesignSystemId] = useState<string | null>(null);
|
|
45
47
|
const [error, setError] = useState<string | null>(null);
|
|
46
48
|
const [loading, setLoading] = useState(true);
|
|
49
|
+
const { designSystem } = useDeckDesignSystem(designSystemId);
|
|
47
50
|
|
|
48
51
|
const slideNumber =
|
|
49
52
|
slideNumberParam !== null ? parseInt(slideNumberParam, 10) : null;
|
|
@@ -75,11 +78,11 @@ export default function SlideRoute() {
|
|
|
75
78
|
return;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
callAction<{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
)
|
|
81
|
+
callAction<{
|
|
82
|
+
slides?: Slide[];
|
|
83
|
+
aspectRatio?: AspectRatio;
|
|
84
|
+
designSystemId?: string | null;
|
|
85
|
+
}>("get-deck", { id: deckId }, { method: "GET" })
|
|
83
86
|
.then((deck) => {
|
|
84
87
|
const slides: Slide[] = deck.slides ?? [];
|
|
85
88
|
if (slides.length === 0) {
|
|
@@ -88,6 +91,7 @@ export default function SlideRoute() {
|
|
|
88
91
|
const idx = Math.max(0, Math.min(slideIndex, slides.length - 1));
|
|
89
92
|
setSlide(slides[idx]);
|
|
90
93
|
setAspectRatio(deck.aspectRatio);
|
|
94
|
+
setDesignSystemId(deck.designSystemId ?? null);
|
|
91
95
|
setLoading(false);
|
|
92
96
|
})
|
|
93
97
|
.catch((err: unknown) => {
|
|
@@ -123,6 +127,7 @@ export default function SlideRoute() {
|
|
|
123
127
|
slide={slide}
|
|
124
128
|
thumbnail={false}
|
|
125
129
|
aspectRatio={aspectRatio}
|
|
130
|
+
designSystem={designSystem}
|
|
126
131
|
/>
|
|
127
132
|
|
|
128
133
|
{inEmbed && (
|
|
@@ -54,6 +54,7 @@ export const deckShareLinks = table("deck_share_links", {
|
|
|
54
54
|
title: text("title").notNull(),
|
|
55
55
|
slides: text("slides").notNull(), // JSON array of slide snapshots
|
|
56
56
|
aspectRatio: text("aspect_ratio"),
|
|
57
|
+
designSystemData: text("design_system_data"), // Share-safe token snapshot
|
|
57
58
|
createdAt: text("created_at").notNull().default(now()),
|
|
58
59
|
});
|
|
59
60
|
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
|
|
3
3
|
import { readBody } from "@agent-native/core/server";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
assertAccess,
|
|
6
|
+
ForbiddenError,
|
|
7
|
+
resolveAccess,
|
|
8
|
+
} from "@agent-native/core/sharing";
|
|
5
9
|
import { toSharedDeckSlide } from "@shared/api";
|
|
6
10
|
import type {
|
|
11
|
+
DesignSystemData,
|
|
7
12
|
ShareDeckRequest,
|
|
8
13
|
ShareDeckResponse,
|
|
9
14
|
SharedDeckResponse,
|
|
@@ -19,6 +24,12 @@ import {
|
|
|
19
24
|
|
|
20
25
|
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
|
21
26
|
|
|
27
|
+
interface DeckShareResource {
|
|
28
|
+
title?: string | null;
|
|
29
|
+
data: string;
|
|
30
|
+
designSystemId?: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
/**
|
|
23
34
|
* POST /api/share
|
|
24
35
|
* Persist a deck snapshot with a random token.
|
|
@@ -53,11 +64,13 @@ async function createShareLink(event: any, deckId: string) {
|
|
|
53
64
|
const db = getDb();
|
|
54
65
|
let storedDeck: any;
|
|
55
66
|
let title = "Untitled";
|
|
67
|
+
let deckResource: DeckShareResource;
|
|
56
68
|
|
|
57
69
|
try {
|
|
58
70
|
const access = await assertAccess("deck", deckId, "admin");
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
deckResource = access.resource as DeckShareResource;
|
|
72
|
+
title = deckResource.title ?? "Untitled";
|
|
73
|
+
storedDeck = JSON.parse(deckResource.data);
|
|
61
74
|
} catch (err) {
|
|
62
75
|
if (err instanceof ForbiddenError) {
|
|
63
76
|
setResponseStatus(event, err.statusCode);
|
|
@@ -73,6 +86,29 @@ async function createShareLink(event: any, deckId: string) {
|
|
|
73
86
|
|
|
74
87
|
const token = crypto.randomBytes(12).toString("base64url");
|
|
75
88
|
const now = new Date().toISOString();
|
|
89
|
+
const designSystemId =
|
|
90
|
+
deckResource.designSystemId ?? storedDeck.designSystemId;
|
|
91
|
+
let designSystemData: string | null = null;
|
|
92
|
+
|
|
93
|
+
if (typeof designSystemId === "string" && designSystemId.trim()) {
|
|
94
|
+
const designSystemAccess = await resolveAccess(
|
|
95
|
+
"design-system",
|
|
96
|
+
designSystemId,
|
|
97
|
+
);
|
|
98
|
+
const rawData = designSystemAccess?.resource?.data;
|
|
99
|
+
if (typeof rawData === "string") {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(rawData);
|
|
102
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
103
|
+
designSystemData = JSON.stringify(parsed as DesignSystemData);
|
|
104
|
+
}
|
|
105
|
+
// coercion-ok: malformed optional style data keeps a valid deck shareable.
|
|
106
|
+
} catch {
|
|
107
|
+
// A malformed style record should not make an otherwise valid deck
|
|
108
|
+
// impossible to share; the presentation will use its default tokens.
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
76
112
|
|
|
77
113
|
const slides = storedDeck.slides.map((slide: unknown, index: number) =>
|
|
78
114
|
toSharedDeckSlide(slide, index),
|
|
@@ -83,6 +119,7 @@ async function createShareLink(event: any, deckId: string) {
|
|
|
83
119
|
title: title || storedDeck.title || "Untitled",
|
|
84
120
|
slides: JSON.stringify(slides),
|
|
85
121
|
aspectRatio: storedDeck.aspectRatio ?? null,
|
|
122
|
+
designSystemData,
|
|
86
123
|
createdAt: now,
|
|
87
124
|
});
|
|
88
125
|
|
|
@@ -136,5 +173,16 @@ export const getSharedDeck = defineEventHandler(async (event) => {
|
|
|
136
173
|
slides: JSON.parse(shared.slides),
|
|
137
174
|
aspectRatio: shared.aspectRatio as SharedDeckResponse["aspectRatio"],
|
|
138
175
|
};
|
|
176
|
+
if (shared.designSystemData) {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = JSON.parse(shared.designSystemData);
|
|
179
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
180
|
+
response.designSystem = parsed as DesignSystemData;
|
|
181
|
+
}
|
|
182
|
+
// coercion-ok: malformed optional snapshots remain viewable with default tokens.
|
|
183
|
+
} catch {
|
|
184
|
+
// Keep legacy or malformed snapshots viewable with default tokens.
|
|
185
|
+
}
|
|
186
|
+
}
|
|
139
187
|
return response;
|
|
140
188
|
});
|
|
@@ -230,6 +230,11 @@ const runSlidesMigrations = runMigrations(
|
|
|
230
230
|
);
|
|
231
231
|
CREATE INDEX IF NOT EXISTS uploaded_assets_owner_created_idx ON uploaded_assets (owner_email, created_at)`,
|
|
232
232
|
},
|
|
233
|
+
{
|
|
234
|
+
version: 21,
|
|
235
|
+
name: "slides-share-design-system-snapshot",
|
|
236
|
+
sql: `ALTER TABLE deck_share_links ADD COLUMN IF NOT EXISTS design_system_data TEXT`,
|
|
237
|
+
},
|
|
233
238
|
],
|
|
234
239
|
{ table: "slides_migrations" },
|
|
235
240
|
);
|