@ggui-ai/iframe-runtime 0.2.0-alpha.3 → 0.3.0-rc.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/dist/channel-transport.d.ts +20 -30
- package/dist/channel-transport.js +24 -24
- package/dist/channels/data.d.ts +5 -20
- package/dist/channels/data.js +4 -52
- package/dist/channels/index.d.ts +0 -1
- package/dist/channels/index.js +0 -1
- package/dist/channels/props-update.d.ts +9 -9
- package/dist/channels/props-update.js +9 -9
- package/dist/channels/render-frame.d.ts +5 -5
- package/dist/channels/render-frame.js +5 -5
- package/dist/compiled-validators.d.ts +2 -2
- package/dist/compiled-validators.js +1 -1
- package/dist/context-observer.d.ts +4 -4
- package/dist/context-observer.js +3 -3
- package/dist/events-polling.d.ts +7 -7
- package/dist/events-polling.js +5 -5
- package/dist/globals.d.ts +1 -1
- package/dist/host-context-emitter.d.ts +4 -4
- package/dist/host-context-emitter.js +9 -9
- package/dist/iframe-runtime.js +94 -76
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +29 -6
- package/dist/mcp-app-iframe-host.d.ts +8 -8
- package/dist/mcp-app-iframe-host.js +4 -4
- package/dist/meta-parse.d.ts +3 -4
- package/dist/meta-parse.js +17 -44
- package/dist/observability.d.ts +14 -36
- package/dist/observability.js +2 -1
- package/dist/protocol-error.d.ts +38 -48
- package/dist/protocol-error.js +5 -23
- package/dist/provisional-renderer.js +3 -3
- package/dist/react-renderer.d.ts +16 -6
- package/dist/react-renderer.js +22 -40
- package/dist/registry-subscribe.d.ts +7 -7
- package/dist/registry-subscribe.js +28 -14
- package/dist/render-item.d.ts +22 -15
- package/dist/render-item.js +7 -14
- package/dist/runtime.d.ts +79 -105
- package/dist/runtime.js +219 -269
- package/dist/status-dom.d.ts +12 -12
- package/dist/status-dom.js +11 -11
- package/dist/system-cards/NoCredentialsCard.d.ts +1 -1
- package/dist/system-cards/NoCredentialsCard.js +1 -1
- package/dist/system-cards/ProtocolProbeCard.d.ts +13 -17
- package/dist/system-cards/ProtocolProbeCard.js +21 -25
- package/dist/system-cards/index.d.ts +5 -5
- package/dist/system-cards/index.js +5 -5
- package/dist/types.d.ts +29 -34
- package/dist/validation.d.ts +4 -5
- package/dist/validation.js +5 -6
- package/dist/wire-config.d.ts +43 -106
- package/dist/wire-config.js +29 -195
- package/package.json +12 -11
- package/dist/channels/feedback.d.ts +0 -14
- package/dist/channels/feedback.js +0 -19
package/dist/status-dom.d.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* - `initializing` — legacy alias for `idle`.
|
|
27
27
|
* - `connecting` — ui/initialize fired or WS handshake in flight.
|
|
28
28
|
* - `connected` — first ack landed + every subsequent successful
|
|
29
|
-
*
|
|
29
|
+
* render.
|
|
30
30
|
* - `reconnecting` — WS dropped; reconnect ladder running.
|
|
31
31
|
* - `disconnected` — terminal close + ladder exhausted.
|
|
32
32
|
* - `upgrade-required` — version handshake failed.
|
|
@@ -41,21 +41,21 @@ export type StatusKind = 'idle' | 'initializing' | 'connecting' | 'connected' |
|
|
|
41
41
|
* Refs handed back from {@link ensureStatusDom}. `status` is a detached
|
|
42
42
|
* element kept for backward compatibility with channel handlers that
|
|
43
43
|
* still pass `refs.status` through; it is NEVER appended to the
|
|
44
|
-
* document, so production iframes carry no diagnostic banner.
|
|
45
|
-
* is the React mount target — appended to `document.body`
|
|
46
|
-
* wiring has a container.
|
|
44
|
+
* document, so production iframes carry no diagnostic banner.
|
|
45
|
+
* `renderRoot` is the React mount target — appended to `document.body`
|
|
46
|
+
* so renderer wiring has a container.
|
|
47
47
|
*/
|
|
48
48
|
export interface StatusRefs {
|
|
49
49
|
readonly status: HTMLElement;
|
|
50
|
-
readonly
|
|
50
|
+
readonly renderRoot: HTMLElement;
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* Build the React mount target. Reuses pre-existing
|
|
54
|
-
* if
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
53
|
+
* Build the React mount target. Reuses a pre-existing
|
|
54
|
+
* `[data-ggui-session-root]` if one was already written; else creates a
|
|
55
|
+
* fresh `<ul data-ggui-session-root>` and appends it to `<body>`. The
|
|
56
|
+
* companion `status` element is created detached and never appended —
|
|
57
|
+
* consumers that still pass it through `StatusRefs` see no visible
|
|
58
|
+
* effect.
|
|
59
59
|
*
|
|
60
60
|
* The `<ul>` element name is preserved (legacy from the stack-of-N
|
|
61
61
|
* placeholder render path) but only ever holds a single React mount
|
|
@@ -72,6 +72,6 @@ export declare function setStatus(refs: StatusRefs, text: string, state: StatusK
|
|
|
72
72
|
* Log the "connected" transition. Post-stack-removal the iframe always
|
|
73
73
|
* holds exactly one item; the message stays bare ("Connected.") since
|
|
74
74
|
* there's no count to surface. Consumers (devtools, e2e specs
|
|
75
|
-
* intercepting `console.log`) get a stable string on every
|
|
75
|
+
* intercepting `console.log`) get a stable string on every render.
|
|
76
76
|
*/
|
|
77
77
|
export declare function setConnectedStatus(refs: StatusRefs): void;
|
package/dist/status-dom.js
CHANGED
|
@@ -18,23 +18,23 @@
|
|
|
18
18
|
* shape.
|
|
19
19
|
*/
|
|
20
20
|
/**
|
|
21
|
-
* Build the React mount target. Reuses pre-existing
|
|
22
|
-
* if
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Build the React mount target. Reuses a pre-existing
|
|
22
|
+
* `[data-ggui-session-root]` if one was already written; else creates a
|
|
23
|
+
* fresh `<ul data-ggui-session-root>` and appends it to `<body>`. The
|
|
24
|
+
* companion `status` element is created detached and never appended —
|
|
25
|
+
* consumers that still pass it through `StatusRefs` see no visible
|
|
26
|
+
* effect.
|
|
27
27
|
*
|
|
28
28
|
* The `<ul>` element name is preserved (legacy from the stack-of-N
|
|
29
29
|
* placeholder render path) but only ever holds a single React mount
|
|
30
30
|
* subtree post-stack-removal.
|
|
31
31
|
*/
|
|
32
32
|
export function ensureStatusDom(doc) {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
33
|
+
const existingRoot = doc.querySelector('[data-ggui-session-root]');
|
|
34
|
+
const renderRoot = existingRoot ??
|
|
35
35
|
(() => {
|
|
36
36
|
const el = doc.createElement('ul');
|
|
37
|
-
el.setAttribute('data-ggui-
|
|
37
|
+
el.setAttribute('data-ggui-session-root', '');
|
|
38
38
|
doc.body.appendChild(el);
|
|
39
39
|
return el;
|
|
40
40
|
})();
|
|
@@ -44,7 +44,7 @@ export function ensureStatusDom(doc) {
|
|
|
44
44
|
const status = doc.createElement('div');
|
|
45
45
|
status.setAttribute('data-ggui-status', 'idle');
|
|
46
46
|
status.setAttribute('aria-hidden', 'true');
|
|
47
|
-
return { status,
|
|
47
|
+
return { status, renderRoot };
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Log a status transition. The element is mutated for backward compat
|
|
@@ -61,7 +61,7 @@ export function setStatus(refs, text, state) {
|
|
|
61
61
|
* Log the "connected" transition. Post-stack-removal the iframe always
|
|
62
62
|
* holds exactly one item; the message stays bare ("Connected.") since
|
|
63
63
|
* there's no count to surface. Consumers (devtools, e2e specs
|
|
64
|
-
* intercepting `console.log`) get a stable string on every
|
|
64
|
+
* intercepting `console.log`) get a stable string on every render.
|
|
65
65
|
*/
|
|
66
66
|
export function setConnectedStatus(refs) {
|
|
67
67
|
setStatus(refs, 'Connected.', 'connected');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* No-credentials system card.
|
|
3
3
|
*
|
|
4
|
-
* Rendered when the server processed a `ggui_render` for a
|
|
4
|
+
* Rendered when the server processed a `ggui_render` for a render whose
|
|
5
5
|
* LLM credentials are missing or unresolvable. The user needs to open
|
|
6
6
|
* the server's `/settings` page in a real browser tab to paste an API
|
|
7
7
|
* key.
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
/**
|
|
3
3
|
* No-credentials system card.
|
|
4
4
|
*
|
|
5
|
-
* Rendered when the server processed a `ggui_render` for a
|
|
5
|
+
* Rendered when the server processed a `ggui_render` for a render whose
|
|
6
6
|
* LLM credentials are missing or unresolvable. The user needs to open
|
|
7
7
|
* the server's `/settings` page in a real browser tab to paste an API
|
|
8
8
|
* key.
|
|
@@ -4,24 +4,20 @@
|
|
|
4
4
|
* Diagnostic + regression fixture exercising every gesture surface
|
|
5
5
|
* the iframe runtime routes:
|
|
6
6
|
*
|
|
7
|
-
* 1. **
|
|
8
|
-
* `ui/update-model-context` (silent context) +
|
|
9
|
-
* (consent prompt). Fires for
|
|
10
|
-
* `actionSpec[name]
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* for same-server, app-visible target tools. Probes against
|
|
16
|
-
* `ggui_runtime_submit_action` itself (the only universally-app-visible
|
|
17
|
-
* tool the iframe can be sure exists).
|
|
18
|
-
* 3. **Native-idiom: anchor click** — `ui/open-link` paired with
|
|
7
|
+
* 1. **Submit-action bridge** — `tools/call ggui_runtime_submit_action`
|
|
8
|
+
* (audit) + `ui/update-model-context` (silent context) +
|
|
9
|
+
* `ui/message` (consent prompt). Fires for every
|
|
10
|
+
* `actionSpec[name]` dispatch — the gesture queues on the
|
|
11
|
+
* render's consume pipe for the agent (`nextStep` is an advisory
|
|
12
|
+
* hint, never a client-side route). Empirical-first reproduction
|
|
13
|
+
* of the production `dispatchSubmitAction` path.
|
|
14
|
+
* 2. **Native-idiom: anchor click** — `ui/open-link` paired with
|
|
19
15
|
* `kind: 'openLink'` audit. Triggered by the runtime's
|
|
20
16
|
* capture-phase `<a href>` interceptor (cross-origin or
|
|
21
17
|
* `target="_blank"`). The probe row simulates the postMessage
|
|
22
18
|
* directly so the operator sees the envelope without needing to
|
|
23
19
|
* click an anchor.
|
|
24
|
-
*
|
|
20
|
+
* 3. **Native-idiom: fullscreen** — `ui/request-display-mode` +
|
|
25
21
|
* `kind: 'requestDisplayMode'` audit. Triggered by the runtime's
|
|
26
22
|
* `Element.prototype.requestFullscreen` /
|
|
27
23
|
* `Document.prototype.exitFullscreen` overrides. The probe row
|
|
@@ -35,8 +31,8 @@
|
|
|
35
31
|
* host-issued request seen while the card is mounted.
|
|
36
32
|
*
|
|
37
33
|
* Why this lives outside the wire-context: system cards (`kind:
|
|
38
|
-
* 'mcp-apps-probe'`, `'no-credentials'`, …) mount in
|
|
39
|
-
*
|
|
34
|
+
* 'mcp-apps-probe'`, `'no-credentials'`, …) mount in render-item's
|
|
35
|
+
* `kind === 'system'` branch, which does NOT install
|
|
40
36
|
* `<GguiWireProvider>` — they exist precisely to surface protocol
|
|
41
37
|
* state when the wire-context might not be live (auth missing,
|
|
42
38
|
* compile failed, etc.). The probe card mirrors the postMessage
|
|
@@ -50,12 +46,12 @@
|
|
|
50
46
|
* reject `tools/call` from views for tools without `'app'` in
|
|
51
47
|
* visibility — claude.ai silently dropped the call. The original
|
|
52
48
|
* probe diagnosed the gap; the routing simplification work landed
|
|
53
|
-
*
|
|
49
|
+
* the submit-action bridge + native idioms in response.
|
|
54
50
|
*/
|
|
55
51
|
import * as React from 'react';
|
|
56
52
|
export interface ProtocolProbeCardProps {
|
|
57
53
|
/**
|
|
58
|
-
* Optional: the original prompt that triggered the probe
|
|
54
|
+
* Optional: the original prompt that triggered the probe render.
|
|
59
55
|
* Surfaced as a footnote so the card matches the framing of other
|
|
60
56
|
* system cards (`NoCredentialsCard`).
|
|
61
57
|
*/
|
|
@@ -5,24 +5,20 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
* Diagnostic + regression fixture exercising every gesture surface
|
|
6
6
|
* the iframe runtime routes:
|
|
7
7
|
*
|
|
8
|
-
* 1. **
|
|
9
|
-
* `ui/update-model-context` (silent context) +
|
|
10
|
-
* (consent prompt). Fires for
|
|
11
|
-
* `actionSpec[name]
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* for same-server, app-visible target tools. Probes against
|
|
17
|
-
* `ggui_runtime_submit_action` itself (the only universally-app-visible
|
|
18
|
-
* tool the iframe can be sure exists).
|
|
19
|
-
* 3. **Native-idiom: anchor click** — `ui/open-link` paired with
|
|
8
|
+
* 1. **Submit-action bridge** — `tools/call ggui_runtime_submit_action`
|
|
9
|
+
* (audit) + `ui/update-model-context` (silent context) +
|
|
10
|
+
* `ui/message` (consent prompt). Fires for every
|
|
11
|
+
* `actionSpec[name]` dispatch — the gesture queues on the
|
|
12
|
+
* render's consume pipe for the agent (`nextStep` is an advisory
|
|
13
|
+
* hint, never a client-side route). Empirical-first reproduction
|
|
14
|
+
* of the production `dispatchSubmitAction` path.
|
|
15
|
+
* 2. **Native-idiom: anchor click** — `ui/open-link` paired with
|
|
20
16
|
* `kind: 'openLink'` audit. Triggered by the runtime's
|
|
21
17
|
* capture-phase `<a href>` interceptor (cross-origin or
|
|
22
18
|
* `target="_blank"`). The probe row simulates the postMessage
|
|
23
19
|
* directly so the operator sees the envelope without needing to
|
|
24
20
|
* click an anchor.
|
|
25
|
-
*
|
|
21
|
+
* 3. **Native-idiom: fullscreen** — `ui/request-display-mode` +
|
|
26
22
|
* `kind: 'requestDisplayMode'` audit. Triggered by the runtime's
|
|
27
23
|
* `Element.prototype.requestFullscreen` /
|
|
28
24
|
* `Document.prototype.exitFullscreen` overrides. The probe row
|
|
@@ -36,8 +32,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
36
32
|
* host-issued request seen while the card is mounted.
|
|
37
33
|
*
|
|
38
34
|
* Why this lives outside the wire-context: system cards (`kind:
|
|
39
|
-
* 'mcp-apps-probe'`, `'no-credentials'`, …) mount in
|
|
40
|
-
*
|
|
35
|
+
* 'mcp-apps-probe'`, `'no-credentials'`, …) mount in render-item's
|
|
36
|
+
* `kind === 'system'` branch, which does NOT install
|
|
41
37
|
* `<GguiWireProvider>` — they exist precisely to surface protocol
|
|
42
38
|
* state when the wire-context might not be live (auth missing,
|
|
43
39
|
* compile failed, etc.). The probe card mirrors the postMessage
|
|
@@ -51,7 +47,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
51
47
|
* reject `tools/call` from views for tools without `'app'` in
|
|
52
48
|
* visibility — claude.ai silently dropped the call. The original
|
|
53
49
|
* probe diagnosed the gap; the routing simplification work landed
|
|
54
|
-
*
|
|
50
|
+
* the submit-action bridge + native idioms in response.
|
|
55
51
|
*/
|
|
56
52
|
import * as React from 'react';
|
|
57
53
|
import { Card, Stack, Heading, Text, Button, Badge, } from '@ggui-ai/design/primitives';
|
|
@@ -190,7 +186,7 @@ function defaultParams(method) {
|
|
|
190
186
|
case 'ui/request-display-mode':
|
|
191
187
|
return { mode: 'fullscreen' };
|
|
192
188
|
case 'tools/call':
|
|
193
|
-
// Mirror `runtime.ts::emitAudit` + `runtime.ts::
|
|
189
|
+
// Mirror `runtime.ts::emitAudit` + `runtime.ts::dispatchSubmitAction`
|
|
194
190
|
// so this probe empirically validates the canonical
|
|
195
191
|
// `GguiUserActionInput` envelope (SPEC §4.6, see
|
|
196
192
|
// `@ggui-ai/protocol/integrations/mcp-apps`). `ggui_runtime_submit_action`
|
|
@@ -200,9 +196,9 @@ function defaultParams(method) {
|
|
|
200
196
|
// a tool result; the host forwards that result to this iframe
|
|
201
197
|
// via the JSON-RPC response matching our outbound id.
|
|
202
198
|
//
|
|
203
|
-
// The probe uses `kind: 'dispatch'` so the chained
|
|
204
|
-
//
|
|
205
|
-
// semantically matches a real
|
|
199
|
+
// The probe uses `kind: 'dispatch'` so the chained 3-message
|
|
200
|
+
// follow-up (`ui/update-model-context` + `ui/message`)
|
|
201
|
+
// semantically matches a real submit-action click.
|
|
206
202
|
return {
|
|
207
203
|
name: 'ggui_runtime_submit_action',
|
|
208
204
|
arguments: {
|
|
@@ -211,7 +207,7 @@ function defaultParams(method) {
|
|
|
211
207
|
intent: 'probe-click',
|
|
212
208
|
data: { note: 'hello from the protocol probe' },
|
|
213
209
|
},
|
|
214
|
-
|
|
210
|
+
sessionId: 'probe-render',
|
|
215
211
|
appId: 'probe-app',
|
|
216
212
|
actionId: '00000000', // overwritten in onClick with real FNV-1a
|
|
217
213
|
firedAt: new Date().toISOString(),
|
|
@@ -222,7 +218,7 @@ function defaultParams(method) {
|
|
|
222
218
|
/**
|
|
223
219
|
* Compute a short deterministic action-id from an action payload.
|
|
224
220
|
* FNV-1a 32-bit, 8 hex chars — not cryptographically strong, just
|
|
225
|
-
* collision-resistant enough for in-flight
|
|
221
|
+
* collision-resistant enough for in-flight submit-action correlation.
|
|
226
222
|
*
|
|
227
223
|
* Why hash (vs. random UUID): the id reproduces from
|
|
228
224
|
* `{intent, data, firedAt}` so both the silent context-update AND
|
|
@@ -312,8 +308,8 @@ function ProbeButtonRow({ method, description, call, }) {
|
|
|
312
308
|
const args = params
|
|
313
309
|
.arguments ?? {};
|
|
314
310
|
// New gesture-envelope shape (SPEC §4.6): `{kind, payload,
|
|
315
|
-
//
|
|
316
|
-
// `payload` carries `{intent, data}`.
|
|
311
|
+
// sessionId, appId, actionId, firedAt}`. For dispatch
|
|
312
|
+
// gestures the `payload` carries `{intent, data}`.
|
|
317
313
|
const payload = args['payload'] ?? {};
|
|
318
314
|
const intent = String(payload['intent'] ?? '?');
|
|
319
315
|
const data = payload['data'];
|
|
@@ -420,7 +416,7 @@ export function ProtocolProbeCard({ intent, }) {
|
|
|
420
416
|
}, children: [_jsx(Heading, { level: 3, children: "MCP Apps protocol probe" }), _jsx(Badge, { variant: "info", children: "diagnostic" })] }), _jsxs(Text, { style: {
|
|
421
417
|
color: 'var(--ggui-color-onSurfaceVariant, #52525b)',
|
|
422
418
|
lineHeight: '1.55',
|
|
423
|
-
}, children: ["One button per primary host effect emitted by the iframe runtime's gesture surfaces (
|
|
419
|
+
}, children: ["One button per primary host effect emitted by the iframe runtime's gesture surfaces (submit-action bridge / native- idiom interceptors). Click each to verify which methods this host honors. The", _jsx("code", { children: "tools/call" }), " row chains the full submit-action bridge (audit + context + consent), reproducing the production ", _jsx("code", { children: "dispatchSubmitAction" }), " envelope shape verbatim. The receive log below captures every notification the host emits while this card is mounted."] })] }), _jsxs(Stack, { gap: "md", children: [_jsx(ProbeButtonRow, { method: "ui/message", description: "Submit-action bridge step 3 \u2014 consent-gated user authorization. Host pre-fills + waits for user confirm before the LLM acts on the paired pending-action context.", call: call }), _jsx(ProbeButtonRow, { method: "ui/update-model-context", description: "Submit-action bridge step 2 \u2014 silent structured `[ggui:pending-action]` context drop. LLM honors on next turn. No immediate UI.", call: call }), _jsx(ProbeButtonRow, { method: "ui/open-link", description: "Native-idiom anchor click interceptor primary effect. Opens ggui.ai in the host's browser / new tab. Real iframe code triggers via `<a href target='_blank'>` or cross-origin href.", call: call }), _jsx(ProbeButtonRow, { method: "ui/request-display-mode", description: "Native-idiom fullscreen interceptor primary effect. Request fullscreen \u2014 real iframe code calls `el.requestFullscreen()`; the runtime overrides the prototype to route through here.", call: call }), _jsx(ProbeButtonRow, { method: "tools/call", description: "Full submit-action bridge: `tools/call ggui_runtime_submit_action` (audit, kind:'dispatch') + `ui/update-model-context` + `ui/message`. Spec \u00A7401 requires `_meta.ui.visibility:['app']` on the receiving tool.", call: call })] }), _jsxs(Stack, { gap: "sm", children: [_jsxs("div", { style: {
|
|
424
420
|
display: 'flex',
|
|
425
421
|
alignItems: 'baseline',
|
|
426
422
|
justifyContent: 'space-between',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System-card registry.
|
|
3
3
|
*
|
|
4
|
-
* Central mapping from `
|
|
4
|
+
* Central mapping from `SystemGguiSession.kind` (a stable wire string)
|
|
5
5
|
* to a real React component bundled inside the iframe-runtime. The
|
|
6
6
|
* runtime's self-contained boot path looks up the kind here when it
|
|
7
7
|
* sees a render with `type: 'system'`. Unknown kinds fall through
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 1. Author `MyNewCard.tsx` in this directory.
|
|
14
14
|
* 2. Add an entry to {@link SYSTEM_CARD_REGISTRY} below.
|
|
15
15
|
* 3. (Optional) Add the new kind string to
|
|
16
|
-
* `
|
|
16
|
+
* `SystemGguiSessionKind` in `@ggui-ai/protocol` for IDE autocomplete.
|
|
17
17
|
*/
|
|
18
18
|
import * as React from 'react';
|
|
19
19
|
import { NoCredentialsCard, type NoCredentialsCardProps } from './NoCredentialsCard.js';
|
|
@@ -28,7 +28,7 @@ import { ProtocolProbeCard, type ProtocolProbeCardProps } from './ProtocolProbeC
|
|
|
28
28
|
export type SystemCardComponent = React.ComponentType<Record<string, unknown>>;
|
|
29
29
|
/**
|
|
30
30
|
* Registered system-card kinds. Keep keys aligned with
|
|
31
|
-
* `
|
|
31
|
+
* `SystemGguiSessionKind` in `@ggui-ai/protocol` so wire + bundle stay
|
|
32
32
|
* in sync. New kinds added without a registry entry render as
|
|
33
33
|
* {@link UnknownSystemCard}.
|
|
34
34
|
*/
|
|
@@ -39,8 +39,8 @@ export declare const SYSTEM_CARD_REGISTRY: Record<string, SystemCardComponent>;
|
|
|
39
39
|
*/
|
|
40
40
|
export declare function renderSystemCard(kind: string, props: Record<string, unknown>): React.ReactElement;
|
|
41
41
|
/**
|
|
42
|
-
* Top-level mount component the runtime renders for system
|
|
43
|
-
*
|
|
42
|
+
* Top-level mount component the runtime renders for system
|
|
43
|
+
* renders. Wraps the resolved card in a {@link ThemeProvider} so design
|
|
44
44
|
* tokens (`var(--ggui-*)`) resolve at `:root` even though the host's
|
|
45
45
|
* shell HTML doesn't pre-stamp them. Idempotent across remounts —
|
|
46
46
|
* shares the `ggui-theme-vars` style id with the rest of the design
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System-card registry.
|
|
3
3
|
*
|
|
4
|
-
* Central mapping from `
|
|
4
|
+
* Central mapping from `SystemGguiSession.kind` (a stable wire string)
|
|
5
5
|
* to a real React component bundled inside the iframe-runtime. The
|
|
6
6
|
* runtime's self-contained boot path looks up the kind here when it
|
|
7
7
|
* sees a render with `type: 'system'`. Unknown kinds fall through
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 1. Author `MyNewCard.tsx` in this directory.
|
|
14
14
|
* 2. Add an entry to {@link SYSTEM_CARD_REGISTRY} below.
|
|
15
15
|
* 3. (Optional) Add the new kind string to
|
|
16
|
-
* `
|
|
16
|
+
* `SystemGguiSessionKind` in `@ggui-ai/protocol` for IDE autocomplete.
|
|
17
17
|
*/
|
|
18
18
|
import * as React from 'react';
|
|
19
19
|
import { ThemeProvider, lightTheme, darkTheme } from '@ggui-ai/design/themes';
|
|
@@ -64,7 +64,7 @@ function UnknownSystemCard({ kind, props, }) {
|
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Registered system-card kinds. Keep keys aligned with
|
|
67
|
-
* `
|
|
67
|
+
* `SystemGguiSessionKind` in `@ggui-ai/protocol` so wire + bundle stay
|
|
68
68
|
* in sync. New kinds added without a registry entry render as
|
|
69
69
|
* {@link UnknownSystemCard}.
|
|
70
70
|
*/
|
|
@@ -96,8 +96,8 @@ export function renderSystemCard(kind, props) {
|
|
|
96
96
|
return React.createElement(UnknownSystemCard, { kind, props });
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
* Top-level mount component the runtime renders for system
|
|
100
|
-
*
|
|
99
|
+
* Top-level mount component the runtime renders for system
|
|
100
|
+
* renders. Wraps the resolved card in a {@link ThemeProvider} so design
|
|
101
101
|
* tokens (`var(--ggui-*)`) resolve at `:root` even though the host's
|
|
102
102
|
* shell HTML doesn't pre-stamp them. Idempotent across remounts —
|
|
103
103
|
* shares the `ggui-theme-vars` style id with the rest of the design
|
package/dist/types.d.ts
CHANGED
|
@@ -15,42 +15,33 @@
|
|
|
15
15
|
* declared the manager's constructor bag has been retired.
|
|
16
16
|
*/
|
|
17
17
|
import type { McpAppAiGguiRenderMeta } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
18
|
-
import type { HostContextProjection,
|
|
19
|
-
/**
|
|
20
|
-
* Post-Phase-B alias kept for ergonomic call sites — the wire-side
|
|
21
|
-
* `McpAppAiGguiRenderMeta` is the single source of truth, and the
|
|
22
|
-
* "validated" qualifier is a no-op now (no nested-optional-session
|
|
23
|
-
* narrowing left after the slice merge). Future callers SHOULD prefer
|
|
24
|
-
* `McpAppAiGguiRenderMeta` directly; the alias persists so the rename
|
|
25
|
-
* sweep can land incrementally without churn at every call site.
|
|
26
|
-
*/
|
|
27
|
-
export type ValidatedMcpAppAiGguiMeta = McpAppAiGguiRenderMeta;
|
|
18
|
+
import type { HostContextProjection, ComponentGguiSession, SystemGguiSession } from '@ggui-ai/protocol';
|
|
28
19
|
/**
|
|
29
20
|
* The four server-assigned ledger fields on every wire-delivered
|
|
30
|
-
* {@link
|
|
21
|
+
* {@link GguiSession}. They're stamped by the server's per-render event
|
|
31
22
|
* ledger — NOT derivable from the inline `__GGUI_META__` bootstrap.
|
|
32
23
|
*/
|
|
33
|
-
type
|
|
24
|
+
type GguiSessionLedgerFields = 'eventSequence' | 'createdAt' | 'lastActivityAt' | 'expiresAt';
|
|
34
25
|
/**
|
|
35
26
|
* The mount surface's INPUT contract — what `mountRender` / `applyRender`
|
|
36
|
-
* accept. It is a {@link
|
|
37
|
-
* fields ({@link
|
|
27
|
+
* accept. It is a {@link GguiSession} minus the four server-assigned ledger
|
|
28
|
+
* fields ({@link GguiSessionLedgerFields}), so the runtime can mount the
|
|
38
29
|
* compiled component (or system card) carried inline by the resource
|
|
39
|
-
* shell BEFORE the authoritative wire `
|
|
30
|
+
* shell BEFORE the authoritative wire `GguiSession` arrives over the WS.
|
|
40
31
|
*
|
|
41
|
-
* A full `
|
|
32
|
+
* A full `GguiSession` is assignable to `GguiSessionSeedInput` (it carries every
|
|
42
33
|
* field plus the ledger), so the WS-ack reconcile path passes a real
|
|
43
|
-
* `
|
|
44
|
-
* built by `
|
|
34
|
+
* `GguiSession` here unchanged; the inline-seed path passes the projection
|
|
35
|
+
* built by `buildGguiSessionSeedInput`. We do NOT fabricate the ledger fields
|
|
45
36
|
* (Strict-Typing-First / no-type-laundering) — the first ack replaces
|
|
46
|
-
* the seed with the authoritative `
|
|
37
|
+
* the seed with the authoritative `GguiSession`.
|
|
47
38
|
*
|
|
48
|
-
* Carries the SAME contract-spec fields a full `
|
|
39
|
+
* Carries the SAME contract-spec fields a full `ComponentGguiSession` does
|
|
49
40
|
* (`propsSpec` / `streamSpec` / `actionSpec`), as `undefined` on a
|
|
50
41
|
* seed — so the channel handlers that read those after the
|
|
51
42
|
* `type !== 'mcpApps' && type !== 'system'` narrowing stay type-clean.
|
|
52
43
|
*/
|
|
53
|
-
export type
|
|
44
|
+
export type GguiSessionSeedInput = Omit<ComponentGguiSession, GguiSessionLedgerFields> | Omit<SystemGguiSession, GguiSessionLedgerFields>;
|
|
54
45
|
/**
|
|
55
46
|
* Why a slice-meta parse can fail. Closed union — every value is a
|
|
56
47
|
* canonical reason the renderer surfaces to the host via postMessage.
|
|
@@ -60,13 +51,16 @@ export type RenderSeedInput = Omit<ComponentRender, RenderLedgerFields> | Omit<S
|
|
|
60
51
|
* `CSP_VIOLATION`, etc) live on the broader `BootstrapFailureReason`
|
|
61
52
|
* union in `protocol-error.ts`. The four parse-time outcomes:
|
|
62
53
|
*
|
|
63
|
-
* - `MISSING_TOOL_OUTPUT` —
|
|
64
|
-
* `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* `BOOTSTRAP_META_MISSING`. (Name retained pre-R4 for the
|
|
68
|
-
* observability + host-postMessage protocol; cosmetic rename is
|
|
54
|
+
* - `MISSING_TOOL_OUTPUT` — the tool-result notification's `params`
|
|
55
|
+
* was not an object (no `CallToolResult` to read). (Name predates
|
|
56
|
+
* the spec-canonical top-level `_meta` reading; retained for the
|
|
57
|
+
* observability + host-postMessage protocol — cosmetic rename is
|
|
69
58
|
* deferred.)
|
|
59
|
+
* - `MISSING_META_GGUI_BOOTSTRAP` — `params` is an object but
|
|
60
|
+
* `params._meta` is absent or carries no `ai.ggui/render` slice.
|
|
61
|
+
* The on-wire synonym is `BOOTSTRAP_META_MISSING`. (Name retained
|
|
62
|
+
* pre-R4 for the observability + host-postMessage protocol;
|
|
63
|
+
* cosmetic rename is deferred.)
|
|
70
64
|
* - `MALFORMED_BOOTSTRAP` — slice is present but fails business
|
|
71
65
|
* rules (no live mode and no static content, mode discriminators
|
|
72
66
|
* mutually exclusive, structural rejection by the combiner).
|
|
@@ -81,17 +75,18 @@ export type McpAppAiGguiMetaParseFailureReason = 'MISSING_TOOL_OUTPUT' | 'MISSIN
|
|
|
81
75
|
* bundle).
|
|
82
76
|
*
|
|
83
77
|
* The `ok: true` arm carries the validated {@link McpAppAiGguiRenderMeta}
|
|
84
|
-
* slice and optionally a `hostContext: HostContextProjection`.
|
|
85
|
-
*
|
|
86
|
-
* the
|
|
87
|
-
* `
|
|
88
|
-
*
|
|
78
|
+
* slice and optionally a `hostContext: HostContextProjection`. The
|
|
79
|
+
* producer is the boot path in `runtime.ts`, which projects
|
|
80
|
+
* `app.getHostContext()` (the App class's spec-canonical
|
|
81
|
+
* `ui/initialize` capture plus its `hostcontextchanged` listener)
|
|
82
|
+
* into this field so the runtime can:
|
|
83
|
+
* - drive display-mode escalation (MCP Apps inline/fullscreen/pip)
|
|
89
84
|
* - echo to the server (live-channel `host_context_observed` envelope)
|
|
90
85
|
* - feed the agent on next handshake/consume
|
|
91
86
|
*
|
|
92
87
|
* Capture is best-effort: a malformed `HostContext` never blocks the
|
|
93
|
-
* slice parse.
|
|
94
|
-
*
|
|
88
|
+
* slice parse. The envelope extractors themselves (`__GGUI_META__`
|
|
89
|
+
* global, `ui/notifications/tool-result`) never populate it — those
|
|
95
90
|
* envelopes don't carry HostContext.
|
|
96
91
|
*/
|
|
97
92
|
export type McpAppAiGguiMetaParseResult = {
|
package/dist/validation.d.ts
CHANGED
|
@@ -30,9 +30,8 @@ import type { ActionSpec, ActionEnvelope, ContextSpec, JsonObject, PropsSpec, Re
|
|
|
30
30
|
import type { CompiledValidatorSet } from './compiled-validators.js';
|
|
31
31
|
/**
|
|
32
32
|
* Install the precompiled validators loaded from the bootstrap. Called
|
|
33
|
-
* once per boot (
|
|
34
|
-
*
|
|
35
|
-
* session, one active contract.
|
|
33
|
+
* once per boot (by `bootSequence`), after the bootstrap is parsed. A
|
|
34
|
+
* single set per iframe document — one render, one active contract.
|
|
36
35
|
*/
|
|
37
36
|
export declare function setActiveValidatorSet(set: CompiledValidatorSet | undefined): void;
|
|
38
37
|
/**
|
|
@@ -69,8 +68,8 @@ export declare function validateOutboundActionEnvelope(actionSpec: ActionSpec |
|
|
|
69
68
|
*/
|
|
70
69
|
export declare function validateInboundStreamPayload(streamSpec: StreamSpec | undefined, channelName: string, payload: unknown, ctx: RendererValidatorContext): ValidationResult;
|
|
71
70
|
/**
|
|
72
|
-
* Validate an inbound `props_update` payload before patching a
|
|
73
|
-
*
|
|
71
|
+
* Validate an inbound `props_update` payload before patching a
|
|
72
|
+
* render's props. Server already runs `assertPropsContract` on the emit
|
|
74
73
|
* path; this client-side revalidation is defense-in-depth for
|
|
75
74
|
* spec-versioning drift (server snapshot ≠ client cached spec).
|
|
76
75
|
*/
|
package/dist/validation.js
CHANGED
|
@@ -3,16 +3,15 @@ import { isKnownReservedChannel, validateActionEnvelope, validateContextData, va
|
|
|
3
3
|
// Active precompiled-validator set
|
|
4
4
|
// =============================================================================
|
|
5
5
|
/**
|
|
6
|
-
* Boot-installed precompiled validators for the active
|
|
6
|
+
* Boot-installed precompiled validators for the active render's
|
|
7
7
|
* contract. `undefined` until {@link setActiveValidatorSet} runs (and
|
|
8
8
|
* in unit tests, which exercise the in-iframe compilation fallback).
|
|
9
9
|
*/
|
|
10
10
|
let activeValidatorSet;
|
|
11
11
|
/**
|
|
12
12
|
* Install the precompiled validators loaded from the bootstrap. Called
|
|
13
|
-
* once per boot (
|
|
14
|
-
*
|
|
15
|
-
* session, one active contract.
|
|
13
|
+
* once per boot (by `bootSequence`), after the bootstrap is parsed. A
|
|
14
|
+
* single set per iframe document — one render, one active contract.
|
|
16
15
|
*/
|
|
17
16
|
export function setActiveValidatorSet(set) {
|
|
18
17
|
activeValidatorSet = set;
|
|
@@ -86,8 +85,8 @@ export function validateInboundStreamPayload(streamSpec, channelName, payload, c
|
|
|
86
85
|
});
|
|
87
86
|
}
|
|
88
87
|
/**
|
|
89
|
-
* Validate an inbound `props_update` payload before patching a
|
|
90
|
-
*
|
|
88
|
+
* Validate an inbound `props_update` payload before patching a
|
|
89
|
+
* render's props. Server already runs `assertPropsContract` on the emit
|
|
91
90
|
* path; this client-side revalidation is defense-in-depth for
|
|
92
91
|
* spec-versioning drift (server snapshot ≠ client cached spec).
|
|
93
92
|
*/
|