@adia-ai/web-modules 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +292 -0
  2. package/README.md +119 -0
  3. package/chat/chat-shell/chat-shell.a2ui.json +149 -0
  4. package/chat/chat-shell/chat-shell.css +10 -0
  5. package/chat/chat-shell/chat-shell.js +297 -0
  6. package/chat/chat-shell/chat-shell.yaml +119 -0
  7. package/chat/chat-shell/css/chat-shell.empty.css +12 -0
  8. package/chat/chat-shell/css/chat-shell.layout.css +60 -0
  9. package/chat/chat-shell/css/chat-shell.markdown.css +74 -0
  10. package/chat/chat-shell/css/chat-shell.messages.css +87 -0
  11. package/chat/chat-shell/css/chat-shell.streaming.css +30 -0
  12. package/chat/chat-shell/css/chat-shell.tokens.css +95 -0
  13. package/chat/index.js +1 -0
  14. package/editor/editor-shell/css/editor-shell.layout.css +171 -0
  15. package/editor/editor-shell/css/editor-shell.tokens.css +28 -0
  16. package/editor/editor-shell/editor-shell.a2ui.json +73 -0
  17. package/editor/editor-shell/editor-shell.css +6 -0
  18. package/editor/editor-shell/editor-shell.js +56 -0
  19. package/editor/editor-shell/editor-shell.yaml +59 -0
  20. package/editor/index.js +1 -0
  21. package/index.js +14 -0
  22. package/package.json +48 -0
  23. package/runtime/a2ui-root/a2ui-root.a2ui.json +125 -0
  24. package/runtime/a2ui-root/a2ui-root.js +191 -0
  25. package/runtime/a2ui-root/a2ui-root.yaml +87 -0
  26. package/runtime/gen-root/gen-root.a2ui.json +72 -0
  27. package/runtime/gen-root/gen-root.css +83 -0
  28. package/runtime/gen-root/gen-root.js +136 -0
  29. package/runtime/gen-root/gen-root.yaml +43 -0
  30. package/runtime/index.js +2 -0
  31. package/shell/admin-shell/admin-shell.a2ui.json +129 -0
  32. package/shell/admin-shell/admin-shell.css +14 -0
  33. package/shell/admin-shell/admin-shell.js +261 -0
  34. package/shell/admin-shell/admin-shell.yaml +89 -0
  35. package/shell/admin-shell/css/admin-shell.collapsed.css +86 -0
  36. package/shell/admin-shell/css/admin-shell.helpers.css +42 -0
  37. package/shell/admin-shell/css/admin-shell.main.css +182 -0
  38. package/shell/admin-shell/css/admin-shell.shell.css +48 -0
  39. package/shell/admin-shell/css/admin-shell.sidebar.css +165 -0
  40. package/shell/admin-shell/css/admin-shell.templates.css +215 -0
  41. package/shell/admin-shell/css/admin-shell.tokens.css +119 -0
  42. package/shell/index.js +1 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * <a2ui-root> — A2UI protocol surface.
3
+ * Connects to a stream source and renders A2UI messages as AdiaUI components.
4
+ *
5
+ * <a2ui-root src="/api/agent" transport="sse"></a2ui-root>
6
+ * <a2ui-root src="ws://localhost:8080" transport="ws"></a2ui-root>
7
+ *
8
+ * Static / author-driven mode — set the `doc` property (array of A2UI messages)
9
+ * and the renderer resets + replays them. Editors and previews can drive the
10
+ * surface without opening a transport. Setting `doc` to a new array re-renders
11
+ * from scratch (reset() + processAll()).
12
+ *
13
+ * const root = document.querySelector('a2ui-root');
14
+ * root.doc = [
15
+ * { type: 'createSurface', surfaceId: 'root', root: 'c-1' },
16
+ * { type: 'updateComponents', components: [{ id: 'c-1', component: 'Heading', text: 'Hi' }] },
17
+ * ];
18
+ *
19
+ * Events:
20
+ * a2ui-connected — stream connected
21
+ * a2ui-message — each message received (detail: { message })
22
+ * a2ui-error — stream error (detail: { error })
23
+ * a2ui-closed — stream ended
24
+ * a2ui-action — user interaction (detail: { name, sourceComponentId, context })
25
+ * doc-replaced — fired after a full doc reset + replay (author-driven mode)
26
+ */
27
+
28
+ import { UIElement } from '../../../web-components/core/element.js';
29
+ import {
30
+ A2UIRenderer,
31
+ registry,
32
+ sseStream,
33
+ wsStream,
34
+ jsonlStream,
35
+ mcpStream,
36
+ } from '@adia-ai/a2ui-utils';
37
+
38
+ class A2UIRoot extends UIElement {
39
+ static properties = {
40
+ src: { type: String, default: '', reflect: true },
41
+ transport: { type: String, default: 'sse', reflect: true },
42
+ loading: { type: Boolean, default: false, reflect: true },
43
+ active: { type: Boolean, default: false, reflect: true },
44
+ batch: { type: Boolean, default: false, reflect: true },
45
+ };
46
+
47
+ static template = () => null;
48
+
49
+ #renderer = null;
50
+ #abortCtrl = null;
51
+ #doc = null;
52
+ #bound = false;
53
+
54
+ #onClick = (e) => {
55
+ const actionEl = e.target.closest('[data-action]');
56
+ if (!actionEl) return;
57
+ this.dispatchEvent(new CustomEvent('a2ui-action', {
58
+ bubbles: true,
59
+ detail: {
60
+ name: actionEl.getAttribute('data-action'),
61
+ sourceComponentId: actionEl.getAttribute('data-a2ui-id') || '',
62
+ timestamp: Date.now(),
63
+ context: {},
64
+ },
65
+ }));
66
+ };
67
+
68
+ connected() {
69
+ this.#renderer = new A2UIRenderer(this, registry, { batch: this.batch });
70
+
71
+ if (!this.#bound) {
72
+ this.#bound = true;
73
+ this.addEventListener('click', this.#onClick);
74
+ }
75
+ }
76
+
77
+ render() {
78
+ if (this.src && !this.active) this.#connect();
79
+ }
80
+
81
+ async #connect() {
82
+ this.#abortCtrl?.abort();
83
+ this.#abortCtrl = new AbortController();
84
+ const signal = this.#abortCtrl.signal;
85
+
86
+ this.loading = true;
87
+ this.active = false;
88
+
89
+ let stream;
90
+ try {
91
+ switch (this.transport) {
92
+ case 'sse':
93
+ stream = sseStream(this.src, { signal, catalog: registry });
94
+ break;
95
+ case 'ws':
96
+ case 'websocket':
97
+ stream = wsStream(this.src, { signal, catalog: registry });
98
+ break;
99
+ case 'jsonl':
100
+ stream = jsonlStream(this.src, { signal, catalog: registry });
101
+ break;
102
+ case 'mcp':
103
+ stream = mcpStream(this.src, {
104
+ signal,
105
+ catalog: registry,
106
+ onAction: (name, params) => {
107
+ this.dispatchEvent(new CustomEvent('a2ui-action', {
108
+ bubbles: true,
109
+ detail: { name, params, timestamp: Date.now() },
110
+ }));
111
+ return Promise.resolve({ status: 'dispatched' });
112
+ },
113
+ });
114
+ break;
115
+ default:
116
+ console.warn(`a2ui-root: unknown transport "${this.transport}"`);
117
+ return;
118
+ }
119
+
120
+ this.active = true;
121
+ this.loading = false;
122
+ this.dispatchEvent(new Event('a2ui-connected', { bubbles: true }));
123
+
124
+ for await (const message of stream) {
125
+ if (signal.aborted) break;
126
+ this.#renderer.process(message);
127
+ this.dispatchEvent(new CustomEvent('a2ui-message', {
128
+ bubbles: true,
129
+ detail: { message },
130
+ }));
131
+ }
132
+ } catch (err) {
133
+ if (!signal.aborted) {
134
+ this.dispatchEvent(new CustomEvent('a2ui-error', {
135
+ bubbles: true,
136
+ detail: { error: err },
137
+ }));
138
+ }
139
+ }
140
+
141
+ this.active = false;
142
+ this.loading = false;
143
+ this.dispatchEvent(new Event('a2ui-closed', { bubbles: true }));
144
+ }
145
+
146
+ process(message) {
147
+ if (!this.#renderer) {
148
+ this.#renderer = new A2UIRenderer(this, registry);
149
+ }
150
+ this.#renderer.process(message);
151
+ }
152
+
153
+ processAll(messages) {
154
+ for (const msg of messages) this.process(msg);
155
+ }
156
+
157
+ get doc() { return this.#doc; }
158
+ set doc(messages) {
159
+ this.#doc = Array.isArray(messages) ? messages : [];
160
+ if (!this.#renderer) {
161
+ this.#renderer = new A2UIRenderer(this, registry);
162
+ }
163
+ this.#renderer.reset();
164
+ for (const msg of this.#doc) this.#renderer.process(msg);
165
+ this.dispatchEvent(new CustomEvent('doc-replaced', {
166
+ bubbles: true,
167
+ detail: { count: this.#doc.length },
168
+ }));
169
+ }
170
+
171
+ reset() {
172
+ this.#renderer?.reset();
173
+ }
174
+
175
+ disconnect() {
176
+ this.#abortCtrl?.abort();
177
+ this.active = false;
178
+ }
179
+
180
+ disconnected() {
181
+ this.#abortCtrl?.abort();
182
+ this.removeEventListener('click', this.#onClick);
183
+ this.#bound = false;
184
+ this.active = false;
185
+ }
186
+
187
+ get renderer() { return this.#renderer; }
188
+ }
189
+ customElements.define('a2ui-root', A2UIRoot);
190
+
191
+ export { A2UIRoot };
@@ -0,0 +1,87 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: A2UIRoot
4
+ tag: a2ui-root
5
+ component: A2UIRoot
6
+ category: container
7
+ version: 1
8
+ description: A2UI protocol surface. Connects to a stream source (SSE, WebSocket, JSONL, MCP) and renders A2UI messages as AdiaUI components via the `@adia-ai/a2ui-utils` renderer.
9
+ props:
10
+ src:
11
+ description: Stream source URL (endpoint for SSE/WebSocket, file path for JSONL, tool-call target for MCP).
12
+ type: string
13
+ default: ""
14
+ transport:
15
+ description: Stream transport to use.
16
+ type: string
17
+ default: sse
18
+ enum:
19
+ - sse
20
+ - ws
21
+ - websocket
22
+ - jsonl
23
+ - mcp
24
+ loading:
25
+ description: True while the stream is connecting.
26
+ type: boolean
27
+ default: false
28
+ reflect: true
29
+ active:
30
+ description: True while the stream is connected and receiving messages.
31
+ type: boolean
32
+ default: false
33
+ reflect: true
34
+ batch:
35
+ description: Batch renderer updates via requestAnimationFrame for large fan-in.
36
+ type: boolean
37
+ default: false
38
+ doc:
39
+ description: >-
40
+ Author-driven mode — set to an array of A2UI messages and the renderer
41
+ resets + replays them. No network/transport involvement. Setting to a
42
+ new array triggers a full re-render. Use this for editors, previews,
43
+ tests, and any static-doc authoring loop. When both `src` and `doc` are
44
+ set, `doc` wins (the stream is not opened). Pass as a JS property; not
45
+ reflected to an attribute.
46
+ type: array
47
+ events:
48
+ a2ui-connected:
49
+ description: Fired when the stream is established.
50
+ a2ui-message:
51
+ description: "Fired for each A2UI message received. detail: { message }"
52
+ a2ui-action:
53
+ description: "Fired when a child element with [data-action] is clicked. detail: { name, sourceComponentId, context }"
54
+ a2ui-error:
55
+ description: "Fired when the stream errors. detail: { error }"
56
+ a2ui-closed:
57
+ description: Fired when the stream ends.
58
+ doc-replaced:
59
+ description: "Fired after a full doc reset + replay in author-driven mode. detail: { count }"
60
+ slots:
61
+ default:
62
+ description: The rendered surface. Children are stamped by the A2UI renderer.
63
+ states:
64
+ - name: idle
65
+ description: Default, ready to connect.
66
+ - name: loading
67
+ description: Stream is connecting.
68
+ - name: active
69
+ description: Stream is connected and receiving messages.
70
+ traits: []
71
+ tokens: {}
72
+ a2ui:
73
+ rules: []
74
+ anti_patterns: []
75
+ keywords:
76
+ - a2ui
77
+ - protocol
78
+ - renderer
79
+ - stream
80
+ - surface
81
+ - sse
82
+ - websocket
83
+ - jsonl
84
+ - mcp
85
+ related:
86
+ - canvas
87
+ - inspector
@@ -0,0 +1,72 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/GenRoot.json",
4
+ "title": "GenRoot",
5
+ "description": "Composition shell for chat + canvas generative UI. Manages layout modes\n(chat-only / split / canvas-only) and delegates a unified API across\nchild chat-ui, canvas-ui, and inspector-ui elements.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "component": {
17
+ "const": "GenRoot"
18
+ },
19
+ "inspector": {
20
+ "description": "Show the inspector pane (for debugging generated A2UI).",
21
+ "type": "boolean",
22
+ "default": false
23
+ },
24
+ "mode": {
25
+ "description": "Layout mode — chat-only, 50/50 split, or canvas-only.",
26
+ "type": "string",
27
+ "enum": [
28
+ "chat",
29
+ "split",
30
+ "canvas"
31
+ ],
32
+ "default": "chat"
33
+ }
34
+ },
35
+ "required": [
36
+ "component"
37
+ ],
38
+ "unevaluatedProperties": false,
39
+ "x-adiaui": {
40
+ "anti_patterns": [],
41
+ "category": "layout",
42
+ "events": {},
43
+ "examples": [],
44
+ "keywords": [
45
+ "gen-ui",
46
+ "generative-ui",
47
+ "chat-canvas",
48
+ "agent-shell"
49
+ ],
50
+ "name": "GenRoot",
51
+ "related": [
52
+ "AppShell",
53
+ "Chat"
54
+ ],
55
+ "slots": {
56
+ "default": {
57
+ "description": "Author supplies chat-ui, canvas-ui, and optional inspector-ui children."
58
+ }
59
+ },
60
+ "states": [
61
+ {
62
+ "description": "Default mode=chat.",
63
+ "name": "idle"
64
+ }
65
+ ],
66
+ "synonyms": {},
67
+ "tag": "gen-root",
68
+ "tokens": {},
69
+ "traits": [],
70
+ "version": 1
71
+ }
72
+ }
@@ -0,0 +1,83 @@
1
+ @scope (gen-root) {
2
+
3
+ /* ═══════════════════════════════════════════════════════
4
+ SHELL HOST — full bleed, no card chrome
5
+ ═══════════════════════════════════════════════════════ */
6
+
7
+ :scope {
8
+ box-sizing: border-box;
9
+ display: grid;
10
+ height: 100%;
11
+ min-height: 0;
12
+ background: var(--chat-bg, var(--a-canvas-0));
13
+ font-family: var(--a-font-family);
14
+ overflow: hidden;
15
+
16
+ /* Default: chat mode — single column */
17
+ grid-template-columns: 1fr;
18
+ }
19
+
20
+ /* ═══════════════════════════════════════════════════════
21
+ MODE: CHAT (initial screen — thread only, full width)
22
+ ═══════════════════════════════════════════════════════ */
23
+
24
+ :scope[mode="chat"] {
25
+ grid-template-columns: 1fr;
26
+ }
27
+
28
+ :scope[mode="chat"] > canvas-ui {
29
+ display: none;
30
+ }
31
+
32
+ /* ═══════════════════════════════════════════════════════
33
+ MODE: SPLIT (dialog left + canvas right)
34
+ ═══════════════════════════════════════════════════════ */
35
+
36
+ :scope[mode="split"] {
37
+ grid-template-columns: minmax(320px, 1fr) 1.5fr;
38
+ }
39
+
40
+ :scope[mode="split"] > chat-ui {
41
+ border-right: var(--a-border-thin) solid var(--a-canvas-border-subtle);
42
+ }
43
+
44
+ /* ═══════════════════════════════════════════════════════
45
+ MODE: CANVAS (canvas only)
46
+ ═══════════════════════════════════════════════════════ */
47
+
48
+ :scope[mode="canvas"] {
49
+ grid-template-columns: 1fr;
50
+ }
51
+
52
+ :scope[mode="canvas"] > chat-ui {
53
+ display: none;
54
+ }
55
+
56
+ /* ═══════════════════════════════════════════════════════
57
+ INSPECTOR
58
+ ═══════════════════════════════════════════════════════ */
59
+
60
+ :scope > inspector-ui {
61
+ display: none;
62
+ }
63
+
64
+ :scope[inspector] > inspector-ui {
65
+ display: flex;
66
+ border-left: var(--a-border-thin) solid var(--a-canvas-border-subtle);
67
+ }
68
+
69
+ :scope[mode="split"][inspector] {
70
+ grid-template-columns: minmax(320px, 1fr) 1.5fr 1fr;
71
+ }
72
+
73
+ /* ═══════════════════════════════════════════════════════
74
+ CHILDREN — fill grid cells
75
+ ═══════════════════════════════════════════════════════ */
76
+
77
+ :scope > chat-ui,
78
+ :scope > canvas-ui,
79
+ :scope > inspector-ui {
80
+ min-height: 0;
81
+ min-width: 0;
82
+ }
83
+ }
@@ -0,0 +1,136 @@
1
+ import { UIElement } from '../../../web-components/core/element.js';
2
+ import '../../../web-components/components/chat-thread/chat-thread.js';
3
+ import '../../../web-components/components/canvas/canvas.js';
4
+ import '../../../web-components/components/inspector/inspector.js';
5
+
6
+ /**
7
+ * <gen-root> — Composition shell for chat + canvas generative UI.
8
+ *
9
+ * Modes:
10
+ * chat — thread only, full width
11
+ * split — thread left + canvas right (50/50)
12
+ * canvas — canvas only, thread hidden
13
+ *
14
+ * Consumer-owns-LLM: forwards all events from children, never calls fetch.
15
+ *
16
+ * Events (forwarded):
17
+ * submit — from thread (chat input)
18
+ * suggestion-select — from thread
19
+ * canvas-interaction — from canvas
20
+ */
21
+ export class GenRoot extends UIElement {
22
+ static properties = {
23
+ mode: { type: String, default: 'chat', reflect: true },
24
+ inspector: { type: Boolean, default: false, reflect: true },
25
+ };
26
+
27
+ static template = () => null;
28
+
29
+ #bound = false;
30
+ #threadEl = null;
31
+ #canvasEl = null;
32
+ #inspectorEl = null;
33
+
34
+ connected() {
35
+ // Forward events from children — they bubble, so just re-dispatch isn't needed.
36
+ // Events already bubble from thread/canvas through this host.
37
+ }
38
+
39
+ render() {
40
+ if (this.#bound) return;
41
+ this.#bound = true;
42
+
43
+ this.#threadEl = document.createElement('chat-thread-ui');
44
+ this.#canvasEl = document.createElement('canvas-ui');
45
+
46
+ this.appendChild(this.#threadEl);
47
+ this.appendChild(this.#canvasEl);
48
+
49
+ if (this.inspector) {
50
+ this.#inspectorEl = document.createElement('inspector-ui');
51
+ this.appendChild(this.#inspectorEl);
52
+ }
53
+ }
54
+
55
+ // ── Public API ──
56
+
57
+ /**
58
+ * Append a chat message. Delegates to thread.
59
+ * @param {{ role: string, content: string, avatar?: string }} msg
60
+ */
61
+ appendMessage(msg) {
62
+ this.#threadEl?.appendMessage(msg);
63
+ }
64
+
65
+ /**
66
+ * Append chain-of-thought. Delegates to thread.
67
+ * @param {{ text: string }} msg
68
+ */
69
+ appendCoT(msg) {
70
+ this.#threadEl?.appendCoT(msg);
71
+ }
72
+
73
+ /**
74
+ * Push an artifact to the canvas. Auto-switches to split mode if in chat mode.
75
+ * @param {object[]} messages — A2UI messages
76
+ */
77
+ pushArtifact(messages) {
78
+ if (this.mode === 'chat') {
79
+ this.mode = 'split';
80
+ }
81
+ this.#canvasEl?.processAll(messages);
82
+ }
83
+
84
+ /**
85
+ * Set suggestion buttons. Delegates to thread.
86
+ * @param {{ label: string, prompt: string }[]} items
87
+ */
88
+ setSuggestions(items) {
89
+ this.#threadEl?.setSuggestions(items);
90
+ }
91
+
92
+ /** Append a result message with action buttons. Delegates to thread. */
93
+ appendResultMessage(opts) { this.#threadEl?.appendResultMessage(opts); }
94
+
95
+ /** Show save-pattern bar. Delegates to thread. */
96
+ showSavePatternBar(opts) { this.#threadEl?.showSavePatternBar(opts); }
97
+
98
+ /** Show feedback widget. Delegates to thread. */
99
+ showFeedbackWidget(opts) { this.#threadEl?.showFeedbackWidget(opts); }
100
+
101
+ /** Show typing indicator. Delegates to thread. */
102
+ showTyping() { this.#threadEl?.showTyping(); }
103
+
104
+ /** Hide typing indicator. Delegates to thread. */
105
+ hideTyping() { this.#threadEl?.hideTyping(); }
106
+
107
+ /** Append an error message. Delegates to thread. */
108
+ appendError(content) { this.#threadEl?.appendError(content); }
109
+
110
+ /** Start a pipeline status indicator. Delegates to thread. */
111
+ startPipelineStatus() { return this.#threadEl?.startPipelineStatus(); }
112
+
113
+ /** Update the active pipeline status. Delegates to thread. */
114
+ updatePipelineStatus(opts) { this.#threadEl?.updatePipelineStatus(opts); }
115
+
116
+ /** Mark the active pipeline status as complete. Delegates to thread. */
117
+ completePipelineStatus() { this.#threadEl?.completePipelineStatus(); }
118
+
119
+ /** Reset both thread and canvas. */
120
+ reset() {
121
+ this.#threadEl?.clear();
122
+ this.#canvasEl?.reset();
123
+ this.mode = 'chat';
124
+ }
125
+
126
+ /** Access the thread element. */
127
+ get thread() { return this.#threadEl; }
128
+
129
+ /** Access the canvas element. */
130
+ get canvas() { return this.#canvasEl; }
131
+
132
+ /** Access the inspector element (null if inspector not enabled). */
133
+ get inspect() { return this.#inspectorEl; }
134
+ }
135
+
136
+ customElements.define('gen-root', GenRoot);
@@ -0,0 +1,43 @@
1
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
+ name: GenRoot
3
+ tag: gen-root
4
+ component: GenRoot
5
+ category: layout
6
+ version: 1
7
+ description: |
8
+ Composition shell for chat + canvas generative UI. Manages layout modes
9
+ (chat-only / split / canvas-only) and delegates a unified API across
10
+ child chat-ui, canvas-ui, and inspector-ui elements.
11
+
12
+ props:
13
+ mode:
14
+ type: string
15
+ default: chat
16
+ enum: [chat, split, canvas]
17
+ reflect: true
18
+ description: Layout mode — chat-only, 50/50 split, or canvas-only.
19
+
20
+ inspector:
21
+ type: boolean
22
+ default: false
23
+ reflect: true
24
+ description: Show the inspector pane (for debugging generated A2UI).
25
+
26
+ events: {}
27
+
28
+ slots:
29
+ default:
30
+ description: Author supplies chat-ui, canvas-ui, and optional inspector-ui children.
31
+
32
+ states:
33
+ - name: idle
34
+ description: Default mode=chat.
35
+
36
+ traits: []
37
+
38
+ a2ui:
39
+ rules:
40
+ - gen-root is an integration shell. Prefer admin-shell for admin UIs; use gen-root only for chat+canvas tooling.
41
+
42
+ keywords: [gen-ui, generative-ui, chat-canvas, agent-shell]
43
+ related: [AppShell, Chat]
@@ -0,0 +1,2 @@
1
+ export { GenRoot } from './gen-root/gen-root.js';
2
+ export { A2UIRoot } from './a2ui-root/a2ui-root.js';