@guuey/mcp-apps-host 0.6.0 → 0.6.1

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/action.d.ts CHANGED
@@ -51,10 +51,33 @@ export type McpToolCallResult = {
51
51
  structuredContent?: McpToolStructuredContent;
52
52
  };
53
53
  /**
54
- * The runtime-action tools a card sandbox may relay — the client-side twin
55
- * of the server allowlist (defense in depth: the proxy enforces it again).
54
+ * The runtime tools a card sandbox may RELAY over `tools/call` — the
55
+ * client-side twin of the server allowlist (defense in depth: the proxy
56
+ * enforces it again). Exactly ggui's iframe-runtime surface, all declared
57
+ * `_meta.ui.visibility: ['app']` (never model-callable):
58
+ *
59
+ * - `ggui_runtime_submit_action` — the user's gesture (the SEMANTIC one);
60
+ * - `ggui_runtime_refresh_ws_token` — live-channel credential refresh
61
+ * (the wsToken TTL is 180 s; without the relay a view on SSE/polling
62
+ * dies at that mark — guuey#220);
63
+ * - `ggui_runtime_pull` — the host-relayed polling rung where the
64
+ * sandbox's own transports are blocked (bridge-pull, terminal rung).
65
+ *
66
+ * Two of these are transport plumbing whose arguments are opaque runtime
67
+ * state — see {@link UI_SEMANTIC_ACTION_TOOLS} for the ONLY set a host may
68
+ * treat as "the user did something".
56
69
  */
57
70
  export declare const UI_ACTION_TOOLS: ReadonlySet<string>;
71
+ /**
72
+ * The strict subset of {@link UI_ACTION_TOOLS} that carries a USER gesture —
73
+ * the only calls a host may project into user-facing affordances (composer
74
+ * staging, "the user selected X" copy, telemetry as intent). Every other
75
+ * relayed tool is runtime plumbing whose payload must NEVER reach the user
76
+ * verbatim (guuey#215/#218: a staged `sessionId …` was exactly that leak).
77
+ * A tool that is relayable is NOT thereby semantic; a host that widens
78
+ * this set is asserting the wire semantics of the new name.
79
+ */
80
+ export declare const UI_SEMANTIC_ACTION_TOOLS: ReadonlySet<string>;
58
81
  /** The in-band answer for anything the relay cannot (or will not) do. */
59
82
  export declare const UI_ACTION_UNAVAILABLE_TEXT = "This action isn't available right now.";
60
83
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,CAC3C;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CACnB,CAAC;CACH,CAAC;AAEN;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC9C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAE9C,CAAC;AAEH,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,2CACG,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,iBAAiB,CAK7D;AAkCD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAgB9E;AAED,iFAAiF;AACjF,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,QAAQ,EAAE,CACR,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,wBAAwB,GAAG,SAAS,KACvC,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,0BAA0B,GAC/B,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAa1D"}
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,CAC3C;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CACnB,CAAC;CACH,CAAC;AAEN;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC9C,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAI9C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAEvD,CAAC;AAEH,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,2CACG,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,iBAAiB,CAK7D;AAkCD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAgB9E;AAED,iFAAiF;AACjF,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,QAAQ,EAAE,CACR,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,wBAAwB,GAAG,SAAS,KACvC,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,0BAA0B,GAC/B,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAa1D"}
package/dist/action.js CHANGED
@@ -13,11 +13,38 @@
13
13
  * it crosses into the sandbox.
14
14
  */
15
15
  /**
16
- * The runtime-action tools a card sandbox may relay — the client-side twin
17
- * of the server allowlist (defense in depth: the proxy enforces it again).
16
+ * The runtime tools a card sandbox may RELAY over `tools/call` — the
17
+ * client-side twin of the server allowlist (defense in depth: the proxy
18
+ * enforces it again). Exactly ggui's iframe-runtime surface, all declared
19
+ * `_meta.ui.visibility: ['app']` (never model-callable):
20
+ *
21
+ * - `ggui_runtime_submit_action` — the user's gesture (the SEMANTIC one);
22
+ * - `ggui_runtime_refresh_ws_token` — live-channel credential refresh
23
+ * (the wsToken TTL is 180 s; without the relay a view on SSE/polling
24
+ * dies at that mark — guuey#220);
25
+ * - `ggui_runtime_pull` — the host-relayed polling rung where the
26
+ * sandbox's own transports are blocked (bridge-pull, terminal rung).
27
+ *
28
+ * Two of these are transport plumbing whose arguments are opaque runtime
29
+ * state — see {@link UI_SEMANTIC_ACTION_TOOLS} for the ONLY set a host may
30
+ * treat as "the user did something".
18
31
  */
19
32
  export const UI_ACTION_TOOLS = new Set([
20
33
  "ggui_runtime_submit_action",
34
+ "ggui_runtime_refresh_ws_token",
35
+ "ggui_runtime_pull",
36
+ ]);
37
+ /**
38
+ * The strict subset of {@link UI_ACTION_TOOLS} that carries a USER gesture —
39
+ * the only calls a host may project into user-facing affordances (composer
40
+ * staging, "the user selected X" copy, telemetry as intent). Every other
41
+ * relayed tool is runtime plumbing whose payload must NEVER reach the user
42
+ * verbatim (guuey#215/#218: a staged `sessionId …` was exactly that leak).
43
+ * A tool that is relayable is NOT thereby semantic; a host that widens
44
+ * this set is asserting the wire semantics of the new name.
45
+ */
46
+ export const UI_SEMANTIC_ACTION_TOOLS = new Set([
47
+ "ggui_runtime_submit_action",
21
48
  ]);
22
49
  /** The in-band answer for anything the relay cannot (or will not) do. */
23
50
  export const UI_ACTION_UNAVAILABLE_TEXT = "This action isn't available right now.";
@@ -104,6 +104,24 @@ export declare function toolResultUiResource(block: Extract<AgBlock, {
104
104
  * are one producer of this shape.
105
105
  */
106
106
  export declare function uiLocator(uiData: JsonValue | undefined): string | undefined;
107
+ /**
108
+ * The `ui://` locator a `tool-result` block carries, from EITHER channel it
109
+ * can arrive on — the single seam every locator reader goes through.
110
+ *
111
+ * AgJSON §2.1 routes a tool result's `structuredContent` by its `_meta.ui`
112
+ * sibling: WITH the sibling it is surface data and the normalizer stamps
113
+ * `uiData`; WITHOUT it, it is model-channel data and lands in
114
+ * `structuredContent`. A producer that withholds `_meta` (ggui's non-prod
115
+ * posture; any plain-locator MCP server) therefore delivers a locator that
116
+ * is byte-identical in shape but lives one field over — reading `uiData`
117
+ * alone renders NOTHING for it (dark, not "expired"), and the persistence
118
+ * projector minted no placeholder row (the read plane 404s). `uiData` wins
119
+ * when both carry one (guuey#209 route-A finding).
120
+ */
121
+ export declare function toolResultLocator(block: {
122
+ uiData?: JsonValue;
123
+ structuredContent?: JsonValue;
124
+ }): string | undefined;
107
125
  export declare function snapshotUiResource(cardSnapshot: JsonValue): McpUiResourcePayload | undefined;
108
126
  /**
109
127
  * The resource's HTML: inline `text` wins; else base64-decode `blob`. `atob`
@@ -1 +1 @@
1
- {"version":3,"file":"block-ui.d.ts","sourceRoot":"","sources":["../src/block-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAExF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAU5F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAK5F;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,SAAS,GAAG,SAAS,GACzB,oBAAoB,GAAG,SAAS,CAMlC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAyBlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,GAC/C,oBAAoB,GAAG,SAAS,CAUlC;AAED;;;;;;;;;;;GAWG;AACH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI3E;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAU5F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAU/E"}
1
+ {"version":3,"file":"block-ui.d.ts","sourceRoot":"","sources":["../src/block-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAExF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAU5F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAK5F;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,SAAS,GAAG,SAAS,GACzB,oBAAoB,GAAG,SAAS,CAMlC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAyBlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,GAC/C,oBAAoB,GAAG,SAAS,CAUlC;AAED;;;;;;;;;;;GAWG;AACH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI3E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,iBAAiB,CAAC,EAAE,SAAS,CAAC;CAC/B,GAAG,MAAM,GAAG,SAAS,CAErB;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,SAAS,GAAG,oBAAoB,GAAG,SAAS,CAU5F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAU/E"}
package/dist/block-ui.js CHANGED
@@ -140,6 +140,23 @@ export function uiLocator(uiData) {
140
140
  const uri = uiData.resourceUri;
141
141
  return typeof uri === "string" && uri.startsWith("ui://") ? uri : undefined;
142
142
  }
143
+ /**
144
+ * The `ui://` locator a `tool-result` block carries, from EITHER channel it
145
+ * can arrive on — the single seam every locator reader goes through.
146
+ *
147
+ * AgJSON §2.1 routes a tool result's `structuredContent` by its `_meta.ui`
148
+ * sibling: WITH the sibling it is surface data and the normalizer stamps
149
+ * `uiData`; WITHOUT it, it is model-channel data and lands in
150
+ * `structuredContent`. A producer that withholds `_meta` (ggui's non-prod
151
+ * posture; any plain-locator MCP server) therefore delivers a locator that
152
+ * is byte-identical in shape but lives one field over — reading `uiData`
153
+ * alone renders NOTHING for it (dark, not "expired"), and the persistence
154
+ * projector minted no placeholder row (the read plane 404s). `uiData` wins
155
+ * when both carry one (guuey#209 route-A finding).
156
+ */
157
+ export function toolResultLocator(block) {
158
+ return uiLocator(block.uiData) ?? uiLocator(block.structuredContent);
159
+ }
143
160
  export function snapshotUiResource(cardSnapshot) {
144
161
  if (!isJsonObject(cardSnapshot))
145
162
  return undefined;
@@ -44,7 +44,9 @@ export type ViewMountChannel = "inline" | "ggui" | "locator";
44
44
  * `"ggui"` — a shell that boots the ggui runtime from a platform-pinned
45
45
  * origin, and therefore needs a host page whose CSP allows that origin.
46
46
  * `"locator"` — no mount material in hand, only the durable `ui://`
47
- * identity (guuey#122): the host resolves it with a fresh, authenticated
47
+ * identity (guuey#122) read from `uiData` OR, for a producer that
48
+ * withheld `_meta` (AgJSON §2.1 then routes it to `structuredContent`),
49
+ * from `structuredContent` (guuey#209): the host resolves it with a fresh, authenticated
48
50
  * `resources/read` of the uri ({@link UiResourceReader}) — the spec-consistent
49
51
  * template fetch, vendor-neutral. (The spec defers persistence/restoration
50
52
  * itself; a full remount additionally owes the View `ui/notifications/tool-input`
@@ -65,7 +67,7 @@ export interface ResolvedViewMount {
65
67
  /** The durable-identity arm: no mount material, only the uri to re-fetch. */
66
68
  export interface LocatorViewMount {
67
69
  channel: "locator";
68
- /** The persisted `uiData.resourceUri` (`ui://` scheme) to re-fetch. */
70
+ /** The durable `ui://` locator to re-fetch (`uiData.resourceUri`, else `structuredContent.resourceUri`). */
69
71
  resourceUri: string;
70
72
  }
71
73
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"card-mount.d.ts","sourceRoot":"","sources":["../src/card-mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAAuD,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE/G,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAW/D,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAED,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,SAAS,CAAC;IACnB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,GAC/C,SAAS,GAAG,SAAS,CAkBvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAUhF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAKxC"}
1
+ {"version":3,"file":"card-mount.d.ts","sourceRoot":"","sources":["../src/card-mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAA+D,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAEvH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAW/D,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAED,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,SAAS,CAAC;IACnB,4GAA4G;IAC5G,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,GAC/C,SAAS,GAAG,SAAS,CAoBvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAUhF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAKxC"}
@@ -33,7 +33,7 @@
33
33
  * keeps that one narrowing in one place — the alternative was for every host
34
34
  * to re-run `toolResultGguiRender` beside this call and ask again.
35
35
  */
36
- import { snapshotUiResource, toolResultUiResource, uiLocator } from "./block-ui.js";
36
+ import { snapshotUiResource, toolResultLocator, toolResultUiResource } from "./block-ui.js";
37
37
  import { GGUI_RENDER_META_KEY, gguiRenderResource, toolResultGguiRender } from "./ggui-render.js";
38
38
  /** Does the block's `_meta` carry the ggui render key at all (valid or not)? */
39
39
  function blockCarriesGguiMetaKey(block) {
@@ -54,14 +54,16 @@ export function toolResultViewMount(block) {
54
54
  if (resource)
55
55
  return { resource, channel: "ggui" };
56
56
  // A live locator whose mount material didn't reach us (a fold that
57
- // dropped `_meta`): re-fetch works on live turns too — the resource is
58
- // freshly minted (guuey#122). One diagnostic when `_meta` DID carry the
57
+ // dropped `_meta`, or a producer that never sent it — the locator then
58
+ // rides `structuredContent`, see `toolResultLocator`): re-fetch works on
59
+ // live turns too — the resource is freshly minted (guuey#122). One
60
+ // diagnostic when `_meta` DID carry the
59
61
  // vendor key but failed validation — a producer bug would otherwise be
60
62
  // indistinguishable from a meta-less fold (blank UI, zero errors).
61
63
  if (ggui && !ggui.bootstrap && blockCarriesGguiMetaKey(block)) {
62
64
  console.warn(`mcp-apps-host: tool result ${block.toolCallId} carries a malformed ggui render bootstrap — degrading to the locator channel`);
63
65
  }
64
- const locator = uiLocator(block.uiData);
66
+ const locator = toolResultLocator(block);
65
67
  return locator !== undefined ? { channel: "locator", resourceUri: locator } : undefined;
66
68
  }
67
69
  /**
@@ -83,7 +85,7 @@ export function snapshotViewMount(cardSnapshot) {
83
85
  continue;
84
86
  if (block.type !== "tool-result")
85
87
  continue;
86
- const locator = uiLocator(block.uiData);
88
+ const locator = toolResultLocator(block);
87
89
  if (locator !== undefined)
88
90
  return { channel: "locator", resourceUri: locator };
89
91
  }
package/dist/index.d.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  * narrowing, ui:// locator rehydration, sandbox-trust channels. See README +
4
4
  * the conformance map (guuey#123).
5
5
  */
6
- export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultUiResource, uiLocator, type McpUiResourcePayload, } from "./block-ui.js";
6
+ export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultLocator, toolResultUiResource, uiLocator, type McpUiResourcePayload, } from "./block-ui.js";
7
7
  export { asGguiRender, asGguiRenderBootstrap, blockGguiRender, gguiRenderResource, gguiShellHtml, toolResultGguiRender, GGUI_RENDER_META_KEY, type GguiRenderBootstrap, type GguiRenderDescriptor, type GguiShellHtmlOptions, } from "./ggui-render.js";
8
8
  export { resolveViewMount, snapshotViewMount, toolResultViewMount, type LocatorViewMount, type ResolvedViewMount, type UiResourceReader, type ViewMount, type ViewMountChannel, } from "./card-mount.js";
9
9
  export { createMcpUiResourceReader, uiResourceChannel, type CreateMcpUiResourceReaderDeps, type McpResourceReadResult, } from "./reader.js";
10
- export { asToolCallResult, createMcpUiActionRelay, unavailableToolCallResult, UI_ACTION_TOOLS, UI_ACTION_UNAVAILABLE_TEXT, type CreateMcpUiActionRelayDeps, type McpToolCallContent, type McpToolCallResult, type McpToolStructuredContent, type UiActionRequest, } from "./action.js";
10
+ export { asToolCallResult, createMcpUiActionRelay, unavailableToolCallResult, UI_ACTION_TOOLS, UI_ACTION_UNAVAILABLE_TEXT, UI_SEMANTIC_ACTION_TOOLS, type CreateMcpUiActionRelayDeps, type McpToolCallContent, type McpToolCallResult, type McpToolStructuredContent, type UiActionRequest, } from "./action.js";
11
11
  export { initializeResult, initialViewHostState, resourceReadResponse, RESOURCES_READ_METHOD, teardownMessage, toolCallResponse, TOOLS_CALL_METHOD, viewHostElapsed, viewHostReceive, type ViewHostBehavior, type ViewHostEffect, type ViewHostOutbound, type ViewHostPhase, type ViewHostInfo, type ViewHostState, type ViewHostTransition, type ViewRequestId, } from "./view-host-protocol.js";
12
12
  export { attachViewHost, viewDocumentHtml, type AttachViewHostConfig, type ViewFrameLike, type ViewHostEvents, } from "./view-host.js";
13
13
  export { attachSandboxPageDelivery, isSandboxProxyReady, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, type SandboxPageDeliveryConfig, } from "./sandbox-page.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,4BAA4B,EAC5B,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,EACT,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,0BAA0B,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,4BAA4B,EAC5B,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,0BAA0B,EAC1B,wBAAwB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -3,11 +3,11 @@
3
3
  * narrowing, ui:// locator rehydration, sandbox-trust channels. See README +
4
4
  * the conformance map (guuey#123).
5
5
  */
6
- export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultUiResource, uiLocator, } from "./block-ui.js";
6
+ export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultLocator, toolResultUiResource, uiLocator, } from "./block-ui.js";
7
7
  export { asGguiRender, asGguiRenderBootstrap, blockGguiRender, gguiRenderResource, gguiShellHtml, toolResultGguiRender, GGUI_RENDER_META_KEY, } from "./ggui-render.js";
8
8
  export { resolveViewMount, snapshotViewMount, toolResultViewMount, } from "./card-mount.js";
9
9
  export { createMcpUiResourceReader, uiResourceChannel, } from "./reader.js";
10
- export { asToolCallResult, createMcpUiActionRelay, unavailableToolCallResult, UI_ACTION_TOOLS, UI_ACTION_UNAVAILABLE_TEXT, } from "./action.js";
10
+ export { asToolCallResult, createMcpUiActionRelay, unavailableToolCallResult, UI_ACTION_TOOLS, UI_ACTION_UNAVAILABLE_TEXT, UI_SEMANTIC_ACTION_TOOLS, } from "./action.js";
11
11
  export { initializeResult, initialViewHostState, resourceReadResponse, RESOURCES_READ_METHOD, teardownMessage, toolCallResponse, TOOLS_CALL_METHOD, viewHostElapsed, viewHostReceive, } from "./view-host-protocol.js";
12
12
  export { attachViewHost, viewDocumentHtml, } from "./view-host.js";
13
13
  export { attachSandboxPageDelivery, isSandboxProxyReady, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, } from "./sandbox-page.js";
@@ -5,5 +5,5 @@
5
5
  * graph through the barrel (which re-exports the ggui render arm until its
6
6
  * retirement — conformance-map step 4).
7
7
  */
8
- export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultUiResource, uiLocator, type McpUiResourcePayload, } from "./block-ui.js";
8
+ export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultLocator, toolResultUiResource, uiLocator, type McpUiResourcePayload, } from "./block-ui.js";
9
9
  //# sourceMappingURL=narrowing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"narrowing.d.ts","sourceRoot":"","sources":["../src/narrowing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,4BAA4B,EAC5B,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,EACT,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"narrowing.d.ts","sourceRoot":"","sources":["../src/narrowing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,4BAA4B,EAC5B,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC"}
package/dist/narrowing.js CHANGED
@@ -5,4 +5,4 @@
5
5
  * graph through the barrel (which re-exports the ggui render arm until its
6
6
  * retirement — conformance-map step 4).
7
7
  */
8
- export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultUiResource, uiLocator, } from "./block-ui.js";
8
+ export { asResourcePayload, asUiResource, blockUiResource, isJsonObject, resourceHtml, scanProviderRawForUiResource, snapshotUiResource, toolResultLocator, toolResultUiResource, uiLocator, } from "./block-ui.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guuey/mcp-apps-host",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "The MCP Apps (SEP-1865) Host role for guuey's chat surfaces — view-mount narrowing across UI channels, ui:// locator rehydration by resources/read, and the sandbox-trust channel contract. Vendor-neutral: any spec-following MCP App mounts through it.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/action.ts CHANGED
@@ -47,11 +47,39 @@ export type McpToolCallResult = {
47
47
  };
48
48
 
49
49
  /**
50
- * The runtime-action tools a card sandbox may relay — the client-side twin
51
- * of the server allowlist (defense in depth: the proxy enforces it again).
50
+ * The runtime tools a card sandbox may RELAY over `tools/call` — the
51
+ * client-side twin of the server allowlist (defense in depth: the proxy
52
+ * enforces it again). Exactly ggui's iframe-runtime surface, all declared
53
+ * `_meta.ui.visibility: ['app']` (never model-callable):
54
+ *
55
+ * - `ggui_runtime_submit_action` — the user's gesture (the SEMANTIC one);
56
+ * - `ggui_runtime_refresh_ws_token` — live-channel credential refresh
57
+ * (the wsToken TTL is 180 s; without the relay a view on SSE/polling
58
+ * dies at that mark — guuey#220);
59
+ * - `ggui_runtime_pull` — the host-relayed polling rung where the
60
+ * sandbox's own transports are blocked (bridge-pull, terminal rung).
61
+ *
62
+ * Two of these are transport plumbing whose arguments are opaque runtime
63
+ * state — see {@link UI_SEMANTIC_ACTION_TOOLS} for the ONLY set a host may
64
+ * treat as "the user did something".
52
65
  */
53
66
  export const UI_ACTION_TOOLS: ReadonlySet<string> = new Set([
54
67
  "ggui_runtime_submit_action",
68
+ "ggui_runtime_refresh_ws_token",
69
+ "ggui_runtime_pull",
70
+ ]);
71
+
72
+ /**
73
+ * The strict subset of {@link UI_ACTION_TOOLS} that carries a USER gesture —
74
+ * the only calls a host may project into user-facing affordances (composer
75
+ * staging, "the user selected X" copy, telemetry as intent). Every other
76
+ * relayed tool is runtime plumbing whose payload must NEVER reach the user
77
+ * verbatim (guuey#215/#218: a staged `sessionId …` was exactly that leak).
78
+ * A tool that is relayable is NOT thereby semantic; a host that widens
79
+ * this set is asserting the wire semantics of the new name.
80
+ */
81
+ export const UI_SEMANTIC_ACTION_TOOLS: ReadonlySet<string> = new Set([
82
+ "ggui_runtime_submit_action",
55
83
  ]);
56
84
 
57
85
  /** The in-band answer for anything the relay cannot (or will not) do. */
package/src/block-ui.ts CHANGED
@@ -175,6 +175,27 @@ export function uiLocator(uiData: JsonValue | undefined): string | undefined {
175
175
  return typeof uri === "string" && uri.startsWith("ui://") ? uri : undefined;
176
176
  }
177
177
 
178
+ /**
179
+ * The `ui://` locator a `tool-result` block carries, from EITHER channel it
180
+ * can arrive on — the single seam every locator reader goes through.
181
+ *
182
+ * AgJSON §2.1 routes a tool result's `structuredContent` by its `_meta.ui`
183
+ * sibling: WITH the sibling it is surface data and the normalizer stamps
184
+ * `uiData`; WITHOUT it, it is model-channel data and lands in
185
+ * `structuredContent`. A producer that withholds `_meta` (ggui's non-prod
186
+ * posture; any plain-locator MCP server) therefore delivers a locator that
187
+ * is byte-identical in shape but lives one field over — reading `uiData`
188
+ * alone renders NOTHING for it (dark, not "expired"), and the persistence
189
+ * projector minted no placeholder row (the read plane 404s). `uiData` wins
190
+ * when both carry one (guuey#209 route-A finding).
191
+ */
192
+ export function toolResultLocator(block: {
193
+ uiData?: JsonValue;
194
+ structuredContent?: JsonValue;
195
+ }): string | undefined {
196
+ return uiLocator(block.uiData) ?? uiLocator(block.structuredContent);
197
+ }
198
+
178
199
  export function snapshotUiResource(cardSnapshot: JsonValue): McpUiResourcePayload | undefined {
179
200
  if (!isJsonObject(cardSnapshot)) return undefined;
180
201
  const parts = cardSnapshot.parts;
package/src/card-mount.ts CHANGED
@@ -33,7 +33,7 @@
33
33
  * keeps that one narrowing in one place — the alternative was for every host
34
34
  * to re-run `toolResultGguiRender` beside this call and ask again.
35
35
  */
36
- import { snapshotUiResource, toolResultUiResource, uiLocator, type McpUiResourcePayload } from "./block-ui.js";
36
+ import { snapshotUiResource, toolResultLocator, toolResultUiResource, type McpUiResourcePayload } from "./block-ui.js";
37
37
  import { GGUI_RENDER_META_KEY, gguiRenderResource, toolResultGguiRender } from "./ggui-render.js";
38
38
  import type { AgBlock, JsonValue } from "@silverprotocol/core";
39
39
 
@@ -56,7 +56,9 @@ export type ViewMountChannel = "inline" | "ggui" | "locator";
56
56
  * `"ggui"` — a shell that boots the ggui runtime from a platform-pinned
57
57
  * origin, and therefore needs a host page whose CSP allows that origin.
58
58
  * `"locator"` — no mount material in hand, only the durable `ui://`
59
- * identity (guuey#122): the host resolves it with a fresh, authenticated
59
+ * identity (guuey#122) read from `uiData` OR, for a producer that
60
+ * withheld `_meta` (AgJSON §2.1 then routes it to `structuredContent`),
61
+ * from `structuredContent` (guuey#209): the host resolves it with a fresh, authenticated
60
62
  * `resources/read` of the uri ({@link UiResourceReader}) — the spec-consistent
61
63
  * template fetch, vendor-neutral. (The spec defers persistence/restoration
62
64
  * itself; a full remount additionally owes the View `ui/notifications/tool-input`
@@ -79,7 +81,7 @@ export interface ResolvedViewMount {
79
81
  /** The durable-identity arm: no mount material, only the uri to re-fetch. */
80
82
  export interface LocatorViewMount {
81
83
  channel: "locator";
82
- /** The persisted `uiData.resourceUri` (`ui://` scheme) to re-fetch. */
84
+ /** The durable `ui://` locator to re-fetch (`uiData.resourceUri`, else `structuredContent.resourceUri`). */
83
85
  resourceUri: string;
84
86
  }
85
87
 
@@ -108,8 +110,10 @@ export function toolResultViewMount(
108
110
  const resource = ggui ? gguiRenderResource(ggui) : undefined;
109
111
  if (resource) return { resource, channel: "ggui" };
110
112
  // A live locator whose mount material didn't reach us (a fold that
111
- // dropped `_meta`): re-fetch works on live turns too — the resource is
112
- // freshly minted (guuey#122). One diagnostic when `_meta` DID carry the
113
+ // dropped `_meta`, or a producer that never sent it — the locator then
114
+ // rides `structuredContent`, see `toolResultLocator`): re-fetch works on
115
+ // live turns too — the resource is freshly minted (guuey#122). One
116
+ // diagnostic when `_meta` DID carry the
113
117
  // vendor key but failed validation — a producer bug would otherwise be
114
118
  // indistinguishable from a meta-less fold (blank UI, zero errors).
115
119
  if (ggui && !ggui.bootstrap && blockCarriesGguiMetaKey(block)) {
@@ -117,7 +121,7 @@ export function toolResultViewMount(
117
121
  `mcp-apps-host: tool result ${block.toolCallId} carries a malformed ggui render bootstrap — degrading to the locator channel`,
118
122
  );
119
123
  }
120
- const locator = uiLocator(block.uiData);
124
+ const locator = toolResultLocator(block);
121
125
  return locator !== undefined ? { channel: "locator", resourceUri: locator } : undefined;
122
126
  }
123
127
 
@@ -137,7 +141,7 @@ export function snapshotViewMount(cardSnapshot: JsonValue): ViewMount | undefine
137
141
  for (const block of snapshotBlocks(cardSnapshot)) {
138
142
  if (typeof block !== "object" || block === null || Array.isArray(block)) continue;
139
143
  if (block.type !== "tool-result") continue;
140
- const locator = uiLocator(block.uiData);
144
+ const locator = toolResultLocator(block);
141
145
  if (locator !== undefined) return { channel: "locator", resourceUri: locator };
142
146
  }
143
147
  return undefined;
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ export {
11
11
  resourceHtml,
12
12
  scanProviderRawForUiResource,
13
13
  snapshotUiResource,
14
+ toolResultLocator,
14
15
  toolResultUiResource,
15
16
  uiLocator,
16
17
  type McpUiResourcePayload,
@@ -49,6 +50,7 @@ export {
49
50
  unavailableToolCallResult,
50
51
  UI_ACTION_TOOLS,
51
52
  UI_ACTION_UNAVAILABLE_TEXT,
53
+ UI_SEMANTIC_ACTION_TOOLS,
52
54
  type CreateMcpUiActionRelayDeps,
53
55
  type McpToolCallContent,
54
56
  type McpToolCallResult,
package/src/narrowing.ts CHANGED
@@ -13,6 +13,7 @@ export {
13
13
  resourceHtml,
14
14
  scanProviderRawForUiResource,
15
15
  snapshotUiResource,
16
+ toolResultLocator,
16
17
  toolResultUiResource,
17
18
  uiLocator,
18
19
  type McpUiResourcePayload,