@womp/mcp-ui 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -57,9 +57,11 @@ _meta: { ui: { resourceUri: IMAGE_APP_URI }, "ui/resourceUri": IMAGE_APP_URI },
57
57
 
58
58
  `get_generation` additionally needs `visibility: ["model", "app"]` — see below.
59
59
 
60
- The cards consume swan-backend's existing `GENERATION_OUTPUT_SCHEMA`
61
- (`status` / `generationId` / `operationId` / `imageUrl` / `glbUrl` /
62
- `previewUrl`) unchanged, so no server contract changes are required.
60
+ The cards read swan-backend's `GENERATION_OUTPUT_SCHEMA`: `status` /
61
+ `generationId` / `operationId` / `imageUrl` / `glbUrl` / `previewUrl`, plus
62
+ `model` and `durationSeconds` for the meta line described below. Every field is
63
+ optional except `status`, so a card is safe against a backend that predates any
64
+ of them — it just renders less.
63
65
 
64
66
  ## Things that will waste your day if you don't know them
65
67
 
@@ -143,6 +145,25 @@ replaced a day of MCP Tasks work with a polling loop.
143
145
  **`get_generation` must declare `visibility: ["model", "app"]`.** Without
144
146
  `"app"` the host refuses the call and the running state never resolves.
145
147
 
148
+ ### What the card shows about a result
149
+
150
+ The line under the image is `8.77s · Nano Banana 2` — `durationSeconds` and
151
+ `model`, formatted the way swan-frontend's generation tile does
152
+ (`OperationModelTags.tsx`), two decimals included.
153
+
154
+ - **`durationSeconds` is the provider's own `stats.generation_time`**, not
155
+ wall-clock from the tool call. Queue wait is excluded, which is what makes it
156
+ the same number the Womp app shows for the same generation. Backend note: for
157
+ `generate_image` it comes off the result in hand rather than the DB row, since
158
+ `Operation.ext.stats` is written *after* the history resolves.
159
+ - **It is one of two lines, not one.** `#meta` is what produced the result;
160
+ `#status` is when something went wrong. They shared an element once and a
161
+ preview error erased the model name, or the reverse, depending on which
162
+ landed last. Both collapse when empty.
163
+ - **There is no generationId chip.** It was the first thing on the card and it
164
+ is an internal id: it means nothing to the reader, and the model gets it from
165
+ the tool's text response. Removed in 0.2.0.
166
+
146
167
  ### Display modes
147
168
 
148
169
  `ctx.displayMode` is `inline` | `fullscreen` | `pip`. Cards are capped narrow
@@ -152,23 +173,51 @@ useless until CSS started keying off `:root[data-display-mode="fullscreen"]`.
152
173
 
153
174
  ## Development
154
175
 
155
- swan-backend cannot be run locally, so the repo ships its own harness.
176
+ **Do not iterate through Claude.** A card change reaches a connector only after
177
+ an npm publish, a swan-backend bump, a deploy, and a remove-and-re-add of the
178
+ connector. The repo ships its own host so that loop is only needed to confirm
179
+ the finished thing.
156
180
 
157
181
  ```bash
158
182
  yarn install
159
- yarn build # build:ui (two vite passes) + build:bake
160
183
  yarn dev:mcp # stub MCP server on :3001 with fake slow generations
184
+ yarn dev # vite; opens the harness at /dev/host/index.html
161
185
  ```
162
186
 
163
- `FAKE_DURATION_MS=8000` controls how long a fake generation takes, so the
164
- running → complete transition is actually exercised.
187
+ Two terminals, then edit `src/` and watch the card hot-reload.
188
+
189
+ ### The harness (`dev/host/`)
190
+
191
+ A real MCP Apps host: `AppBridge` from `@modelcontextprotocol/ext-apps`, driving
192
+ the card in an iframe and proxying its tool calls to the stub. Buttons for
193
+ card (image/mesh), tool call, theme, and display mode; a log of every message
194
+ that crosses the bridge.
195
+
196
+ It is deliberately faithful where being unfaithful would hide a bug:
197
+
198
+ | It reproduces | So you catch |
199
+ |---|---|
200
+ | iframe mounted hidden until `initialized` + a size report | a card that never calls `app.connect()` and is invisible in Claude |
201
+ | host style variables sent **only** over the bridge (and a toggle to withhold them) | a `var()` shipped without a fallback |
202
+ | the card's own `get_generation` polling, proxied to a real MCP server | a running state that never resolves |
203
+ | **"built resource" mode** — the exact HTML `resources/read` returns, in a sandboxed opaque-origin iframe | an asset `vite-plugin-singlefile` failed to inline (blank card) |
204
+
205
+ `FAKE_DURATION_MS=8000 yarn dev:mcp` lengthens a fake generation, so the
206
+ running → polling → complete transition is worth watching.
207
+
208
+ **Keep the tab visible.** A backgrounded tab does not run
209
+ `requestAnimationFrame` and clamps `setTimeout`, so auto-resize stops reporting
210
+ and the card's polling crawls — both look like card bugs and are not.
211
+ Headless/software-rendered browsers may also fail to create a WebGL context, in
212
+ which case the mesh card correctly falls back to the still image.
213
+
214
+ **The sandbox CSP is Claude's own** and cannot be reproduced here: a blocked
215
+ `media.womp.com` image or GLB only shows up there. The declared CSP is printed
216
+ under the stage so it can at least be read against the URLs in play.
165
217
 
166
- **Local hosts** (nothing exposed): point VS Code or Postman at
167
- `http://localhost:3001/mcp`. Proves the card and the bridge — but **not** that
168
- Claude renders it.
218
+ ### Confirming it in Claude
169
219
 
170
- **Claude** needs a public URL, because it connects from Anthropic's cloud and
171
- cannot reach localhost:
220
+ Still needed before shipping a card, because only Claude proves Claude:
172
221
 
173
222
  ```bash
174
223
  ngrok http 3001 --url https://<reserved>.ngrok-free.dev
@@ -63,25 +63,6 @@
63
63
  .skeleton.pulsing { animation: none; }
64
64
  }
65
65
 
66
- /* Overlays float above the image, mirroring swan-frontend's generation
67
- tile rather than sitting in a bar beneath it. */
68
- .chips {
69
- position: absolute;
70
- top: 10px;
71
- left: 10px;
72
- display: flex;
73
- gap: 6px;
74
- }
75
- .chip {
76
- font-size: var(--font-text-xs-size, 11px);
77
- padding: 3px 8px;
78
- border-radius: var(--border-radius-full, 999px);
79
- background: rgba(0, 0, 0, 0.55);
80
- color: #fff;
81
- backdrop-filter: blur(6px);
82
- white-space: nowrap;
83
- }
84
-
85
66
  .actions {
86
67
  position: absolute;
87
68
  bottom: 10px;
@@ -147,12 +128,19 @@
147
128
  /* Nothing to reveal on hover when the image fills the screen. */
148
129
  :root[data-display-mode="fullscreen"] .actions { opacity: 1; }
149
130
 
150
- .status:empty { display: none; }
151
- .status {
131
+ .status:empty,
132
+ .meta:empty { display: none; }
133
+ .status,
134
+ .meta {
152
135
  font-size: var(--font-text-xs-size, 11px);
153
136
  color: var(--color-text-secondary, rgba(232, 232, 232, 0.6));
154
137
  padding: 8px 12px;
155
138
  }
139
+ /* When both are shown the pair reads as one block, so the meta line drops
140
+ its bottom padding rather than double-spacing them. */
141
+ .meta:has(+ .status:not(:empty)) {
142
+ padding-bottom: 0;
143
+ }
156
144
  </style>
157
145
  <script type="module" crossorigin>var e=Object.defineProperty,t=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},n=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),r=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r},i=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.")});(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function a(e,t,n){function r(n,r){var i;Object.defineProperty(n,"_zod",{value:n._zod??{},enumerable:!1}),(i=n._zod).traits??(i.traits=new Set),n._zod.traits.add(e),t(n,r);for(let e in o.prototype)e in n||Object.defineProperty(n,e,{value:o.prototype[e].bind(n)});n._zod.constr=o,n._zod.def=r}let i=n?.Parent??Object;class a extends i{}Object.defineProperty(a,"name",{value:e});function o(e){var t;let i=n?.Parent?new a:this;r(i,e),(t=i._zod).deferred??(t.deferred=[]);for(let e of i._zod.deferred)e();return i}return Object.defineProperty(o,"init",{value:r}),Object.defineProperty(o,Symbol.hasInstance,{value:t=>n?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,"name",{value:e}),o}function o(e){return e&&Object.assign(u,e),u}var s,c,l,u,d=t((()=>{s=Object.freeze({status:`aborted`}),c=Symbol(`zod_brand`),l=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}},u={}})),f=r({BIGINT_FORMAT_RANGES:()=>ze,Class:()=>Be,NUMBER_FORMAT_RANGES:()=>Re,aborted:()=>De,allowsEval:()=>Pe,assert:()=>re,assertEqual:()=>p,assertIs:()=>te,assertNever:()=>ne,assertNotEqual:()=>ee,assignProp:()=>ue,cached:()=>oe,captureStackTrace:()=>Ne,cleanEnum:()=>Me,cleanRegex:()=>ce,clone:()=>g,createTransparentProxy:()=>ye,defineLazy:()=>h,esc:()=>me,escapeRegex:()=>ve,extend:()=>Ce,finalizeIssue:()=>b,floatSafeRemainder:()=>le,getElementAtPath:()=>de,getEnumValues:()=>ie,getLengthableOrigin:()=>Ae,getParsedType:()=>Fe,getSizableOrigin:()=>ke,isObject:()=>he,isPlainObject:()=>ge,issue:()=>je,joinValues:()=>m,jsonStringifyReplacer:()=>ae,merge:()=>we,normalizeParams:()=>_,nullish:()=>se,numKeys:()=>_e,omit:()=>Se,optionalKeys:()=>be,partial:()=>Te,pick:()=>xe,prefixIssues:()=>y,primitiveTypes:()=>Le,promiseAllObject:()=>fe,propertyKeyTypes:()=>Ie,randomString:()=>pe,required:()=>Ee,stringifyPrimitive:()=>v,unwrapMessage:()=>Oe});function p(e){return e}function ee(e){return e}function te(e){}function ne(e){throw Error()}function re(e){}function ie(e){let t=Object.values(e).filter(e=>typeof e==`number`);return Object.entries(e).filter(([e,n])=>t.indexOf(+e)===-1).map(([e,t])=>t)}function m(e,t=`|`){return e.map(e=>v(e)).join(t)}function ae(e,t){return typeof t==`bigint`?t.toString():t}function oe(e){return{get value(){{let t=e();return Object.defineProperty(this,"value",{value:t}),t}}}}function se(e){return e==null}function ce(e){let t=+!!e.startsWith(`^`),n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}function le(e,t){let n=(e.toString().split(`.`)[1]||``).length,r=(t.toString().split(`.`)[1]||``).length,i=n>r?n:r;return Number.parseInt(e.toFixed(i).replace(`.`,``))%Number.parseInt(t.toFixed(i).replace(`.`,``))/10**i}function h(e,t,n){Object.defineProperty(e,t,{get(){{let r=n();return e[t]=r,r}},set(n){Object.defineProperty(e,t,{value:n})},configurable:!0})}function ue(e,t,n){Object.defineProperty(e,t,{value:n,writable:!0,enumerable:!0,configurable:!0})}function de(e,t){return t?t.reduce((e,t)=>e?.[t],e):e}function fe(e){let t=Object.keys(e),n=t.map(t=>e[t]);return Promise.all(n).then(e=>{let n={};for(let r=0;r<t.length;r++)n[t[r]]=e[r];return n})}function pe(e=10){let t=``;for(let n=0;n<e;n++)t+=`abcdefghijklmnopqrstuvwxyz`[Math.floor(Math.random()*26)];return t}function me(e){return JSON.stringify(e)}function he(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ge(e){if(he(e)===!1)return!1;let t=e.constructor;if(t===void 0)return!0;let n=t.prototype;return he(n)!==!1&&Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)!==!1}function _e(e){let t=0;for(let n in e)Object.prototype.hasOwnProperty.call(e,n)&&t++;return t}function ve(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function g(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function _(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error("Cannot specify both `message` and `error` params");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function ye(e){let t;return new Proxy({},{get(n,r,i){return t??=e(),Reflect.get(t,r,i)},set(n,r,i,a){return t??=e(),Reflect.set(t,r,i,a)},has(n,r){return t??=e(),Reflect.has(t,r)},deleteProperty(n,r){return t??=e(),Reflect.deleteProperty(t,r)},ownKeys(n){return t??=e(),Reflect.ownKeys(t)},getOwnPropertyDescriptor(n,r){return t??=e(),Reflect.getOwnPropertyDescriptor(t,r)},defineProperty(n,r,i){return t??=e(),Reflect.defineProperty(t,r,i)}})}function v(e){return typeof e==`bigint`?e.toString()+`n`:typeof e==`string`?`"${e}"`:`${e}`}function be(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}function xe(e,t){let n={},r=e._zod.def;for(let e in t){if(!(e in r.shape))throw Error(`Unrecognized key: "${e}"`);t[e]&&(n[e]=r.shape[e])}return g(e,{...e._zod.def,shape:n,checks:[]})}function Se(e,t){let n={...e._zod.def.shape},r=e._zod.def;for(let e in t){if(!(e in r.shape))throw Error(`Unrecognized key: "${e}"`);t[e]&&delete n[e]}return g(e,{...e._zod.def,shape:n,checks:[]})}function Ce(e,t){if(!ge(t))throw Error(`Invalid input to extend: expected a plain object`);return g(e,{...e._zod.def,get shape(){let n={...e._zod.def.shape,...t};return ue(this,`shape`,n),n},checks:[]})}function we(e,t){return g(e,{...e._zod.def,get shape(){let n={...e._zod.def.shape,...t._zod.def.shape};return ue(this,`shape`,n),n},catchall:t._zod.def.catchall,checks:[]})}function Te(e,t,n){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in r))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t])}else for(let t in r)i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t];return g(t,{...t._zod.def,shape:i,checks:[]})}function Ee(e,t,n){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in i))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=new e({type:`nonoptional`,innerType:r[t]}))}else for(let t in r)i[t]=new e({type:`nonoptional`,innerType:r[t]});return g(t,{...t._zod.def,shape:i,checks:[]})}function De(e,t=0){for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function y(e,t){return t.map(t=>{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function Oe(e){return typeof e==`string`?e:e?.message}function b(e,t,n){let r={...e,path:e.path??[]};return e.message||(r.message=Oe(e.inst?._zod.def?.error?.(e))??Oe(t?.error?.(e))??Oe(n.customError?.(e))??Oe(n.localeError?.(e))??`Invalid input`),delete r.inst,delete r.continue,t?.reportInput||delete r.input,r}function ke(e){return e instanceof Set?`set`:e instanceof Map?`map`:e instanceof File?`file`:`unknown`}function Ae(e){return Array.isArray(e)?`array`:typeof e==`string`?`string`:`unknown`}function je(...e){let[t,n,r]=e;return typeof t==`string`?{message:t,code:`custom`,input:n,inst:r}:{...t}}function Me(e){return Object.entries(e).filter(([e,t])=>Number.isNaN(Number.parseInt(e,10))).map(e=>e[1])}var Ne,Pe,Fe,Ie,Le,Re,ze,Be,x=t((()=>{Ne=Error.captureStackTrace?Error.captureStackTrace:(...e)=>{},Pe=oe(()=>{if(typeof navigator<`u`&&navigator?.userAgent?.includes(`Cloudflare`))return!1;try{return Function(``),!0}catch{return!1}}),Fe=e=>{let t=typeof e;switch(t){case`undefined`:return`undefined`;case`string`:return`string`;case`number`:return Number.isNaN(e)?`nan`:`number`;case`boolean`:return`boolean`;case`function`:return`function`;case`bigint`:return`bigint`;case`symbol`:return`symbol`;case`object`:return Array.isArray(e)?`array`:e===null?`null`:e.then&&typeof e.then==`function`&&e.catch&&typeof e.catch==`function`?`promise`:typeof Map<`u`&&e instanceof Map?`map`:typeof Set<`u`&&e instanceof Set?`set`:typeof Date<`u`&&e instanceof Date?`date`:typeof File<`u`&&e instanceof File?`file`:`object`;default:throw Error(`Unknown data type: ${t}`)}},Ie=new Set([`string`,`number`,`symbol`]),Le=new Set([`string`,`number`,`bigint`,`boolean`,`symbol`,`undefined`]),Re={safeint:[-(2**53-1),2**53-1],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]},ze={int64:[BigInt(`-9223372036854775808`),BigInt(`9223372036854775807`)],uint64:[BigInt(0),BigInt(`18446744073709551615`)]},Be=class{constructor(...e){}}}));function Ve(e,t=e=>e.message){let n={},r=[];for(let i of e.issues)i.path.length>0?(n[i.path[0]]=n[i.path[0]]||[],n[i.path[0]].push(t(i))):r.push(t(i));return{formErrors:r,fieldErrors:n}}function He(e,t){let n=t||function(e){return e.message},r={_errors:[]},i=e=>{for(let t of e.issues)if(t.code===`invalid_union`&&t.errors.length)t.errors.map(e=>i({issues:e}));else if(t.code===`invalid_key`)i({issues:t.issues});else if(t.code===`invalid_element`)i({issues:t.issues});else if(t.path.length===0)r._errors.push(n(t));else{let e=r,i=0;for(;i<t.path.length;){let r=t.path[i];i===t.path.length-1?(e[r]=e[r]||{_errors:[]},e[r]._errors.push(n(t))):e[r]=e[r]||{_errors:[]},e=e[r],i++}}};return i(e),r}function Ue(e,t){let n=t||function(e){return e.message},r={errors:[]},i=(e,t=[])=>{var a,o;for(let s of e.issues)if(s.code===`invalid_union`&&s.errors.length)s.errors.map(e=>i({issues:e},s.path));else if(s.code===`invalid_key`)i({issues:s.issues},s.path);else if(s.code===`invalid_element`)i({issues:s.issues},s.path);else{let e=[...t,...s.path];if(e.length===0){r.errors.push(n(s));continue}let i=r,c=0;for(;c<e.length;){let t=e[c],r=c===e.length-1;typeof t==`string`?(i.properties??(i.properties={}),(a=i.properties)[t]??(a[t]={errors:[]}),i=i.properties[t]):(i.items??(i.items=[]),(o=i.items)[t]??(o[t]={errors:[]}),i=i.items[t]),r&&i.errors.push(n(s)),c++}}};return i(e),r}function We(e){let t=[];for(let n of e)typeof n==`number`?t.push(`[${n}]`):typeof n==`symbol`?t.push(`[${JSON.stringify(String(n))}]`):/[^\w$]/.test(n)?t.push(`[${JSON.stringify(n)}]`):(t.length&&t.push(`.`),t.push(n));return t.join(``)}function Ge(e){let t=[],n=[...e.issues].sort((e,t)=>e.path.length-t.path.length);for(let e of n)t.push(`✖ ${e.message}`),e.path?.length&&t.push(` → at ${We(e.path)}`);return t.join(`
158
146
  `)}var Ke,qe,Je,Ye=t((()=>{d(),x(),Ke=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,"_zod",{value:e._zod,enumerable:!1}),Object.defineProperty(e,"issues",{value:t,enumerable:!1}),Object.defineProperty(e,"message",{get(){return JSON.stringify(t,ae,2)},enumerable:!0}),Object.defineProperty(e,"toString",{value:()=>e.message,enumerable:!1})},qe=a(`$ZodError`,Ke),Je=a(`$ZodError`,Ke,{Parent:Error})})),Xe,Ze,Qe,$e,et,tt,nt,rt,it=t((()=>{d(),Ye(),x(),Xe=e=>(t,n,r,i)=>{let a=r?Object.assign(r,{async:!1}):{async:!1},s=t._zod.run({value:n,issues:[]},a);if(s instanceof Promise)throw new l;if(s.issues.length){let t=new((i?.Err)??e)(s.issues.map(e=>b(e,a,o())));throw Ne(t,i?.callee),t}return s.value},Ze=Xe(Je),Qe=e=>async(t,n,r,i)=>{let a=r?Object.assign(r,{async:!0}):{async:!0},s=t._zod.run({value:n,issues:[]},a);if(s instanceof Promise&&(s=await s),s.issues.length){let t=new((i?.Err)??e)(s.issues.map(e=>b(e,a,o())));throw Ne(t,i?.callee),t}return s.value},$e=Qe(Je),et=e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new l;return a.issues.length?{success:!1,error:new(e??qe)(a.issues.map(e=>b(e,i,o())))}:{success:!0,data:a.value}},tt=et(Je),nt=e=>async(t,n,r)=>{let i=r?Object.assign(r,{async:!0}):{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>b(e,i,o())))}:{success:!0,data:a.value}},rt=nt(Je)})),at=r({_emoji:()=>Ot,base64:()=>Nt,base64url:()=>Pt,bigint:()=>Vt,boolean:()=>Wt,browserEmail:()=>Dt,cidrv4:()=>jt,cidrv6:()=>Mt,cuid:()=>ut,cuid2:()=>dt,date:()=>zt,datetime:()=>lt,domain:()=>It,duration:()=>gt,e164:()=>Lt,email:()=>Ct,emoji:()=>ot,extendedDuration:()=>_t,guid:()=>vt,hostname:()=>Ft,html5Email:()=>wt,integer:()=>Ht,ipv4:()=>kt,ipv6:()=>At,ksuid:()=>mt,lowercase:()=>qt,nanoid:()=>ht,null:()=>Gt,number:()=>Ut,rfc5322Email:()=>Tt,string:()=>Bt,time:()=>ct,ulid:()=>ft,undefined:()=>Kt,unicodeEmail:()=>Et,uppercase:()=>Jt,uuid:()=>yt,uuid4:()=>bt,uuid6:()=>xt,uuid7:()=>St,xid:()=>pt});function ot(){return new RegExp(Ot,`u`)}function st(e){let t=`(?:[01]\\d|2[0-3]):[0-5]\\d`;return typeof e.precision==`number`?e.precision===-1?`${t}`:e.precision===0?`${t}:[0-5]\\d`:`${t}:[0-5]\\d\\.\\d{${e.precision}}`:`${t}(?::[0-5]\\d(?:\\.\\d+)?)?`}function ct(e){return RegExp(`^${st(e)}$`)}function lt(e){let t=st({precision:e.precision}),n=[`Z`];e.local&&n.push(``),e.offset&&n.push(`([+-]\\d{2}:\\d{2})`);let r=`${t}(?:${n.join(`|`)})`;return RegExp(`^${Rt}T(?:${r})$`)}var ut,dt,ft,pt,mt,ht,gt,_t,vt,yt,bt,xt,St,Ct,wt,Tt,Et,Dt,Ot,kt,At,jt,Mt,Nt,Pt,Ft,It,Lt,Rt,zt,Bt,Vt,Ht,Ut,Wt,Gt,Kt,qt,Jt,Yt=t((()=>{ut=/^[cC][^\s-]{8,}$/,dt=/^[0-9a-z]+$/,ft=/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,pt=/^[0-9a-vA-V]{20}$/,mt=/^[A-Za-z0-9]{27}$/,ht=/^[a-zA-Z0-9_-]{21}$/,gt=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,_t=/^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/,vt=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,yt=e=>e?RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${e}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$/,bt=yt(4),xt=yt(6),St=yt(7),Ct=/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,wt=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,Tt=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,Et=/^[^\s@"]{1,64}@[^\s@]{1,255}$/u,Dt=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,Ot=`^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`,kt=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,At=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$/,jt=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,Mt=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,Nt=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,Pt=/^[A-Za-z0-9_-]*$/,Ft=/^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$/,It=/^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/,Lt=/^\+(?:[0-9]){6,14}[0-9]$/,Rt=`(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`,zt=RegExp(`^${Rt}$`),Bt=e=>{let t=e?`[\\s\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\s\\S]*`;return RegExp(`^${t}$`)},Vt=/^\d+n?$/,Ht=/^\d+$/,Ut=/^-?\d+(?:\.\d+)?/i,Wt=/true|false/i,Gt=/null/i,Kt=/undefined/i,qt=/^[^A-Z]*$/,Jt=/^[^a-z]*$/}));function Xt(e,t,n){e.issues.length&&t.issues.push(...y(n,e.issues))}var S,Zt,Qt,$t,en,tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn,hn,gn,_n,vn,yn,bn=t((()=>{d(),Yt(),x(),S=a(`$ZodCheck`,(e,t)=>{var n;e._zod??={},e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])}),Zt={number:`number`,bigint:`bigint`,object:`date`},Qt=a(`$ZodCheckLessThan`,(e,t)=>{S.init(e,t);let n=Zt[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.maximum:n.exclusiveMaximum)??1/0;t.value<r&&(t.inclusive?n.maximum=t.value:n.exclusiveMaximum=t.value)}),e._zod.check=r=>{(t.inclusive?r.value<=t.value:r.value<t.value)||r.issues.push({origin:n,code:`too_big`,maximum:t.value,input:r.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),$t=a(`$ZodCheckGreaterThan`,(e,t)=>{S.init(e,t);let n=Zt[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.minimum:n.exclusiveMinimum)??-1/0;t.value>r&&(t.inclusive?n.minimum=t.value:n.exclusiveMinimum=t.value)}),e._zod.check=r=>{(t.inclusive?r.value>=t.value:r.value>t.value)||r.issues.push({origin:n,code:`too_small`,minimum:t.value,input:r.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),en=a(`$ZodCheckMultipleOf`,(e,t)=>{S.init(e,t),e._zod.onattach.push(e=>{var n;(n=e._zod.bag).multipleOf??(n.multipleOf=t.value)}),e._zod.check=n=>{if(typeof n.value!=typeof t.value)throw Error(`Cannot mix number and bigint in multiple_of check.`);(typeof n.value==`bigint`?n.value%t.value===BigInt(0):le(n.value,t.value)===0)||n.issues.push({origin:typeof n.value,code:`not_multiple_of`,divisor:t.value,input:n.value,inst:e,continue:!t.abort})}}),tn=a(`$ZodCheckNumberFormat`,(e,t)=>{S.init(e,t),t.format=t.format||`float64`;let n=t.format?.includes(`int`),r=n?`int`:`number`,[i,a]=Re[t.format];e._zod.onattach.push(e=>{let r=e._zod.bag;r.format=t.format,r.minimum=i,r.maximum=a,n&&(r.pattern=Ht)}),e._zod.check=o=>{let s=o.value;if(n){if(!Number.isInteger(s)){o.issues.push({expected:r,format:t.format,code:`invalid_type`,input:s,inst:e});return}if(!Number.isSafeInteger(s)){s>0?o.issues.push({input:s,code:`too_big`,maximum:2**53-1,note:`Integers must be within the safe integer range.`,inst:e,origin:r,continue:!t.abort}):o.issues.push({input:s,code:`too_small`,minimum:-(2**53-1),note:`Integers must be within the safe integer range.`,inst:e,origin:r,continue:!t.abort});return}}s<i&&o.issues.push({origin:`number`,input:s,code:`too_small`,minimum:i,inclusive:!0,inst:e,continue:!t.abort}),s>a&&o.issues.push({origin:`number`,input:s,code:`too_big`,maximum:a,inst:e})}}),nn=a(`$ZodCheckBigIntFormat`,(e,t)=>{S.init(e,t);let[n,r]=ze[t.format];e._zod.onattach.push(e=>{let i=e._zod.bag;i.format=t.format,i.minimum=n,i.maximum=r}),e._zod.check=i=>{let a=i.value;a<n&&i.issues.push({origin:`bigint`,input:a,code:`too_small`,minimum:n,inclusive:!0,inst:e,continue:!t.abort}),a>r&&i.issues.push({origin:`bigint`,input:a,code:`too_big`,maximum:r,inst:e})}}),rn=a(`$ZodCheckMaxSize`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.size!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.maximum??1/0;t.maximum<n&&(e._zod.bag.maximum=t.maximum)}),e._zod.check=n=>{let r=n.value;r.size<=t.maximum||n.issues.push({origin:ke(r),code:`too_big`,maximum:t.maximum,input:r,inst:e,continue:!t.abort})}}),an=a(`$ZodCheckMinSize`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.size!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;r.size>=t.minimum||n.issues.push({origin:ke(r),code:`too_small`,minimum:t.minimum,input:r,inst:e,continue:!t.abort})}}),on=a(`$ZodCheckSizeEquals`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.size!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag;n.minimum=t.size,n.maximum=t.size,n.size=t.size}),e._zod.check=n=>{let r=n.value,i=r.size;if(i===t.size)return;let a=i>t.size;n.issues.push({origin:ke(r),...a?{code:`too_big`,maximum:t.size}:{code:`too_small`,minimum:t.size},inclusive:!0,exact:!0,input:n.value,inst:e,continue:!t.abort})}}),sn=a(`$ZodCheckMaxLength`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.maximum??1/0;t.maximum<n&&(e._zod.bag.maximum=t.maximum)}),e._zod.check=n=>{let r=n.value;if(r.length<=t.maximum)return;let i=Ae(r);n.issues.push({origin:i,code:`too_big`,maximum:t.maximum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),cn=a(`$ZodCheckMinLength`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;if(r.length>=t.minimum)return;let i=Ae(r);n.issues.push({origin:i,code:`too_small`,minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),ln=a(`$ZodCheckLengthEquals`,(e,t)=>{var n;S.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!se(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag;n.minimum=t.length,n.maximum=t.length,n.length=t.length}),e._zod.check=n=>{let r=n.value,i=r.length;if(i===t.length)return;let a=Ae(r),o=i>t.length;n.issues.push({origin:a,...o?{code:`too_big`,maximum:t.length}:{code:`too_small`,minimum:t.length},inclusive:!0,exact:!0,input:n.value,inst:e,continue:!t.abort})}}),un=a(`$ZodCheckStringFormat`,(e,t)=>{var n,r;S.init(e,t),e._zod.onattach.push(e=>{let n=e._zod.bag;n.format=t.format,t.pattern&&(n.patterns??=new Set,n.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:t.format,input:n.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(r=e._zod).check??(r.check=()=>{})}),dn=a(`$ZodCheckRegex`,(e,t)=>{un.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:`regex`,input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),fn=a(`$ZodCheckLowerCase`,(e,t)=>{t.pattern??=qt,un.init(e,t)}),pn=a(`$ZodCheckUpperCase`,(e,t)=>{t.pattern??=Jt,un.init(e,t)}),mn=a(`$ZodCheckIncludes`,(e,t)=>{S.init(e,t);let n=ve(t.includes),r=new RegExp(typeof t.position==`number`?`^.{${t.position}}${n}`:n);t.pattern=r,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(r)}),e._zod.check=n=>{n.value.includes(t.includes,t.position)||n.issues.push({origin:`string`,code:`invalid_format`,format:`includes`,includes:t.includes,input:n.value,inst:e,continue:!t.abort})}}),hn=a(`$ZodCheckStartsWith`,(e,t)=>{S.init(e,t);let n=RegExp(`^${ve(t.prefix)}.*`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.startsWith(t.prefix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`starts_with`,prefix:t.prefix,input:n.value,inst:e,continue:!t.abort})}}),gn=a(`$ZodCheckEndsWith`,(e,t)=>{S.init(e,t);let n=RegExp(`.*${ve(t.suffix)}$`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.endsWith(t.suffix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`ends_with`,suffix:t.suffix,input:n.value,inst:e,continue:!t.abort})}}),_n=a(`$ZodCheckProperty`,(e,t)=>{S.init(e,t),e._zod.check=e=>{let n=t.schema._zod.run({value:e.value[t.property],issues:[]},{});if(n instanceof Promise)return n.then(n=>Xt(n,e,t.property));Xt(n,e,t.property)}}),vn=a(`$ZodCheckMimeType`,(e,t)=>{S.init(e,t);let n=new Set(t.mime);e._zod.onattach.push(e=>{e._zod.bag.mime=t.mime}),e._zod.check=r=>{n.has(r.value.type)||r.issues.push({code:`invalid_value`,values:t.mime,input:r.value.type,inst:e})}}),yn=a(`$ZodCheckOverwrite`,(e,t)=>{S.init(e,t),e._zod.check=e=>{e.value=t.tx(e.value)}})})),xn,Sn=t((()=>{xn=class{constructor(e=[]){this.content=[],this.indent=0,this&&(this.args=e)}indented(e){this.indent+=1,e(this),--this.indent}write(e){if(typeof e==`function`){e(this,{execution:`sync`}),e(this,{execution:`async`});return}let t=e.split(`
@@ -228,18 +216,13 @@ Boolean requesting whether a visible border and background is provided by the ho
228
216
  - omitted: host decides border`)}),F({method:B(`ui/request-display-mode`),params:F({mode:Uh.describe(`The display mode being requested.`)})}),og=F({mode:Uh.describe(`The display mode that was actually set. May differ from requested if not supported.`)}).passthrough(),sg=L([B(`model`),B(`app`)]).describe(`Tool visibility scope - who can access the tool.`),F({resourceUri:A().optional(),visibility:P(sg).optional().describe(`Who can access this tool. Default: ["model", "app"]
229
217
  - "model": Tool visible to and callable by the agent
230
218
  - "app": Tool callable by the app from this server only`),csp:Hl().optional(),permissions:Hl().optional()}),F({mimeTypes:P(A()).optional().describe('Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.')}),F({method:B(`ui/download-file`),params:F({contents:P(L([kp,Ap])).describe(`Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types.`)})}),F({method:B(`ui/message`),params:F({role:B(`user`).describe(`Message role, currently only "user" is supported.`),content:P(jp).describe(`Message content blocks (text, image, etc.).`)})}),F({method:B(`ui/notifications/sandbox-resource-ready`),params:F({html:A().describe(`HTML content to load into the inner iframe.`),sandbox:A().optional().describe(`Optional override for the inner iframe's sandbox attribute.`),csp:Yh.optional().describe(`CSP configuration from resource metadata.`),permissions:Xh.optional().describe(`Sandbox permissions from resource metadata.`)})}),cg=F({method:B(`ui/notifications/tool-result`),params:Bp.describe(`Standard MCP tool execution result.`)}),lg=F({toolInfo:F({id:rf.optional().describe(`JSON-RPC id of the tools/call request.`),tool:Lp.describe(`Tool definition including name, inputSchema, etc.`)}).optional().describe(`Metadata of the tool call that instantiated this App.`),theme:Hh.optional().describe(`Current color theme preference.`),styles:tg.optional().describe(`Style configuration for theming the app.`),displayMode:Uh.optional().describe(`How the UI is currently displayed.`),availableDisplayModes:P(Uh).optional().describe(`Display modes the host supports.`),containerDimensions:L([F({height:j().describe(`Fixed container height in pixels.`)}),F({maxHeight:L([j(),zl()]).optional().describe(`Maximum container height in pixels.`)})]).and(L([F({width:j().describe(`Fixed container width in pixels.`)}),F({maxWidth:L([j(),zl()]).optional().describe(`Maximum container width in pixels.`)})])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other
231
- container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:A().optional().describe(`User's language and region preference in BCP 47 format.`),timeZone:A().optional().describe(`User's timezone in IANA format.`),userAgent:A().optional().describe(`Host application identifier.`),platform:L([B(`web`),B(`desktop`),B(`mobile`)]).optional().describe(`Platform type for responsive design decisions.`),deviceCapabilities:F({touch:M().optional().describe(`Whether the device supports touch input.`),hover:M().optional().describe(`Whether the device supports hover interactions.`)}).optional().describe(`Device input capabilities.`),safeAreaInsets:F({top:j().describe(`Top safe area inset in pixels.`),right:j().describe(`Right safe area inset in pixels.`),bottom:j().describe(`Bottom safe area inset in pixels.`),left:j().describe(`Left safe area inset in pixels.`)}).optional().describe(`Mobile safe area boundaries in pixels.`)}).passthrough(),ug=F({method:B(`ui/notifications/host-context-changed`),params:lg.describe(`Partial context update containing only changed fields.`)}),F({method:B(`ui/update-model-context`),params:F({content:P(jp).optional().describe(`Context content blocks (text, image, etc.).`),structuredContent:R(A(),N().describe(`Structured content for machine-readable context data.`)).optional().describe(`Structured content for machine-readable context data.`)})}),F({method:B(`ui/initialize`),params:F({appInfo:bf.describe(`App identification (name and version).`),appCapabilities:ag.describe(`Features and capabilities this app provides.`),protocolVersion:A().describe(`Protocol version this app supports.`)})}),dg=F({protocolVersion:A().describe(`Negotiated protocol version string (e.g., "2025-11-21").`),hostInfo:bf.describe(`Host application identification and version.`),hostCapabilities:ig.describe(`Features and capabilities provided by the host.`),hostContext:lg.describe(`Rich context about the host environment.`)}).passthrough(),fg={target:`draft-2020-12`},pg=class e extends zh{_appInfo;_capabilities;options;_hostCapabilities;_hostInfo;_hostContext;_registeredTools={};_initializedSent=!1;_assertInitialized(e){if(this._initializedSent)return;let t=`[ext-apps] App.${e}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(t);console.warn(`${t}. This will throw in a future release.`)}eventSchemas={toolinput:Zh,toolinputpartial:Qh,toolresult:cg,toolcancelled:$h,hostcontextchanged:ug};static ONE_SHOT_EVENTS=new Set([`toolinput`,`toolinputpartial`,`toolresult`,`toolcancelled`]);_everHadListener=new Set;_assertHandlerTiming(t){if(!e.ONE_SHOT_EVENTS.has(t)||this._everHadListener.has(t)||(this._everHadListener.add(t),!this._initializedSent))return;let n=`[ext-apps] "${String(t)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(n);console.warn(n)}setEventHandler(e,t){t&&this._assertHandlerTiming(e),super.setEventHandler(e,t)}addEventListener(e,t){this._assertHandlerTiming(e),super.addEventListener(e,t)}onEventDispatch(e,t){e===`hostcontextchanged`&&(this._hostContext={...this._hostContext,...t})}constructor(e,t={},n={autoResize:!0}){super(n),this._appInfo=e,this._capabilities=t,this.options=n,n.allowUnsafeEval||o({jitless:!0}),this.setRequestHandler(jf,e=>(console.log(`Received ping:`,e.params),{})),this.setEventHandler(`hostcontextchanged`,void 0)}registerCapabilities(e){if(this.transport)throw Error(`Cannot register capabilities after transport is established`);this._capabilities=Dh(this._capabilities,e)}registerTool(e,t,n){if(this._registeredTools[e])throw Error(`Tool ${e} is already registered`);let r=this,i=()=>{r._initializedSent&&r._capabilities.tools?.listChanged&&r.sendToolListChanged()},a=t.inputSchema!==void 0,o={title:t.title,description:t.description,inputSchema:t.inputSchema,outputSchema:t.outputSchema,annotations:t.annotations,_meta:t._meta,enabled:!0,enable(){this.enabled=!0,i()},disable(){this.enabled=!1,i()},update(e){Object.assign(this,e),i()},remove(){r._registeredTools[e]===o&&(delete r._registeredTools[e],i())},handler:async(t,r)=>{if(!o.enabled)throw Error(`Tool ${e} is disabled`);let i;if(a){let a=o.inputSchema;i=await n(a?await Ih(a,t??{},`Invalid input for tool ${e}: `):t??{},r)}else i=await n(r);return o.outputSchema&&!i.isError&&(i.structuredContent=await Ih(o.outputSchema,i.structuredContent,`Invalid output for tool ${e}: `)),i}};return this._registeredTools[e]=o,!this._capabilities.tools&&!this.transport&&this.registerCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),i(),o}_toolHandlersInitialized=!1;ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(e,t)=>{let n=this._registeredTools[e.name];if(!n)throw Error(`Tool ${e.name} not found`);return n.handler(e.arguments,t)},this.onlisttools=async(e,t)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([e,t])=>t.enabled).map(async([e,t])=>{let n={name:e,title:t.title,description:t.description,inputSchema:t.inputSchema?await Fh(t.inputSchema,`input`):{type:`object`,properties:{}}};return t.outputSchema&&(n.outputSchema=await Fh(t.outputSchema,`output`)),t.annotations&&(n.annotations=t.annotations),t._meta&&(n._meta=t._meta),n}))}))}async sendToolListChanged(e={}){this._assertInitialized(`sendToolListChanged`),await this.notification({method:`notifications/tools/list_changed`,params:e})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler(`toolinput`)}set ontoolinput(e){this.setEventHandler(`toolinput`,e)}get ontoolinputpartial(){return this.getEventHandler(`toolinputpartial`)}set ontoolinputpartial(e){this.setEventHandler(`toolinputpartial`,e)}get ontoolresult(){return this.getEventHandler(`toolresult`)}set ontoolresult(e){this.setEventHandler(`toolresult`,e)}get ontoolcancelled(){return this.getEventHandler(`toolcancelled`)}set ontoolcancelled(e){this.setEventHandler(`toolcancelled`,e)}get onhostcontextchanged(){return this.getEventHandler(`hostcontextchanged`)}set onhostcontextchanged(e){this.setEventHandler(`hostcontextchanged`,e)}_onteardown;get onteardown(){return this._onteardown}set onteardown(e){this.warnIfRequestHandlerReplaced(`onteardown`,this._onteardown,e),this._onteardown=e,this.replaceRequestHandler(ng,(e,t)=>{if(!this._onteardown)throw Error(`No onteardown handler set`);return this._onteardown(e.params,t)})}_oncalltool;get oncalltool(){return this._oncalltool}set oncalltool(e){this.warnIfRequestHandlerReplaced(`oncalltool`,this._oncalltool,e),this._oncalltool=e,this.replaceRequestHandler(Hp,(e,t)=>{if(!this._oncalltool)throw Error(`No oncalltool handler set`);return this._oncalltool(e.params,t)})}_onlisttools;get onlisttools(){return this._onlisttools}set onlisttools(e){this.warnIfRequestHandlerReplaced(`onlisttools`,this._onlisttools,e),this._onlisttools=e,this.replaceRequestHandler(Rp,(e,t)=>{if(!this._onlisttools)throw Error(`No onlisttools handler set`);return this._onlisttools(e.params,t)})}assertCapabilityForMethod(e){if(e===`sampling/createMessage`&&!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${e})`)}assertRequestHandlerCapability(e){switch(e){case`tools/call`:case`tools/list`:if(!this._capabilities.tools)throw Error(`Client does not support tool capability (required for ${e})`);return;case`ping`:case`ui/resource-teardown`:return;default:throw Error(`No handler for method ${e} registered`)}}assertNotificationCapability(e){}assertTaskCapability(e){throw Error(`Tasks are not supported in MCP Apps`)}assertTaskHandlerCapability(e){throw Error(`Task handlers are not supported in MCP Apps`)}async callServerTool(e,t){if(this._assertInitialized(`callServerTool`),typeof e==`string`)throw Error(`callServerTool() expects an object as its first argument, but received a string ("${e}"). Did you mean: callServerTool({ name: "${e}", arguments: { ... } })?`);return await this.request({method:`tools/call`,params:e},Bp,{onprogress:()=>{},resetTimeoutOnProgress:!0,...t})}async readServerResource(e,t){return this._assertInitialized(`readServerResource`),await this.request({method:`resources/read`,params:e},dp,t)}async listServerResources(e,t){return this._assertInitialized(`listServerResources`),await this.request({method:`resources/list`,params:e},ap,t)}async createSamplingMessage(e,t){this._assertInitialized(`createSamplingMessage`);let n=e.tools?am:im;return await this.request({method:`sampling/createMessage`,params:e},n,t)}sendMessage(e,t){return this._assertInitialized(`sendMessage`),this.request({method:`ui/message`,params:e},Jh,t)}sendLog(e){return this.notification({method:`notifications/message`,params:e})}updateModelContext(e,t){return this._assertInitialized(`updateModelContext`),this.request({method:`ui/update-model-context`,params:e},mf,t)}openLink(e,t){return this._assertInitialized(`openLink`),this.request({method:`ui/open-link`,params:e},Kh,t)}sendOpenLink=this.openLink;downloadFile(e,t){return this._assertInitialized(`downloadFile`),this.request({method:`ui/download-file`,params:e},qh,t)}requestTeardown(e={}){return this.notification({method:`ui/notifications/request-teardown`,params:e})}requestDisplayMode(e,t){return this._assertInitialized(`requestDisplayMode`),this.request({method:`ui/request-display-mode`,params:e},og,t)}sendSizeChanged(e){return this.notification({method:`ui/notifications/size-changed`,params:e})}setupSizeChangedNotifications(){let e=!1,t=0,n=0,r=()=>{e||(e=!0,requestAnimationFrame(()=>{e=!1;let r=document.documentElement,i=r.style.height;r.style.height=`max-content`;let a=Math.ceil(r.getBoundingClientRect().height);r.style.height=i;let o=Math.ceil(window.innerWidth);(o!==t||a!==n)&&(t=o,n=a,this.sendSizeChanged({width:o,height:a}))}))};r();let i=new ResizeObserver(r);return i.observe(document.documentElement),i.observe(document.body),()=>i.disconnect()}async connect(e=new Vh(window.parent,window.parent),t){if(this.transport)throw Error(`App is already connected. Call close() before connecting again.`);this._initializedSent=!1,await super.connect(e);try{let e=await this.request({method:`ui/initialize`,params:{appCapabilities:this._capabilities,appInfo:this._appInfo,protocolVersion:Bh}},dg,t);if(e===void 0)throw Error(`Server sent invalid initialize result: ${e}`);this._hostCapabilities=e.hostCapabilities,this._hostInfo=e.hostInfo,this._hostContext=e.hostContext,await this.notification({method:`ui/notifications/initialized`}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(e){throw this.close(),e}}}}));function hg(e,t){let n,r=0,i,a=()=>{n!==void 0&&(clearTimeout(n),n=void 0)},o=new pg({name:e,version:`0.0.1`},{}),s=async e=>{let t=await o.request({method:`tools/call`,params:{name:`get_generation`,arguments:{operationId:e}}},Bp);if(!t.isError)return t.structuredContent},c=(e,o)=>{n=window.setTimeout(async()=>{if(Date.now()-r>bg){t.onTimeout?.();return}try{let n=await s(e);if(n?.status===`complete`){a(),i=n,t.onResult(n);return}}catch{}c(e,Math.min(o*1.5,yg))},o)},l=e=>{e&&(a(),i=e,t.onResult(e),e.status===`running`&&e.operationId!==void 0&&(r=Date.now(),c(e.operationId,vg)))};return o.ontoolinput=()=>t.onResult({status:`running`}),o.ontoolresult=e=>l(e?.structuredContent),o.onhostcontextchanged=e=>{if(e?.theme&&Lh(e.theme),e?.styles?.variables&&Rh(e.styles.variables),e?.displayMode&&(document.documentElement.dataset.displayMode=e.displayMode),e?.safeAreaInsets){let{top:t=0,right:n=0,bottom:r=0,left:i=0}=e.safeAreaInsets;document.body.style.padding=`${t}px ${n}px ${r}px ${i}px`}},o.onteardown=async()=>(a(),{}),o.connect(new Vh(window.parent,window.parent)).catch(()=>{}),{app:o,current:()=>i}}function gg(e,t){return e.openLink({url:t})}function _g(e){let t=document.documentElement.dataset.displayMode===`fullscreen`;return e.requestDisplayMode({mode:t?`inline`:`fullscreen`}).then(e=>{e?.mode&&(document.documentElement.dataset.displayMode=e.mode)})}var $,vg,yg,bg,xg=t((()=>{mg(),Fm(),$=e=>document.getElementById(e),vg=2e3,yg=1e4,bg=36e4}));n((()=>{xg();var e=e=>{$(`status`).textContent=e};function t(e,t,n){let r=$(e);r.hidden=!t,n&&(r.title=n)}var n=hg(`Womp image`,{onTimeout:()=>e(`Still running — ask me to check on it.`),onResult:n=>{if(n.status===`running`){$(`kind`).textContent=`Working`,$(`skeleton`).classList.add(`pulsing`),$(`actions`).hidden=!0,e(`Generating…`);return}$(`skeleton`).classList.remove(`pulsing`);let r=n.previewUrl||n.imageUrl;if(r){let t=$(`hero`);t.onload=()=>{$(`skeleton`).style.display=`none`,t.style.display=`block`},t.onerror=()=>e(`Preview unavailable — the file link still works.`),t.src=r}let i=!!n.glbUrl;$(`kind`).textContent=i?`3D mesh`:`Image`,n.generationId&&($(`gid`).textContent=`#`+n.generationId,$(`gid`).hidden=!1);let a=n.glbUrl||n.imageUrl;t(`download`,!!a,i?`Download GLB`:`Open full size`),t(`expand`,!!r),$(`actions`).hidden=!a&&!r,e(``)}});$(`download`).addEventListener(`click`,()=>{let t=n.current()?.glbUrl||n.current()?.imageUrl;t&&gg(n.app,t).catch(()=>e(`Could not open the link.`))}),$(`expand`).addEventListener(`click`,()=>{_g(n.app).catch(()=>e(`This host does not support fullscreen.`))})}))();</script>
219
+ container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:A().optional().describe(`User's language and region preference in BCP 47 format.`),timeZone:A().optional().describe(`User's timezone in IANA format.`),userAgent:A().optional().describe(`Host application identifier.`),platform:L([B(`web`),B(`desktop`),B(`mobile`)]).optional().describe(`Platform type for responsive design decisions.`),deviceCapabilities:F({touch:M().optional().describe(`Whether the device supports touch input.`),hover:M().optional().describe(`Whether the device supports hover interactions.`)}).optional().describe(`Device input capabilities.`),safeAreaInsets:F({top:j().describe(`Top safe area inset in pixels.`),right:j().describe(`Right safe area inset in pixels.`),bottom:j().describe(`Bottom safe area inset in pixels.`),left:j().describe(`Left safe area inset in pixels.`)}).optional().describe(`Mobile safe area boundaries in pixels.`)}).passthrough(),ug=F({method:B(`ui/notifications/host-context-changed`),params:lg.describe(`Partial context update containing only changed fields.`)}),F({method:B(`ui/update-model-context`),params:F({content:P(jp).optional().describe(`Context content blocks (text, image, etc.).`),structuredContent:R(A(),N().describe(`Structured content for machine-readable context data.`)).optional().describe(`Structured content for machine-readable context data.`)})}),F({method:B(`ui/initialize`),params:F({appInfo:bf.describe(`App identification (name and version).`),appCapabilities:ag.describe(`Features and capabilities this app provides.`),protocolVersion:A().describe(`Protocol version this app supports.`)})}),dg=F({protocolVersion:A().describe(`Negotiated protocol version string (e.g., "2025-11-21").`),hostInfo:bf.describe(`Host application identification and version.`),hostCapabilities:ig.describe(`Features and capabilities provided by the host.`),hostContext:lg.describe(`Rich context about the host environment.`)}).passthrough(),fg={target:`draft-2020-12`},pg=class e extends zh{_appInfo;_capabilities;options;_hostCapabilities;_hostInfo;_hostContext;_registeredTools={};_initializedSent=!1;_assertInitialized(e){if(this._initializedSent)return;let t=`[ext-apps] App.${e}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(t);console.warn(`${t}. This will throw in a future release.`)}eventSchemas={toolinput:Zh,toolinputpartial:Qh,toolresult:cg,toolcancelled:$h,hostcontextchanged:ug};static ONE_SHOT_EVENTS=new Set([`toolinput`,`toolinputpartial`,`toolresult`,`toolcancelled`]);_everHadListener=new Set;_assertHandlerTiming(t){if(!e.ONE_SHOT_EVENTS.has(t)||this._everHadListener.has(t)||(this._everHadListener.add(t),!this._initializedSent))return;let n=`[ext-apps] "${String(t)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(n);console.warn(n)}setEventHandler(e,t){t&&this._assertHandlerTiming(e),super.setEventHandler(e,t)}addEventListener(e,t){this._assertHandlerTiming(e),super.addEventListener(e,t)}onEventDispatch(e,t){e===`hostcontextchanged`&&(this._hostContext={...this._hostContext,...t})}constructor(e,t={},n={autoResize:!0}){super(n),this._appInfo=e,this._capabilities=t,this.options=n,n.allowUnsafeEval||o({jitless:!0}),this.setRequestHandler(jf,e=>(console.log(`Received ping:`,e.params),{})),this.setEventHandler(`hostcontextchanged`,void 0)}registerCapabilities(e){if(this.transport)throw Error(`Cannot register capabilities after transport is established`);this._capabilities=Dh(this._capabilities,e)}registerTool(e,t,n){if(this._registeredTools[e])throw Error(`Tool ${e} is already registered`);let r=this,i=()=>{r._initializedSent&&r._capabilities.tools?.listChanged&&r.sendToolListChanged()},a=t.inputSchema!==void 0,o={title:t.title,description:t.description,inputSchema:t.inputSchema,outputSchema:t.outputSchema,annotations:t.annotations,_meta:t._meta,enabled:!0,enable(){this.enabled=!0,i()},disable(){this.enabled=!1,i()},update(e){Object.assign(this,e),i()},remove(){r._registeredTools[e]===o&&(delete r._registeredTools[e],i())},handler:async(t,r)=>{if(!o.enabled)throw Error(`Tool ${e} is disabled`);let i;if(a){let a=o.inputSchema;i=await n(a?await Ih(a,t??{},`Invalid input for tool ${e}: `):t??{},r)}else i=await n(r);return o.outputSchema&&!i.isError&&(i.structuredContent=await Ih(o.outputSchema,i.structuredContent,`Invalid output for tool ${e}: `)),i}};return this._registeredTools[e]=o,!this._capabilities.tools&&!this.transport&&this.registerCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),i(),o}_toolHandlersInitialized=!1;ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(e,t)=>{let n=this._registeredTools[e.name];if(!n)throw Error(`Tool ${e.name} not found`);return n.handler(e.arguments,t)},this.onlisttools=async(e,t)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([e,t])=>t.enabled).map(async([e,t])=>{let n={name:e,title:t.title,description:t.description,inputSchema:t.inputSchema?await Fh(t.inputSchema,`input`):{type:`object`,properties:{}}};return t.outputSchema&&(n.outputSchema=await Fh(t.outputSchema,`output`)),t.annotations&&(n.annotations=t.annotations),t._meta&&(n._meta=t._meta),n}))}))}async sendToolListChanged(e={}){this._assertInitialized(`sendToolListChanged`),await this.notification({method:`notifications/tools/list_changed`,params:e})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler(`toolinput`)}set ontoolinput(e){this.setEventHandler(`toolinput`,e)}get ontoolinputpartial(){return this.getEventHandler(`toolinputpartial`)}set ontoolinputpartial(e){this.setEventHandler(`toolinputpartial`,e)}get ontoolresult(){return this.getEventHandler(`toolresult`)}set ontoolresult(e){this.setEventHandler(`toolresult`,e)}get ontoolcancelled(){return this.getEventHandler(`toolcancelled`)}set ontoolcancelled(e){this.setEventHandler(`toolcancelled`,e)}get onhostcontextchanged(){return this.getEventHandler(`hostcontextchanged`)}set onhostcontextchanged(e){this.setEventHandler(`hostcontextchanged`,e)}_onteardown;get onteardown(){return this._onteardown}set onteardown(e){this.warnIfRequestHandlerReplaced(`onteardown`,this._onteardown,e),this._onteardown=e,this.replaceRequestHandler(ng,(e,t)=>{if(!this._onteardown)throw Error(`No onteardown handler set`);return this._onteardown(e.params,t)})}_oncalltool;get oncalltool(){return this._oncalltool}set oncalltool(e){this.warnIfRequestHandlerReplaced(`oncalltool`,this._oncalltool,e),this._oncalltool=e,this.replaceRequestHandler(Hp,(e,t)=>{if(!this._oncalltool)throw Error(`No oncalltool handler set`);return this._oncalltool(e.params,t)})}_onlisttools;get onlisttools(){return this._onlisttools}set onlisttools(e){this.warnIfRequestHandlerReplaced(`onlisttools`,this._onlisttools,e),this._onlisttools=e,this.replaceRequestHandler(Rp,(e,t)=>{if(!this._onlisttools)throw Error(`No onlisttools handler set`);return this._onlisttools(e.params,t)})}assertCapabilityForMethod(e){if(e===`sampling/createMessage`&&!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${e})`)}assertRequestHandlerCapability(e){switch(e){case`tools/call`:case`tools/list`:if(!this._capabilities.tools)throw Error(`Client does not support tool capability (required for ${e})`);return;case`ping`:case`ui/resource-teardown`:return;default:throw Error(`No handler for method ${e} registered`)}}assertNotificationCapability(e){}assertTaskCapability(e){throw Error(`Tasks are not supported in MCP Apps`)}assertTaskHandlerCapability(e){throw Error(`Task handlers are not supported in MCP Apps`)}async callServerTool(e,t){if(this._assertInitialized(`callServerTool`),typeof e==`string`)throw Error(`callServerTool() expects an object as its first argument, but received a string ("${e}"). Did you mean: callServerTool({ name: "${e}", arguments: { ... } })?`);return await this.request({method:`tools/call`,params:e},Bp,{onprogress:()=>{},resetTimeoutOnProgress:!0,...t})}async readServerResource(e,t){return this._assertInitialized(`readServerResource`),await this.request({method:`resources/read`,params:e},dp,t)}async listServerResources(e,t){return this._assertInitialized(`listServerResources`),await this.request({method:`resources/list`,params:e},ap,t)}async createSamplingMessage(e,t){this._assertInitialized(`createSamplingMessage`);let n=e.tools?am:im;return await this.request({method:`sampling/createMessage`,params:e},n,t)}sendMessage(e,t){return this._assertInitialized(`sendMessage`),this.request({method:`ui/message`,params:e},Jh,t)}sendLog(e){return this.notification({method:`notifications/message`,params:e})}updateModelContext(e,t){return this._assertInitialized(`updateModelContext`),this.request({method:`ui/update-model-context`,params:e},mf,t)}openLink(e,t){return this._assertInitialized(`openLink`),this.request({method:`ui/open-link`,params:e},Kh,t)}sendOpenLink=this.openLink;downloadFile(e,t){return this._assertInitialized(`downloadFile`),this.request({method:`ui/download-file`,params:e},qh,t)}requestTeardown(e={}){return this.notification({method:`ui/notifications/request-teardown`,params:e})}requestDisplayMode(e,t){return this._assertInitialized(`requestDisplayMode`),this.request({method:`ui/request-display-mode`,params:e},og,t)}sendSizeChanged(e){return this.notification({method:`ui/notifications/size-changed`,params:e})}setupSizeChangedNotifications(){let e=!1,t=0,n=0,r=()=>{e||(e=!0,requestAnimationFrame(()=>{e=!1;let r=document.documentElement,i=r.style.height;r.style.height=`max-content`;let a=Math.ceil(r.getBoundingClientRect().height);r.style.height=i;let o=Math.ceil(window.innerWidth);(o!==t||a!==n)&&(t=o,n=a,this.sendSizeChanged({width:o,height:a}))}))};r();let i=new ResizeObserver(r);return i.observe(document.documentElement),i.observe(document.body),()=>i.disconnect()}async connect(e=new Vh(window.parent,window.parent),t){if(this.transport)throw Error(`App is already connected. Call close() before connecting again.`);this._initializedSent=!1,await super.connect(e);try{let e=await this.request({method:`ui/initialize`,params:{appCapabilities:this._capabilities,appInfo:this._appInfo,protocolVersion:Bh}},dg,t);if(e===void 0)throw Error(`Server sent invalid initialize result: ${e}`);this._hostCapabilities=e.hostCapabilities,this._hostInfo=e.hostInfo,this._hostContext=e.hostContext,await this.notification({method:`ui/notifications/initialized`}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(e){throw this.close(),e}}}}));function hg(e){let t=[];return typeof e.durationSeconds==`number`&&t.push(`${e.durationSeconds.toFixed(2)}s`),e.model&&t.push(e.model),t.join(` · `)}function gg(e,t){let n,r=0,i,a=()=>{n!==void 0&&(clearTimeout(n),n=void 0)},o=new pg({name:e,version:`0.0.1`},{}),s=async e=>{let t=await o.request({method:`tools/call`,params:{name:`get_generation`,arguments:{operationId:e}}},Bp);if(!t.isError)return t.structuredContent},c=(e,o)=>{n=window.setTimeout(async()=>{if(Date.now()-r>xg){t.onTimeout?.();return}try{let n=await s(e);if(n?.status===`complete`){a(),i=n,t.onResult(n);return}}catch{}c(e,Math.min(o*1.5,bg))},o)},l=e=>{e&&(a(),i=e,t.onResult(e),e.status===`running`&&e.operationId!==void 0&&(r=Date.now(),c(e.operationId,yg)))};return o.ontoolinput=()=>t.onResult({status:`running`}),o.ontoolresult=e=>l(e?.structuredContent),o.onhostcontextchanged=e=>{if(e?.theme&&Lh(e.theme),e?.styles?.variables&&Rh(e.styles.variables),e?.displayMode&&(document.documentElement.dataset.displayMode=e.displayMode),e?.safeAreaInsets){let{top:t=0,right:n=0,bottom:r=0,left:i=0}=e.safeAreaInsets;document.body.style.padding=`${t}px ${n}px ${r}px ${i}px`}},o.onteardown=async()=>(a(),{}),o.connect(new Vh(window.parent,window.parent)).catch(()=>{}),{app:o,current:()=>i}}function _g(e,t){return e.openLink({url:t})}function vg(e){let t=document.documentElement.dataset.displayMode===`fullscreen`;return e.requestDisplayMode({mode:t?`inline`:`fullscreen`}).then(e=>{e?.mode&&(document.documentElement.dataset.displayMode=e.mode)})}var $,yg,bg,xg,Sg=t((()=>{mg(),Fm(),$=e=>document.getElementById(e),yg=2e3,bg=1e4,xg=36e4}));n((()=>{Sg();var e=e=>{$(`status`).textContent=e},t=e=>{$(`meta`).textContent=e};function n(e,t,n){let r=$(e);r.hidden=!t,n&&(r.title=n)}var r=gg(`Womp image`,{onTimeout:()=>e(`Still running — ask me to check on it.`),onResult:r=>{if(r.status===`running`){$(`skeleton`).classList.add(`pulsing`),$(`actions`).hidden=!0,t(``),e(`Generating…`);return}$(`skeleton`).classList.remove(`pulsing`);let i=r.previewUrl||r.imageUrl;if(i){let t=$(`hero`);t.onload=()=>{$(`skeleton`).style.display=`none`,t.style.display=`block`},t.onerror=()=>e(`Preview unavailable — the file link still works.`),t.src=i}let a=!!r.glbUrl;t(hg(r));let o=r.glbUrl||r.imageUrl;n(`download`,!!o,a?`Download GLB`:`Open full size`),n(`expand`,!!i),$(`actions`).hidden=!o&&!i,e(``)}});$(`download`).addEventListener(`click`,()=>{let t=r.current()?.glbUrl||r.current()?.imageUrl;t&&_g(r.app,t).catch(()=>e(`Could not open the link.`))}),$(`expand`).addEventListener(`click`,()=>{vg(r.app).catch(()=>e(`This host does not support fullscreen.`))})}))();</script>
232
220
  </head>
233
221
  <body>
234
222
  <div class="card" id="card">
235
223
  <img id="hero" class="hero" alt="" style="display: none" />
236
224
  <div id="skeleton" class="skeleton"></div>
237
225
 
238
- <div class="chips">
239
- <span class="chip" id="kind">Image</span>
240
- <span class="chip" id="gid" hidden></span>
241
- </div>
242
-
243
226
  <div class="actions" id="actions" hidden>
244
227
  <button class="btn" id="download" title="Open full size" hidden>
245
228
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
@@ -253,6 +236,11 @@ container holding the app. Specify either width or maxWidth, and either height o
253
236
  </button>
254
237
  </div>
255
238
 
239
+ <!-- Two lines, not one: `meta` is what produced the result, `status` is
240
+ when something went wrong. Sharing an element meant a preview error
241
+ erased the model name, or the reverse, depending on which landed
242
+ last. Both collapse when empty. -->
243
+ <div class="meta" id="meta"></div>
256
244
  <div class="status" id="status">Connecting&hellip;</div>
257
245
  </div>
258
246
  </body>