@unoverse-platform/studio 0.1.56 → 0.1.58
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/local/plugin.ts +5 -66
- package/local/sample-template/chat/components/assistant-turn.yaml +40 -0
- package/local/sample-template/chat/components/core-focus.yaml +46 -0
- package/local/sample-template/chat/components/core.yaml +41 -0
- package/local/sample-template/chat/components/focus-overlay.yaml +20 -0
- package/local/sample-template/chat/components/header.yaml +53 -0
- package/local/sample-template/chat/components/suggestions.yaml +142 -0
- package/local/sample-template/chat/components/thinking-dots.yaml +38 -0
- package/local/sample-template/chat/components/user-turn.yaml +22 -0
- package/local/sample-template/chat/layouts/focused.yaml +12 -0
- package/local/sample-template/chat/layouts/standard.yaml +9 -0
- package/local/sample-template/chat/manifest.yaml +41 -0
- package/local/sample-template/chat/states/conversation.yaml +21 -0
- package/local/sample-template/chat/states/welcome.yaml +119 -0
- package/local/scaffold.mjs +15 -2
- package/package.json +1 -1
- package/screens/DesignSystemView.tsx +4 -1
- package/screens/NativeAppHost.tsx +2 -2
- package/screens/TemplatesView.tsx +28 -4
- package/src/App.tsx +14 -70
- package/src/OfflineSession.tsx +50 -0
- package/vendor/sdk/appEngine.tsx +15 -2
- package/vendor/sdk/lib/core/connection.ts +11 -0
- package/vendor/sdk/lib/core/store.ts +17 -0
- package/src/ConnectUniverse.tsx +0 -232
- package/src/PublishDialog.tsx +0 -309
- package/src/UniverseSession.tsx +0 -121
- package/src/universes.ts +0 -210
package/local/plugin.ts
CHANGED
|
@@ -222,7 +222,7 @@ export function localStudioHost(): Plugin {
|
|
|
222
222
|
// 200. That has now cost three separate bugs (the /api allowlist, the dev proxy for
|
|
223
223
|
// /.well-known and /publish), each of which looked like a missing route rather than
|
|
224
224
|
// a filtered one.
|
|
225
|
-
if (!/^\/(dev|local|mcp|skills|prompt-blocks|registry|nodes|keys|execute
|
|
225
|
+
if (!/^\/(dev|local|mcp|skills|prompt-blocks|registry|nodes|keys|execute)\b/.test(path)) return next();
|
|
226
226
|
|
|
227
227
|
/** Read a JSON request body. */
|
|
228
228
|
const body = async (): Promise<Record<string, unknown>> => {
|
|
@@ -248,71 +248,10 @@ export function localStudioHost(): Plugin {
|
|
|
248
248
|
envFiles: [resolve(projectRoot, "..", ".env"), resolve(projectRoot, ".env")],
|
|
249
249
|
});
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
* developer's disk: their definitions, and the design system they built on.
|
|
256
|
-
* A browser cannot, and a server that could would be a server this tool
|
|
257
|
-
* deliberately does not have.
|
|
258
|
-
*
|
|
259
|
-
* The token is passed per request and never stored. Studio holds it in the
|
|
260
|
-
* OIDC session for the tab (UniverseSession) and hands it over for the one
|
|
261
|
-
* call; local Studio writes no secret to disk (local/keys.ts), and connecting
|
|
262
|
-
* to a universe must not be the thing that breaks that.
|
|
263
|
-
*
|
|
264
|
-
* Same functions the CLI uses (`unoverse publish assets`), so the two cannot
|
|
265
|
-
* disagree about what a publish is.
|
|
266
|
-
*/
|
|
267
|
-
case path === "/publish/plan" || path === "/publish/send": {
|
|
268
|
-
const b = await body();
|
|
269
|
-
const project = String(b.project ?? "");
|
|
270
|
-
const universe = String(b.universe ?? "");
|
|
271
|
-
const token = String(b.token ?? "");
|
|
272
|
-
if (!project || !universe || !token)
|
|
273
|
-
return json(res, { error: "project, universe and token are required" }, 400);
|
|
274
|
-
|
|
275
|
-
// Loaded through Vite's SSR runner, like the catalog and node loaders above: a bare
|
|
276
|
-
// dynamic import of a .js path does not resolve to the .ts source. The type below
|
|
277
|
-
// mirrors the module's real exports — tsc can't follow an ssrLoadModule path.
|
|
278
|
-
type PublishItem = { kind: string; name: string; why?: string; mode?: string };
|
|
279
|
-
type PublishModule = {
|
|
280
|
-
lintForPublish(designRoot: string, project: string): Promise<{ problems: unknown[]; errors: unknown[] }>;
|
|
281
|
-
collectProject(designRoot: string, project: string): unknown;
|
|
282
|
-
planPublish(collected: unknown, universe: string, token: string): Promise<Record<string, PublishItem[]>>;
|
|
283
|
-
sendPublish(plan: unknown, universe: string, token: string): Promise<{ sent: PublishItem[]; failed?: PublishItem[] }>;
|
|
284
|
-
};
|
|
285
|
-
const items = (await ssr(`${baseSrc}/items/publish.ts`)) as PublishModule;
|
|
286
|
-
const designRoot = designHome(projectRoot);
|
|
287
|
-
|
|
288
|
-
// LINT FIRST, ALWAYS. Nothing leaves the machine until the rules pass: a
|
|
289
|
-
// developer should learn about a raw hex value here, not from an HTTP error.
|
|
290
|
-
const { problems, errors } = await items.lintForPublish(designRoot, project);
|
|
291
|
-
if (errors.length) return json(res, { blocked: true, problems, errors });
|
|
292
|
-
|
|
293
|
-
const collected = items.collectProject(designRoot, project);
|
|
294
|
-
const plan = await items.planPublish(collected, universe, token);
|
|
295
|
-
|
|
296
|
-
// The screen renders kinds and names. The plan carries every file's full
|
|
297
|
-
// contents, so sending it whole would push the entire project through the
|
|
298
|
-
// browser for a list, and again on send.
|
|
299
|
-
type Lean = { kind: string; name: string; why?: string; mode?: string };
|
|
300
|
-
const lean = (list: Lean[] = []) =>
|
|
301
|
-
list.map(({ kind, name, why, mode }) => ({ kind, name, why, mode }));
|
|
302
|
-
const leanPlan = Object.fromEntries(
|
|
303
|
-
Object.entries(plan as Record<string, Lean[]>).map(([k, v]) => [k, lean(v)]),
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
if (path === "/publish/plan") return json(res, { problems, plan: leanPlan });
|
|
307
|
-
|
|
308
|
-
const result = await items.sendPublish(plan, universe, token);
|
|
309
|
-
return json(res, {
|
|
310
|
-
problems,
|
|
311
|
-
plan: leanPlan,
|
|
312
|
-
sent: lean(result.sent),
|
|
313
|
-
failed: lean(result.failed),
|
|
314
|
-
});
|
|
315
|
-
}
|
|
251
|
+
// NO PUBLISH ROUTES. Studio had /publish/plan and /publish/send; they moved
|
|
252
|
+
// to the terminal whole (LOCAL_STUDIO.md §Publish is terminal-only): the CLI
|
|
253
|
+
// runs the same base items/publish functions directly, and no token ever
|
|
254
|
+
// nears the browser because the browser no longer takes part.
|
|
316
255
|
|
|
317
256
|
case path === "/dev/orgs":
|
|
318
257
|
return json(res, { orgs: c.themeOrgs() });
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
visibleWhen: active
|
|
3
|
+
style:
|
|
4
|
+
direction: row
|
|
5
|
+
gap: "2"
|
|
6
|
+
align: start
|
|
7
|
+
children:
|
|
8
|
+
- type: Box
|
|
9
|
+
style:
|
|
10
|
+
direction: column
|
|
11
|
+
flex: 1
|
|
12
|
+
gap: "2"
|
|
13
|
+
minWidth: 0
|
|
14
|
+
children:
|
|
15
|
+
- type: ComponentSlot
|
|
16
|
+
select: {}
|
|
17
|
+
- type: Box
|
|
18
|
+
visibleWhen: streaming
|
|
19
|
+
children:
|
|
20
|
+
- type: Box
|
|
21
|
+
visibleWhen: empty
|
|
22
|
+
style:
|
|
23
|
+
direction: row
|
|
24
|
+
gap: "2"
|
|
25
|
+
align: center
|
|
26
|
+
children:
|
|
27
|
+
- $include: components/thinking-dots
|
|
28
|
+
- type: Text
|
|
29
|
+
bind:
|
|
30
|
+
value: thinkingText
|
|
31
|
+
style:
|
|
32
|
+
font: body.sm
|
|
33
|
+
color: text.secondary
|
|
34
|
+
- type: Text
|
|
35
|
+
visibleWhen: time
|
|
36
|
+
bind:
|
|
37
|
+
value: time
|
|
38
|
+
style:
|
|
39
|
+
font: body.sm
|
|
40
|
+
color: text.secondary
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# THE CHAT COLUMN WITH A FOCUSED COMPONENT OVER IT — core, plus the focus surface
|
|
2
|
+
# laid over the conversation region. A core VARIANT, not a copy: header, states and
|
|
3
|
+
# composer are the same shared files core.yaml includes; the only difference is the
|
|
4
|
+
# overlay slot.
|
|
5
|
+
type: Box
|
|
6
|
+
appWidth: chat
|
|
7
|
+
style:
|
|
8
|
+
direction: column
|
|
9
|
+
minHeight: "0"
|
|
10
|
+
children:
|
|
11
|
+
- type: Box
|
|
12
|
+
style:
|
|
13
|
+
direction: column
|
|
14
|
+
flex: 1
|
|
15
|
+
minHeight: "0"
|
|
16
|
+
position: relative
|
|
17
|
+
children:
|
|
18
|
+
- $include: components/header
|
|
19
|
+
- type: Box
|
|
20
|
+
style:
|
|
21
|
+
direction: column
|
|
22
|
+
flex: 1
|
|
23
|
+
minHeight: "0"
|
|
24
|
+
position: relative
|
|
25
|
+
when:
|
|
26
|
+
- field: hasMessages
|
|
27
|
+
eq: true
|
|
28
|
+
apply:
|
|
29
|
+
background: surface.base
|
|
30
|
+
radiusTopLeft: 2xl
|
|
31
|
+
overflow: hidden
|
|
32
|
+
children:
|
|
33
|
+
- $include: states/welcome
|
|
34
|
+
- $include: states/conversation
|
|
35
|
+
- type: Box
|
|
36
|
+
style:
|
|
37
|
+
position: absolute
|
|
38
|
+
bottom: "0"
|
|
39
|
+
left: "0"
|
|
40
|
+
right: "0"
|
|
41
|
+
direction: column
|
|
42
|
+
children:
|
|
43
|
+
- $include: components/suggestions
|
|
44
|
+
- $include: components/focus-overlay
|
|
45
|
+
- type: Ref
|
|
46
|
+
ref: composer-bar
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
appWidth: chat
|
|
3
|
+
style:
|
|
4
|
+
direction: column
|
|
5
|
+
minHeight: "0"
|
|
6
|
+
children:
|
|
7
|
+
- type: Box
|
|
8
|
+
style:
|
|
9
|
+
direction: column
|
|
10
|
+
flex: 1
|
|
11
|
+
minHeight: "0"
|
|
12
|
+
position: relative
|
|
13
|
+
children:
|
|
14
|
+
- $include: components/header
|
|
15
|
+
- type: Box
|
|
16
|
+
style:
|
|
17
|
+
direction: column
|
|
18
|
+
flex: 1
|
|
19
|
+
minHeight: "0"
|
|
20
|
+
position: relative
|
|
21
|
+
when:
|
|
22
|
+
- field: hasMessages
|
|
23
|
+
eq: true
|
|
24
|
+
apply:
|
|
25
|
+
background: surface.base
|
|
26
|
+
radiusTopLeft: 2xl
|
|
27
|
+
overflow: hidden
|
|
28
|
+
children:
|
|
29
|
+
- $include: states/welcome
|
|
30
|
+
- $include: states/conversation
|
|
31
|
+
- type: Box
|
|
32
|
+
style:
|
|
33
|
+
position: absolute
|
|
34
|
+
bottom: "0"
|
|
35
|
+
left: "0"
|
|
36
|
+
right: "0"
|
|
37
|
+
direction: column
|
|
38
|
+
children:
|
|
39
|
+
- $include: components/suggestions
|
|
40
|
+
- type: Ref
|
|
41
|
+
ref: composer-bar
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type: ComponentSlot
|
|
2
|
+
select:
|
|
3
|
+
from: all
|
|
4
|
+
where:
|
|
5
|
+
field: view
|
|
6
|
+
eq: focused
|
|
7
|
+
limit: 1
|
|
8
|
+
frame:
|
|
9
|
+
type: Box
|
|
10
|
+
style:
|
|
11
|
+
position: absolute
|
|
12
|
+
inset: "0"
|
|
13
|
+
width: full
|
|
14
|
+
height: full
|
|
15
|
+
background: surface.base
|
|
16
|
+
overflow: hidden
|
|
17
|
+
direction: column
|
|
18
|
+
align: stretch
|
|
19
|
+
children:
|
|
20
|
+
- type: ComponentSlot
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
style:
|
|
3
|
+
direction: row
|
|
4
|
+
align: center
|
|
5
|
+
justify: space-between
|
|
6
|
+
height: "20"
|
|
7
|
+
padding: [ "0", "4" ]
|
|
8
|
+
background: transparent
|
|
9
|
+
children:
|
|
10
|
+
- type: Box
|
|
11
|
+
style:
|
|
12
|
+
direction: row
|
|
13
|
+
align: center
|
|
14
|
+
gap: "2"
|
|
15
|
+
children:
|
|
16
|
+
- type: Icon
|
|
17
|
+
icon: sparkles
|
|
18
|
+
style:
|
|
19
|
+
width: "6"
|
|
20
|
+
height: "6"
|
|
21
|
+
color: action.primary
|
|
22
|
+
- type: Text
|
|
23
|
+
style:
|
|
24
|
+
font: title
|
|
25
|
+
color: text.primary
|
|
26
|
+
value: Assistant
|
|
27
|
+
- type: Button
|
|
28
|
+
action: close
|
|
29
|
+
style:
|
|
30
|
+
flex: 0 0 auto
|
|
31
|
+
cursor: pointer
|
|
32
|
+
width: "8"
|
|
33
|
+
height: "8"
|
|
34
|
+
radius: full
|
|
35
|
+
background: surface.base
|
|
36
|
+
border: subtle
|
|
37
|
+
shadow: sm
|
|
38
|
+
direction: row
|
|
39
|
+
align: center
|
|
40
|
+
justify: center
|
|
41
|
+
transition: all 150ms ease
|
|
42
|
+
hover:
|
|
43
|
+
background: surface.sunken
|
|
44
|
+
children:
|
|
45
|
+
- type: Icon
|
|
46
|
+
icon: close
|
|
47
|
+
style:
|
|
48
|
+
width: "4"
|
|
49
|
+
height: "4"
|
|
50
|
+
color: text.secondary
|
|
51
|
+
visibleWhen:
|
|
52
|
+
field: surfacedView
|
|
53
|
+
in: [ "" ]
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
visibleWhen: hasMessages
|
|
3
|
+
style:
|
|
4
|
+
width: full
|
|
5
|
+
position: relative
|
|
6
|
+
direction: column
|
|
7
|
+
background: transparent
|
|
8
|
+
children:
|
|
9
|
+
- type: Box
|
|
10
|
+
visibleWhen:
|
|
11
|
+
field: openPanel
|
|
12
|
+
eq: faq
|
|
13
|
+
style:
|
|
14
|
+
width: full
|
|
15
|
+
direction: column
|
|
16
|
+
gap: "2"
|
|
17
|
+
background: surface.base
|
|
18
|
+
radius: lg
|
|
19
|
+
padding: "4"
|
|
20
|
+
shadow: lg
|
|
21
|
+
margin: [ "0", "0", "2", "0" ]
|
|
22
|
+
animation:
|
|
23
|
+
name: slideUp
|
|
24
|
+
duration: 0.3s
|
|
25
|
+
easing: ease-out
|
|
26
|
+
iteration: "1"
|
|
27
|
+
children:
|
|
28
|
+
- type: Box
|
|
29
|
+
style:
|
|
30
|
+
direction: row
|
|
31
|
+
justify: end
|
|
32
|
+
children:
|
|
33
|
+
- type: Button
|
|
34
|
+
action:
|
|
35
|
+
type: setTemplateValue
|
|
36
|
+
values:
|
|
37
|
+
- key: openPanel
|
|
38
|
+
value: null
|
|
39
|
+
style:
|
|
40
|
+
flex: 0 0 auto
|
|
41
|
+
cursor: pointer
|
|
42
|
+
width: "8"
|
|
43
|
+
height: "8"
|
|
44
|
+
radius: full
|
|
45
|
+
background: surface.base
|
|
46
|
+
border: subtle
|
|
47
|
+
shadow: sm
|
|
48
|
+
direction: row
|
|
49
|
+
align: center
|
|
50
|
+
justify: center
|
|
51
|
+
transition: all 150ms ease
|
|
52
|
+
hover:
|
|
53
|
+
background: surface.sunken
|
|
54
|
+
children:
|
|
55
|
+
- type: Icon
|
|
56
|
+
icon: close
|
|
57
|
+
style:
|
|
58
|
+
width: "4"
|
|
59
|
+
height: "4"
|
|
60
|
+
color: text.secondary
|
|
61
|
+
- type: Each
|
|
62
|
+
style:
|
|
63
|
+
direction: row
|
|
64
|
+
wrap: wrap
|
|
65
|
+
align: start
|
|
66
|
+
gap: "2"
|
|
67
|
+
width: full
|
|
68
|
+
template:
|
|
69
|
+
type: Button
|
|
70
|
+
action:
|
|
71
|
+
type: sendMessage
|
|
72
|
+
then:
|
|
73
|
+
type: setTemplateValue
|
|
74
|
+
values:
|
|
75
|
+
- key: openPanel
|
|
76
|
+
value: null
|
|
77
|
+
style:
|
|
78
|
+
direction: row
|
|
79
|
+
align: center
|
|
80
|
+
flex: 0 0 auto
|
|
81
|
+
maxWidth: full
|
|
82
|
+
padding: [ "2", "4" ]
|
|
83
|
+
background: surface.base
|
|
84
|
+
border: subtle
|
|
85
|
+
outline: none
|
|
86
|
+
radius: full
|
|
87
|
+
shadow: sm
|
|
88
|
+
cursor: pointer
|
|
89
|
+
transition: all 150ms ease
|
|
90
|
+
hover:
|
|
91
|
+
background: surface.sunken
|
|
92
|
+
children:
|
|
93
|
+
- type: Text
|
|
94
|
+
bind:
|
|
95
|
+
value: text
|
|
96
|
+
style:
|
|
97
|
+
font: body.sm
|
|
98
|
+
color: text.secondary
|
|
99
|
+
lineHeight: tight
|
|
100
|
+
items:
|
|
101
|
+
- text: What can you help me with?
|
|
102
|
+
- text: How does this work?
|
|
103
|
+
- text: Show me an example
|
|
104
|
+
- type: Box
|
|
105
|
+
style:
|
|
106
|
+
width: full
|
|
107
|
+
direction: row
|
|
108
|
+
justify: center
|
|
109
|
+
padding: [ "1", "0" ]
|
|
110
|
+
children:
|
|
111
|
+
- type: Button
|
|
112
|
+
action:
|
|
113
|
+
type: setTemplateValue
|
|
114
|
+
values:
|
|
115
|
+
- key: openPanel
|
|
116
|
+
value: faq
|
|
117
|
+
style:
|
|
118
|
+
direction: row
|
|
119
|
+
align: center
|
|
120
|
+
gap: "1"
|
|
121
|
+
padding: [ "1", "3" ]
|
|
122
|
+
background: surface.base
|
|
123
|
+
border: subtle
|
|
124
|
+
outline: none
|
|
125
|
+
radius: full
|
|
126
|
+
cursor: pointer
|
|
127
|
+
transition: all 150ms ease
|
|
128
|
+
hover:
|
|
129
|
+
background: surface.sunken
|
|
130
|
+
children:
|
|
131
|
+
- type: Icon
|
|
132
|
+
icon: chat
|
|
133
|
+
style:
|
|
134
|
+
width: "4"
|
|
135
|
+
height: "4"
|
|
136
|
+
color: text.secondary
|
|
137
|
+
- type: Text
|
|
138
|
+
style:
|
|
139
|
+
font: body.sm
|
|
140
|
+
color: text.secondary
|
|
141
|
+
weight: medium
|
|
142
|
+
value: Suggestions
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
style:
|
|
3
|
+
direction: row
|
|
4
|
+
gap: "1"
|
|
5
|
+
align: center
|
|
6
|
+
children:
|
|
7
|
+
- type: Box
|
|
8
|
+
style:
|
|
9
|
+
width: "1.5"
|
|
10
|
+
height: "1.5"
|
|
11
|
+
background: action.primary
|
|
12
|
+
radius: full
|
|
13
|
+
animation:
|
|
14
|
+
name: wave
|
|
15
|
+
duration: 1.6s
|
|
16
|
+
easing: ease-in-out
|
|
17
|
+
- type: Box
|
|
18
|
+
style:
|
|
19
|
+
width: "1.5"
|
|
20
|
+
height: "1.5"
|
|
21
|
+
background: action.primary
|
|
22
|
+
radius: full
|
|
23
|
+
animation:
|
|
24
|
+
name: wave
|
|
25
|
+
duration: 1.6s
|
|
26
|
+
easing: ease-in-out
|
|
27
|
+
animationDelay: 0.16s
|
|
28
|
+
- type: Box
|
|
29
|
+
style:
|
|
30
|
+
width: "1.5"
|
|
31
|
+
height: "1.5"
|
|
32
|
+
background: action.primary
|
|
33
|
+
radius: full
|
|
34
|
+
animation:
|
|
35
|
+
name: wave
|
|
36
|
+
duration: 1.6s
|
|
37
|
+
easing: ease-in-out
|
|
38
|
+
animationDelay: 0.32s
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
style:
|
|
3
|
+
direction: row
|
|
4
|
+
justify: end
|
|
5
|
+
children:
|
|
6
|
+
- type: Box
|
|
7
|
+
style:
|
|
8
|
+
direction: row
|
|
9
|
+
align: center
|
|
10
|
+
background: action.primary
|
|
11
|
+
radius: 2xl
|
|
12
|
+
radiusTopRight: sm
|
|
13
|
+
padding: [ "2", "4" ]
|
|
14
|
+
maxWidth: compact
|
|
15
|
+
children:
|
|
16
|
+
- type: Text
|
|
17
|
+
bind:
|
|
18
|
+
value: text
|
|
19
|
+
style:
|
|
20
|
+
font: body.md
|
|
21
|
+
color: action.primary-text
|
|
22
|
+
lineHeight: tight
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# FOCUSED — a component holding the conversation region, composer live beneath.
|
|
2
|
+
# A LAYOUT owned by the `focused` state: a hosted component writes `view: focused`,
|
|
3
|
+
# the ladder makes this arrangement active, this file draws it.
|
|
4
|
+
type: Box
|
|
5
|
+
style:
|
|
6
|
+
direction: row
|
|
7
|
+
width: full
|
|
8
|
+
height: full
|
|
9
|
+
overflow: hidden
|
|
10
|
+
background: surface.sunken
|
|
11
|
+
children:
|
|
12
|
+
- $include: components/core-focus
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# A GENERIC CHAT — a worked example template, shipped with Studio so templates/ is
|
|
2
|
+
# never an empty folder. It is yours: rename it, restyle it (it uses only foundation
|
|
3
|
+
# tokens, so your project's theme restyles it whole), or delete it.
|
|
4
|
+
# Guide: https://docs.unoverse.ai/design/templates.md
|
|
5
|
+
name: chat
|
|
6
|
+
description: A conversational assistant surface with a welcome hero, suggestions, and a focus overlay.
|
|
7
|
+
whenToUse: Talk to the assistant — ask a question, get help, or start any task in conversation. The conversational home and fallback surface.
|
|
8
|
+
category: Assistant
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
defaultState: template
|
|
11
|
+
inputSchema:
|
|
12
|
+
type: object
|
|
13
|
+
properties:
|
|
14
|
+
message:
|
|
15
|
+
type: string
|
|
16
|
+
description: The user's request
|
|
17
|
+
|
|
18
|
+
# THE TEMPLATE TREE (State Model v2): one declaration, everything follows.
|
|
19
|
+
# Top-level order IS the priority ladder (base first, then reaction states). NESTING
|
|
20
|
+
# is containment: welcome exists only inside standard — the compiler strips it from
|
|
21
|
+
# every other arrangement — and it is the landing default. No stateOrder, no
|
|
22
|
+
# hand-written guards.
|
|
23
|
+
# NOTE: the conversation timeline is NOT declared as a substate — it is standard's own
|
|
24
|
+
# shell content (states/conversation), included by the shared chrome (components/core)
|
|
25
|
+
# and legitimately drawn under the focus overlay too. Declaring it would contain it to
|
|
26
|
+
# standard and empty the chat column in every reaction state.
|
|
27
|
+
states:
|
|
28
|
+
standard:
|
|
29
|
+
states:
|
|
30
|
+
welcome: {}
|
|
31
|
+
focused: {}
|
|
32
|
+
|
|
33
|
+
preview:
|
|
34
|
+
conversation: [ markdown-renderer ]
|
|
35
|
+
focused: [ card ]
|
|
36
|
+
|
|
37
|
+
autoTrigger: false
|
|
38
|
+
# BIND YOUR WORKFLOW to bring this to life: build one on the Canvas, then set
|
|
39
|
+
# binding: { workflow: <workflow-id>, trigger: <trigger-node-id> }
|
|
40
|
+
# The app owns its workflow; until it is bound, this template previews but cannot run.
|
|
41
|
+
layout: standard
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type: Box
|
|
2
|
+
visibleWhen: hasMessages
|
|
3
|
+
autoScroll: true
|
|
4
|
+
style:
|
|
5
|
+
flex: 1
|
|
6
|
+
minHeight: "0"
|
|
7
|
+
direction: column
|
|
8
|
+
overflow: auto
|
|
9
|
+
padding: [ "6", "8" ]
|
|
10
|
+
children:
|
|
11
|
+
- type: Timeline
|
|
12
|
+
style:
|
|
13
|
+
direction: column
|
|
14
|
+
gap: "4"
|
|
15
|
+
margin: [ auto, "0", "0", "0" ]
|
|
16
|
+
assistantData:
|
|
17
|
+
thinkingText: Thinking…
|
|
18
|
+
user:
|
|
19
|
+
$include: components/user-turn
|
|
20
|
+
assistant:
|
|
21
|
+
$include: components/assistant-turn
|