@guuey/mcp-apps-host 0.7.1 → 0.8.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/card-mount.d.ts +2 -2
- package/dist/card-mount.js +2 -2
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/react.d.ts +9 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +18 -2
- package/dist/view-host-protocol.d.ts +51 -3
- package/dist/view-host-protocol.d.ts.map +1 -1
- package/dist/view-host-protocol.js +58 -2
- package/dist/view-host.d.ts +45 -1
- package/dist/view-host.d.ts.map +1 -1
- package/dist/view-host.js +32 -1
- package/package.json +1 -1
- package/src/card-mount.ts +2 -2
- package/src/index.ts +5 -17
- package/src/react.tsx +36 -7
- package/src/view-host-protocol.ts +104 -2
- package/src/view-host.ts +77 -0
- package/dist/ggui-render.d.ts +0 -144
- package/dist/ggui-render.d.ts.map +0 -1
- package/dist/ggui-render.js +0 -108
- package/src/ggui-render.ts +0 -188
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
* SEP-1865 surface itself, someone else's frozen contract. Zero ggui
|
|
29
29
|
* imports, deliberately (guuey#123): this host answers ANY spec-following
|
|
30
30
|
* view. (The ggui vendor arm that used to live beside it in
|
|
31
|
-
* `ggui-render.ts` retired 2026-08-16 — guuey#209;
|
|
32
|
-
* deprecated re-exports
|
|
31
|
+
* `ggui-render.ts` retired 2026-08-16 — guuey#209; the module shipped one
|
|
32
|
+
* minor as deprecated re-exports and was deleted at 0.8.0.)
|
|
33
33
|
*/
|
|
34
34
|
import {
|
|
35
35
|
INITIALIZE_METHOD,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
type McpUiHostCapabilities,
|
|
40
40
|
type McpUiHostContext,
|
|
41
41
|
type McpUiInitializeResult,
|
|
42
|
+
type McpUiResourceCsp,
|
|
42
43
|
} from "@modelcontextprotocol/ext-apps";
|
|
43
44
|
import type { McpToolStructuredContent } from "./action.js";
|
|
44
45
|
import type { McpResourceReadResult } from "./reader.js";
|
|
@@ -398,3 +399,104 @@ export function viewHostReceive(
|
|
|
398
399
|
export function viewHostElapsed(state: ViewHostState): ViewHostState {
|
|
399
400
|
return state.phase === "negotiating" ? { ...state, phase: "no-handshake" } : state;
|
|
400
401
|
}
|
|
402
|
+
|
|
403
|
+
// ─── CSP diagnosis (guuey#235) ────────────────────────────────────────────
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* The origins a view needs the EMBEDDER's page to allow — the spec's own
|
|
407
|
+
* per-resource CSP declaration (`McpUiResourceCsp`: `connectDomains` →
|
|
408
|
+
* `connect-src`, `resourceDomains` → `script-src`/`style-src`/…,
|
|
409
|
+
* `frameDomains` → `frame-src`). This is the honest filter for the CSP
|
|
410
|
+
* tripwire: a `securitypolicyviolation` whose `blockedURI` lands on one of
|
|
411
|
+
* these hosts is a violation ABOUT the view, not about anything else the
|
|
412
|
+
* page loads. Empty/absent → nothing to match, tripwire inert.
|
|
413
|
+
*/
|
|
414
|
+
export type ViewCspOrigins = McpUiResourceCsp;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* What the embedder can act on when its own CSP blocked the view: the
|
|
418
|
+
* URI the browser refused, the directive that refused it, and the entry
|
|
419
|
+
* that would allow it (the blocked URI's origin — the smallest allowance
|
|
420
|
+
* that fixes exactly this). Rides beside `"no-handshake"` — the phase
|
|
421
|
+
* stays honest ("it never negotiated"); this is WHY.
|
|
422
|
+
*/
|
|
423
|
+
export interface ViewCspDiagnosis {
|
|
424
|
+
blockedUri: string;
|
|
425
|
+
violatedDirective: string;
|
|
426
|
+
/** The origin to add under `violatedDirective` — e.g. `https://assets.mcp.example`. */
|
|
427
|
+
suggestedEntry: string;
|
|
428
|
+
/** Operator-facing sentence, ready to label. */
|
|
429
|
+
message: string;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* The slice of a `SecurityPolicyViolationEvent` the tripwire reads —
|
|
434
|
+
* structural, so Node tests hand in plain objects (lib.dom's class is not
|
|
435
|
+
* constructible outside a browser).
|
|
436
|
+
*/
|
|
437
|
+
export interface CspViolationLike {
|
|
438
|
+
blockedURI: string;
|
|
439
|
+
/** e.g. `script-src-elem`, `connect-src`. */
|
|
440
|
+
violatedDirective: string;
|
|
441
|
+
/** The directive as the policy spelled it (`script-src` may govern `script-src-elem`). */
|
|
442
|
+
effectiveDirective?: string;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Every declared origin's HOST, wildcards (`https://*.x`) reduced to their suffix. */
|
|
446
|
+
function declaredHosts(origins: ViewCspOrigins): { host: string; wildcard: boolean }[] {
|
|
447
|
+
const out: { host: string; wildcard: boolean }[] = [];
|
|
448
|
+
for (const list of [origins.connectDomains, origins.resourceDomains, origins.frameDomains]) {
|
|
449
|
+
for (const entry of list ?? []) {
|
|
450
|
+
// `https://*.example.com` → wildcard suffix `.example.com`
|
|
451
|
+
const wildcard = /^[a-z]+:\/\/\*\./i.exec(entry);
|
|
452
|
+
if (wildcard) {
|
|
453
|
+
out.push({ host: entry.slice(wildcard[0].length - 1).toLowerCase(), wildcard: true });
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
out.push({ host: new URL(entry).hostname.toLowerCase(), wildcard: false });
|
|
458
|
+
} catch {
|
|
459
|
+
// A malformed declaration is producer-side wire data; it simply
|
|
460
|
+
// never matches. The tripwire only ever ADDS a diagnosis, never
|
|
461
|
+
// blocks, so there is nothing to guard.
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return out;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Pure: is this violation ABOUT the view (its blocked URI lands on a
|
|
470
|
+
* declared origin), and if so, what should the embedder add?
|
|
471
|
+
*
|
|
472
|
+
* `blockedURI` is a full URL for network/script blocks; the browser sends
|
|
473
|
+
* bare tokens (`eval`, `inline`, `data`) for policy-class blocks — those
|
|
474
|
+
* carry no host and never match a declared origin, which is right: a
|
|
475
|
+
* `script-src eval` report is not the view's (see guuey#236 for the zod
|
|
476
|
+
* probe that produces exactly one such report at boot).
|
|
477
|
+
*/
|
|
478
|
+
export function diagnoseCspViolation(
|
|
479
|
+
violation: CspViolationLike,
|
|
480
|
+
origins: ViewCspOrigins | undefined,
|
|
481
|
+
): ViewCspDiagnosis | undefined {
|
|
482
|
+
if (origins === undefined) return undefined;
|
|
483
|
+
let blocked: URL;
|
|
484
|
+
try {
|
|
485
|
+
blocked = new URL(violation.blockedURI);
|
|
486
|
+
} catch {
|
|
487
|
+
return undefined; // bare token (eval/inline/data/…) — not a host, not the view's
|
|
488
|
+
}
|
|
489
|
+
const host = blocked.hostname.toLowerCase();
|
|
490
|
+
const hit = declaredHosts(origins).some((d) =>
|
|
491
|
+
d.wildcard ? host.endsWith(d.host) : host === d.host,
|
|
492
|
+
);
|
|
493
|
+
if (!hit) return undefined;
|
|
494
|
+
const directive = violation.effectiveDirective || violation.violatedDirective;
|
|
495
|
+
const suggestedEntry = blocked.origin;
|
|
496
|
+
return {
|
|
497
|
+
blockedUri: violation.blockedURI,
|
|
498
|
+
violatedDirective: directive,
|
|
499
|
+
suggestedEntry,
|
|
500
|
+
message: `This page's Content-Security-Policy blocks ${violation.blockedURI} (${directive}) — the view cannot start. Add \`${directive} ${suggestedEntry}\` to the page's policy.`,
|
|
501
|
+
};
|
|
502
|
+
}
|
package/src/view-host.ts
CHANGED
|
@@ -28,12 +28,16 @@
|
|
|
28
28
|
* re-derived here against the pure machine + our own tests.
|
|
29
29
|
*/
|
|
30
30
|
import {
|
|
31
|
+
diagnoseCspViolation,
|
|
31
32
|
initialViewHostState,
|
|
32
33
|
resourceReadResponse,
|
|
33
34
|
teardownMessage,
|
|
34
35
|
toolCallResponse,
|
|
35
36
|
viewHostElapsed,
|
|
36
37
|
viewHostReceive,
|
|
38
|
+
type CspViolationLike,
|
|
39
|
+
type ViewCspDiagnosis,
|
|
40
|
+
type ViewCspOrigins,
|
|
37
41
|
type ViewHostBehavior,
|
|
38
42
|
type ViewHostOutbound,
|
|
39
43
|
type ViewHostPhase,
|
|
@@ -74,6 +78,16 @@ export interface ViewHostEvents {
|
|
|
74
78
|
): void;
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Where CSP violations are observed — the EMBEDDING document (the frame's
|
|
83
|
+
* blocked loads report there, not inside the opaque frame). Structural like
|
|
84
|
+
* {@link ViewHostEvents}, injectable for tests. Default: `document`.
|
|
85
|
+
*/
|
|
86
|
+
export interface ViewCspEvents {
|
|
87
|
+
addEventListener(type: "securitypolicyviolation", listener: (event: CspViolationLike) => void): void;
|
|
88
|
+
removeEventListener(type: "securitypolicyviolation", listener: (event: CspViolationLike) => void): void;
|
|
89
|
+
}
|
|
90
|
+
|
|
77
91
|
export interface AttachViewHostConfig {
|
|
78
92
|
/**
|
|
79
93
|
* Capabilities to advertise in the initialize result. Default: `{}` —
|
|
@@ -130,6 +144,41 @@ export interface AttachViewHostConfig {
|
|
|
130
144
|
onSizeChanged?: (size: { width?: number; height?: number }) => void;
|
|
131
145
|
/** Observe phase transitions (see {@link ViewHostPhase}). */
|
|
132
146
|
onPhaseChange?: (phase: ViewHostPhase) => void;
|
|
147
|
+
/**
|
|
148
|
+
* The origins this view needs the embedding PAGE's CSP to allow — the
|
|
149
|
+
* spec's per-resource declaration (`McpUiResourceCsp`). Given, the host
|
|
150
|
+
* arms a CSP tripwire for the attachment's lifetime: a
|
|
151
|
+
* `securitypolicyviolation` on the EMBEDDING document whose blocked URI
|
|
152
|
+
* lands on one of these hosts is upgraded from a silent "never
|
|
153
|
+
* negotiated" into an actionable {@link ViewCspDiagnosis} (guuey#235).
|
|
154
|
+
* The phase itself stays `"no-handshake"` — honest about WHAT happened;
|
|
155
|
+
* the diagnosis says WHY. Absent → tripwire not installed, zero behavior
|
|
156
|
+
* change (the default for every existing caller).
|
|
157
|
+
*
|
|
158
|
+
* REACH (pinned by the browser leg, `e2e/tests/sdk/view-host.spec.ts`):
|
|
159
|
+
* the listener lives on the embedding document, so it sees violations
|
|
160
|
+
* the PAGE incurs on the view's origins — a runtime bundle the page
|
|
161
|
+
* loads at page level, a live channel the page opens on the view's
|
|
162
|
+
* behalf (the shape ggui's landing tripwire exercised). It does NOT see
|
|
163
|
+
* a `srcdoc` view's own blocked loads: the frame inherits the page's
|
|
164
|
+
* policy, but the browser enforces that copy in — and dispatches the
|
|
165
|
+
* violation on — the FRAME's document, which is opaque-origin and cannot
|
|
166
|
+
* be listened to from outside. A frame-side reporter would need host
|
|
167
|
+
* script injected into untrusted view HTML, a trust-boundary change this
|
|
168
|
+
* primitive deliberately does not make; the `sandboxPageUrl` mount owns
|
|
169
|
+
* its own policy and reports nothing here by construction.
|
|
170
|
+
*/
|
|
171
|
+
cspOrigins?: ViewCspOrigins;
|
|
172
|
+
/**
|
|
173
|
+
* A CSP violation ABOUT this view was observed (see {@link cspOrigins}).
|
|
174
|
+
* Fires at most once per attachment, as soon as the violation lands —
|
|
175
|
+
* typically BEFORE the negotiation window lapses, since a blocked runtime
|
|
176
|
+
* never gets to negotiate. `<GuueyView>` folds it into the no-handshake
|
|
177
|
+
* label; a custom renderer shows/logs it as it likes.
|
|
178
|
+
*/
|
|
179
|
+
onCspDiagnosis?: (diagnosis: ViewCspDiagnosis) => void;
|
|
180
|
+
/** CSP-violation event source, injectable for tests. Default: `document`. */
|
|
181
|
+
cspEvents?: ViewCspEvents;
|
|
133
182
|
/**
|
|
134
183
|
* How long to wait for `ui/initialize` before declaring
|
|
135
184
|
* `"no-handshake"` (ms). `0` disables the timer. Default 8000 — a view
|
|
@@ -270,6 +319,33 @@ export function attachViewHost(frame: ViewFrameLike, config: AttachViewHostConfi
|
|
|
270
319
|
};
|
|
271
320
|
const unsubscribe = subscribe();
|
|
272
321
|
|
|
322
|
+
// The CSP tripwire (guuey#235): armed only when the caller declared the
|
|
323
|
+
// view's origins — with none, there is nothing to match and nothing is
|
|
324
|
+
// installed. It only ever ADDS a diagnosis; it never changes what the
|
|
325
|
+
// machine does. Once per attachment: the first violation about the view
|
|
326
|
+
// is the diagnosis (later ones are the same failure repeating).
|
|
327
|
+
const unsubscribeCsp = ((): (() => void) => {
|
|
328
|
+
const { cspOrigins, onCspDiagnosis } = config;
|
|
329
|
+
if (cspOrigins === undefined) return () => {};
|
|
330
|
+
let reported = false;
|
|
331
|
+
const onViolation = (event: CspViolationLike): void => {
|
|
332
|
+
if (reported) return;
|
|
333
|
+
const diagnosis = diagnoseCspViolation(event, cspOrigins);
|
|
334
|
+
if (diagnosis === undefined) return;
|
|
335
|
+
reported = true;
|
|
336
|
+
onCspDiagnosis?.(diagnosis);
|
|
337
|
+
};
|
|
338
|
+
const { cspEvents } = config;
|
|
339
|
+
if (cspEvents !== undefined) {
|
|
340
|
+
cspEvents.addEventListener("securitypolicyviolation", onViolation);
|
|
341
|
+
return () => cspEvents.removeEventListener("securitypolicyviolation", onViolation);
|
|
342
|
+
}
|
|
343
|
+
if (typeof document === "undefined") return () => {}; // no embedding document — nothing reports there
|
|
344
|
+
const domListener = (event: SecurityPolicyViolationEvent): void => onViolation(event);
|
|
345
|
+
document.addEventListener("securitypolicyviolation", domListener);
|
|
346
|
+
return () => document.removeEventListener("securitypolicyviolation", domListener);
|
|
347
|
+
})();
|
|
348
|
+
|
|
273
349
|
const timeoutMs = config.negotiationTimeoutMs ?? DEFAULT_NEGOTIATION_TIMEOUT_MS;
|
|
274
350
|
const timer =
|
|
275
351
|
timeoutMs > 0 ? setTimeout(() => setState(viewHostElapsed(state)), timeoutMs) : undefined;
|
|
@@ -277,6 +353,7 @@ export function attachViewHost(frame: ViewFrameLike, config: AttachViewHostConfi
|
|
|
277
353
|
return () => {
|
|
278
354
|
if (timer !== undefined) clearTimeout(timer);
|
|
279
355
|
unsubscribe();
|
|
356
|
+
unsubscribeCsp();
|
|
280
357
|
cachedWindow?.postMessage(teardownMessage(), "*");
|
|
281
358
|
};
|
|
282
359
|
}
|
package/dist/ggui-render.d.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated — the ggui vendor arm is RETIRED (guuey#209, 2026-08-16).
|
|
3
|
-
*
|
|
4
|
-
* Everything in this module is kept exported for ONE MINOR under the
|
|
5
|
-
* post-launch compatibility rule and is removed in the minor after the one
|
|
6
|
-
* that ships this notice. Nothing in `@guuey/mcp-apps-host` calls it any
|
|
7
|
-
* more: `toolResultViewMount` hands a ggui render back as a `ui://`
|
|
8
|
-
* **locator** (`toolResultLocator`, either channel), the mount material
|
|
9
|
-
* comes from a `resources/read` through a `UiResourceReader` (pod door
|
|
10
|
-
* live, persisted door on rehydration), and the `"ggui"` sandbox-trust
|
|
11
|
-
* channel is assigned at resolution from the requested uri
|
|
12
|
-
* (`uiResourceChannel` in `reader.ts`). Migration per symbol:
|
|
13
|
-
*
|
|
14
|
-
* - {@link asGguiRender} / {@link toolResultGguiRender} /
|
|
15
|
-
* {@link blockGguiRender} → `toolResultLocator(block)` — the locator is
|
|
16
|
-
* the recognition signal; there is no descriptor to build.
|
|
17
|
-
* - {@link gguiRenderResource} → resolve the locator through a reader
|
|
18
|
-
* (`resolveViewMount(mount, reader)`); ggui's `resources/read` returns
|
|
19
|
-
* the shell with live-channel material minted FRESH at read time.
|
|
20
|
-
* - {@link GGUI_RENDER_META_KEY} → the wire key is ggui's; import
|
|
21
|
-
* `MCP_APP_AI_GGUI_RENDER_META_KEY` from
|
|
22
|
-
* `@ggui-ai/protocol/integrations/mcp-apps` if you still inspect
|
|
23
|
-
* `_meta` (nothing here does).
|
|
24
|
-
* - {@link asGguiRenderBootstrap} / {@link gguiShellHtml} and their types
|
|
25
|
-
* are pure re-exports of ggui's protocol package — import them from
|
|
26
|
-
* `@ggui-ai/protocol/integrations/mcp-apps` directly.
|
|
27
|
-
*
|
|
28
|
-
* ## Why the arm existed, for the record
|
|
29
|
-
*
|
|
30
|
-
* A ggui render's `tool.done` used to carry two signals: `uiData.resourceUri`
|
|
31
|
-
* (recognition — the only part surviving the fold) and the
|
|
32
|
-
* `_meta["ai.ggui/render"]` bootstrap (mount material: runtime bundle,
|
|
33
|
-
* live channel, seeded props). Because guuey's chat client is not an MCP
|
|
34
|
-
* client (the pod holds the connection), a live locator had no host-side
|
|
35
|
-
* read channel, so the bootstrap was inlined as a read-skipping fast path
|
|
36
|
-
* and this module built ggui's self-contained shell from it. The pod door
|
|
37
|
-
* (`GET <pod>/agent/ui-resource`, guuey#209 C1) closed that gap; ggui's
|
|
38
|
-
* read-time mint (C2) made the read strictly fresher than the inlined
|
|
39
|
-
* copy; the vendor arm's only reason to exist was gone.
|
|
40
|
-
*/
|
|
41
|
-
import type { AgBlock, JsonValue } from "@silverprotocol/core";
|
|
42
|
-
import { type GguiRenderBootstrap } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
43
|
-
import { type McpUiResourcePayload } from "./block-ui.js";
|
|
44
|
-
export {
|
|
45
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
46
|
-
asGguiRenderBootstrap,
|
|
47
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
48
|
-
gguiShellHtml, } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
49
|
-
export type {
|
|
50
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
51
|
-
GguiRenderBootstrap,
|
|
52
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
53
|
-
GguiShellHtmlOptions, } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
54
|
-
/**
|
|
55
|
-
* The `_meta` key the ggui render bootstrap rides on. Alias of the
|
|
56
|
-
* protocol package's own constant — one spelling, owned upstream.
|
|
57
|
-
*
|
|
58
|
-
* @deprecated guuey#209 — nothing in this package reads `_meta` any more.
|
|
59
|
-
* Import `MCP_APP_AI_GGUI_RENDER_META_KEY` from
|
|
60
|
-
* `@ggui-ai/protocol/integrations/mcp-apps` if you still need the key.
|
|
61
|
-
* Removed in the minor after the one shipping this notice.
|
|
62
|
-
*/
|
|
63
|
-
export declare const GGUI_RENDER_META_KEY: "ai.ggui/render";
|
|
64
|
-
/**
|
|
65
|
-
* A ggui render recognised on a tool result: its resource uri + mount material.
|
|
66
|
-
* @deprecated guuey#209 — the locator (`toolResultLocator`) is the whole
|
|
67
|
-
* recognition signal now; there is no descriptor to build. Removed next minor.
|
|
68
|
-
*/
|
|
69
|
-
export interface GguiRenderDescriptor {
|
|
70
|
-
/** `uiData.resourceUri` — `ui://ggui/render/<sessionId>/<contractHash>`. */
|
|
71
|
-
resourceUri: string;
|
|
72
|
-
/** `uiData.sessionId`, when present. */
|
|
73
|
-
sessionId?: string;
|
|
74
|
-
/**
|
|
75
|
-
* The `_meta["ai.ggui/render"]` slice, when it reached us. Absent for a
|
|
76
|
-
* persisted history card and for any consumer folding without `fold.ts`'s
|
|
77
|
-
* `_meta` carriage — such a descriptor is recognised but NOT mountable.
|
|
78
|
-
*/
|
|
79
|
-
bootstrap?: GguiRenderBootstrap;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* A tool result's `uiData` (+ its `_meta`, when carried) → a ggui render
|
|
83
|
-
* descriptor, or `undefined` for anything that is not one.
|
|
84
|
-
*
|
|
85
|
-
* The `ui://` scheme gate is deliberate: `uiData` is a general-purpose channel
|
|
86
|
-
* (every `structuredContent` of a `_meta.ui`-stamped tool lands there), so a
|
|
87
|
-
* bare `resourceUri` string is not on its own a claim of generative UI.
|
|
88
|
-
*
|
|
89
|
-
* @deprecated guuey#209 — use `toolResultLocator(block)`; the vendor arm is
|
|
90
|
-
* retired and nothing consumes the descriptor. Removed next minor.
|
|
91
|
-
*/
|
|
92
|
-
export declare function asGguiRender(uiData: JsonValue | undefined, meta: JsonValue | undefined): GguiRenderDescriptor | undefined;
|
|
93
|
-
/**
|
|
94
|
-
* A live `tool-result` AgBlock → its ggui render descriptor, if it is one.
|
|
95
|
-
*
|
|
96
|
-
* NOTE: `@ggui-ai/protocol/integrations/mcp-apps` exports a helper of the
|
|
97
|
-
* same name that narrows a spec-canonical MCP `CallToolResult` instead. This
|
|
98
|
-
* one is the silverprotocol-side twin — the input is the FOLDED block, whose
|
|
99
|
-
* `uiData`/`_meta` carriage is `@silverprotocol/core`'s contract, not ggui's.
|
|
100
|
-
*
|
|
101
|
-
* @deprecated guuey#209 — use `toolResultLocator(block)`. Removed next minor.
|
|
102
|
-
*/
|
|
103
|
-
export declare function toolResultGguiRender(block: Extract<AgBlock, {
|
|
104
|
-
type: "tool-result";
|
|
105
|
-
}>): GguiRenderDescriptor | undefined;
|
|
106
|
-
/**
|
|
107
|
-
* An untyped (persisted-snapshot) block → its ggui render descriptor, if it is one.
|
|
108
|
-
* @deprecated guuey#209 — use `snapshotViewMount(cardSnapshot)`, whose locator
|
|
109
|
-
* arm is the persisted path. Removed next minor.
|
|
110
|
-
*/
|
|
111
|
-
export declare function blockGguiRender(block: JsonValue): GguiRenderDescriptor | undefined;
|
|
112
|
-
/**
|
|
113
|
-
* A ggui render descriptor → the mountable resource the host's existing
|
|
114
|
-
* mcp-ui path already knows how to mount, or `undefined` when the descriptor
|
|
115
|
-
* carries no bootstrap (history cards, and any fold that dropped `_meta`).
|
|
116
|
-
*
|
|
117
|
-
* @deprecated guuey#209 — resolve the locator through a `UiResourceReader`
|
|
118
|
-
* (`resolveViewMount`); ggui's `resources/read` returns the shell with
|
|
119
|
-
* live-channel material minted FRESH at read time, which this inlined
|
|
120
|
-
* copy could never be. Removed next minor.
|
|
121
|
-
*
|
|
122
|
-
* The `uri` is the render's REAL `resourceUri` — the shell is the payload, not
|
|
123
|
-
* a renaming of the resource.
|
|
124
|
-
*
|
|
125
|
-
* The shell is built `background: 'transparent'`: every guuey host that
|
|
126
|
-
* mounts through this adapter (widget, portal web, Studio) draws its own
|
|
127
|
-
* card chrome around the iframe, so the host page composits behind the card.
|
|
128
|
-
* The upstream default (`'surface'`) is for standalone served documents —
|
|
129
|
-
* see `GguiShellHtmlOptions` in `@ggui-ai/protocol/integrations/mcp-apps`.
|
|
130
|
-
*
|
|
131
|
-
* **On `_meta` being required to MOUNT (but never to RECOGNISE).** Recognition
|
|
132
|
-
* — "this tool result is a ggui card" — is keyed on `uiData.resourceUri` alone
|
|
133
|
-
* and never waits for anything (see {@link asGguiRender}); nothing in this
|
|
134
|
-
* package is blocked on an upstream change. Mounting is different, and the
|
|
135
|
-
* requirement is ggui's, not ours: its runtime rejects a slice without
|
|
136
|
-
* `runtimeUrl` AND without at least one mode discriminator (`wsUrl`+`wsToken`,
|
|
137
|
-
* `codeUrl`, or `kind`) as `MALFORMED_BOOTSTRAP` and renders nothing. `uiData`
|
|
138
|
-
* carries none of those fields, so a bootstrap-less descriptor could only ever
|
|
139
|
-
* produce a blank frame; returning `undefined` and letting the host show its
|
|
140
|
-
* own placeholder is the honest answer, not a deferral. `@silverprotocol/core`'s
|
|
141
|
-
* `Reducer` is what puts `_meta` on the block for a live turn, in-repo, today.
|
|
142
|
-
*/
|
|
143
|
-
export declare function gguiRenderResource(render: GguiRenderDescriptor): McpUiResourcePayload | undefined;
|
|
144
|
-
//# sourceMappingURL=ggui-render.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ggui-render.d.ts","sourceRoot":"","sources":["../src/ggui-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO;AACL,yGAAyG;AACzG,qBAAqB;AACrB,yGAAyG;AACzG,aAAa,GACd,MAAM,yCAAyC,CAAC;AACjD,YAAY;AACV,yGAAyG;AACzG,mBAAmB;AACnB,yGAAyG;AACzG,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,kBAAkC,CAAC;AAKpE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,GAAG,SAAS,EAC7B,IAAI,EAAE,SAAS,GAAG,SAAS,GAC1B,oBAAoB,GAAG,SAAS,CAUlC;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,GAC/C,oBAAoB,GAAG,SAAS,CAElC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAIlF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,oBAAoB,GAC3B,oBAAoB,GAAG,SAAS,CAOlC"}
|
package/dist/ggui-render.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { asGguiRenderBootstrap, gguiShellHtml, MCP_APP_AI_GGUI_RENDER_META_KEY, } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
2
|
-
import { isJsonObject } from "./block-ui.js";
|
|
3
|
-
export {
|
|
4
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
5
|
-
asGguiRenderBootstrap,
|
|
6
|
-
/** @deprecated import from `@ggui-ai/protocol/integrations/mcp-apps` (guuey#209; removed next minor). */
|
|
7
|
-
gguiShellHtml, } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
8
|
-
/**
|
|
9
|
-
* The `_meta` key the ggui render bootstrap rides on. Alias of the
|
|
10
|
-
* protocol package's own constant — one spelling, owned upstream.
|
|
11
|
-
*
|
|
12
|
-
* @deprecated guuey#209 — nothing in this package reads `_meta` any more.
|
|
13
|
-
* Import `MCP_APP_AI_GGUI_RENDER_META_KEY` from
|
|
14
|
-
* `@ggui-ai/protocol/integrations/mcp-apps` if you still need the key.
|
|
15
|
-
* Removed in the minor after the one shipping this notice.
|
|
16
|
-
*/
|
|
17
|
-
export const GGUI_RENDER_META_KEY = MCP_APP_AI_GGUI_RENDER_META_KEY;
|
|
18
|
-
/** The `ui://` scheme prefix every ggui render resource uri carries. */
|
|
19
|
-
const UI_SCHEME = "ui://";
|
|
20
|
-
/**
|
|
21
|
-
* A tool result's `uiData` (+ its `_meta`, when carried) → a ggui render
|
|
22
|
-
* descriptor, or `undefined` for anything that is not one.
|
|
23
|
-
*
|
|
24
|
-
* The `ui://` scheme gate is deliberate: `uiData` is a general-purpose channel
|
|
25
|
-
* (every `structuredContent` of a `_meta.ui`-stamped tool lands there), so a
|
|
26
|
-
* bare `resourceUri` string is not on its own a claim of generative UI.
|
|
27
|
-
*
|
|
28
|
-
* @deprecated guuey#209 — use `toolResultLocator(block)`; the vendor arm is
|
|
29
|
-
* retired and nothing consumes the descriptor. Removed next minor.
|
|
30
|
-
*/
|
|
31
|
-
export function asGguiRender(uiData, meta) {
|
|
32
|
-
if (!isJsonObject(uiData))
|
|
33
|
-
return undefined;
|
|
34
|
-
const resourceUri = uiData.resourceUri;
|
|
35
|
-
if (typeof resourceUri !== "string" || !resourceUri.startsWith(UI_SCHEME))
|
|
36
|
-
return undefined;
|
|
37
|
-
const bootstrap = asGguiRenderBootstrap(meta);
|
|
38
|
-
return {
|
|
39
|
-
resourceUri,
|
|
40
|
-
...(typeof uiData.sessionId === "string" ? { sessionId: uiData.sessionId } : {}),
|
|
41
|
-
...(bootstrap ? { bootstrap } : {}),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* A live `tool-result` AgBlock → its ggui render descriptor, if it is one.
|
|
46
|
-
*
|
|
47
|
-
* NOTE: `@ggui-ai/protocol/integrations/mcp-apps` exports a helper of the
|
|
48
|
-
* same name that narrows a spec-canonical MCP `CallToolResult` instead. This
|
|
49
|
-
* one is the silverprotocol-side twin — the input is the FOLDED block, whose
|
|
50
|
-
* `uiData`/`_meta` carriage is `@silverprotocol/core`'s contract, not ggui's.
|
|
51
|
-
*
|
|
52
|
-
* @deprecated guuey#209 — use `toolResultLocator(block)`. Removed next minor.
|
|
53
|
-
*/
|
|
54
|
-
export function toolResultGguiRender(block) {
|
|
55
|
-
return asGguiRender(block.uiData, block._meta);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* An untyped (persisted-snapshot) block → its ggui render descriptor, if it is one.
|
|
59
|
-
* @deprecated guuey#209 — use `snapshotViewMount(cardSnapshot)`, whose locator
|
|
60
|
-
* arm is the persisted path. Removed next minor.
|
|
61
|
-
*/
|
|
62
|
-
export function blockGguiRender(block) {
|
|
63
|
-
if (!isJsonObject(block))
|
|
64
|
-
return undefined;
|
|
65
|
-
if (block.type !== "tool-result")
|
|
66
|
-
return undefined;
|
|
67
|
-
return asGguiRender(block.uiData, block._meta);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* A ggui render descriptor → the mountable resource the host's existing
|
|
71
|
-
* mcp-ui path already knows how to mount, or `undefined` when the descriptor
|
|
72
|
-
* carries no bootstrap (history cards, and any fold that dropped `_meta`).
|
|
73
|
-
*
|
|
74
|
-
* @deprecated guuey#209 — resolve the locator through a `UiResourceReader`
|
|
75
|
-
* (`resolveViewMount`); ggui's `resources/read` returns the shell with
|
|
76
|
-
* live-channel material minted FRESH at read time, which this inlined
|
|
77
|
-
* copy could never be. Removed next minor.
|
|
78
|
-
*
|
|
79
|
-
* The `uri` is the render's REAL `resourceUri` — the shell is the payload, not
|
|
80
|
-
* a renaming of the resource.
|
|
81
|
-
*
|
|
82
|
-
* The shell is built `background: 'transparent'`: every guuey host that
|
|
83
|
-
* mounts through this adapter (widget, portal web, Studio) draws its own
|
|
84
|
-
* card chrome around the iframe, so the host page composits behind the card.
|
|
85
|
-
* The upstream default (`'surface'`) is for standalone served documents —
|
|
86
|
-
* see `GguiShellHtmlOptions` in `@ggui-ai/protocol/integrations/mcp-apps`.
|
|
87
|
-
*
|
|
88
|
-
* **On `_meta` being required to MOUNT (but never to RECOGNISE).** Recognition
|
|
89
|
-
* — "this tool result is a ggui card" — is keyed on `uiData.resourceUri` alone
|
|
90
|
-
* and never waits for anything (see {@link asGguiRender}); nothing in this
|
|
91
|
-
* package is blocked on an upstream change. Mounting is different, and the
|
|
92
|
-
* requirement is ggui's, not ours: its runtime rejects a slice without
|
|
93
|
-
* `runtimeUrl` AND without at least one mode discriminator (`wsUrl`+`wsToken`,
|
|
94
|
-
* `codeUrl`, or `kind`) as `MALFORMED_BOOTSTRAP` and renders nothing. `uiData`
|
|
95
|
-
* carries none of those fields, so a bootstrap-less descriptor could only ever
|
|
96
|
-
* produce a blank frame; returning `undefined` and letting the host show its
|
|
97
|
-
* own placeholder is the honest answer, not a deferral. `@silverprotocol/core`'s
|
|
98
|
-
* `Reducer` is what puts `_meta` on the block for a live turn, in-repo, today.
|
|
99
|
-
*/
|
|
100
|
-
export function gguiRenderResource(render) {
|
|
101
|
-
if (!render.bootstrap)
|
|
102
|
-
return undefined;
|
|
103
|
-
return {
|
|
104
|
-
uri: render.resourceUri,
|
|
105
|
-
mimeType: "text/html",
|
|
106
|
-
text: gguiShellHtml(render.bootstrap, { background: "transparent" }),
|
|
107
|
-
};
|
|
108
|
-
}
|