@frontmcp/uipack 1.8.4 → 1.8.6

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/index.js CHANGED
@@ -358,6 +358,23 @@ function __applySizingCss(sizing) {
358
358
  }
359
359
  }
360
360
 
361
+ function __measureHeight() {
362
+ // <html> at fit-content includes body margins and collapsed child margins;
363
+ // content overflowing a fixed-height body is added; a px max-height clamps.
364
+ var de = document.documentElement;
365
+ var body = document.body;
366
+ if (!de || !body) return 0;
367
+ var prev = de.style.height;
368
+ de.style.height = 'fit-content';
369
+ var dr = de.getBoundingClientRect();
370
+ var br = body.getBoundingClientRect();
371
+ var h = Math.max(dr.height, br.top + body.scrollHeight + Math.max(0, dr.bottom - br.bottom) - dr.top);
372
+ de.style.height = prev;
373
+ var maxHeight = getComputedStyle(de).maxHeight;
374
+ var mx = maxHeight && maxHeight.slice(-2) === 'px' ? parseFloat(maxHeight) : NaN;
375
+ return Math.ceil(isNaN(mx) ? h : Math.min(h, mx));
376
+ }
377
+
361
378
  function __initAutoResize() {
362
379
  if (typeof window === 'undefined') return;
363
380
  // Idempotent: a re-injected IIFE must not stack observers.
@@ -380,23 +397,30 @@ function __initAutoResize() {
380
397
  if (typeof ResizeObserver === 'undefined') return;
381
398
 
382
399
  function startObserving() {
383
- var target = document.getElementById('root') || document.body;
384
- if (!target) return;
400
+ if (!document.body) return;
401
+ var targets = [document.documentElement, document.body];
402
+ var root = document.getElementById('root');
403
+ if (root) targets.push(root);
385
404
 
386
405
  var rafId = null;
387
406
  var lastReported = -1;
388
407
  function report() {
389
408
  rafId = null;
390
409
  try {
391
- var rect = target.getBoundingClientRect();
392
- var height = Math.ceil(rect.height);
393
- var width = Math.ceil(rect.width);
410
+ // Before the handshake an ext-apps host can't receive the report; the
411
+ // bridge:ready listener below sends it once the bridge is up.
412
+ if (window.FrontMcpBridge && window.FrontMcpBridge.initialized === false) return;
413
+ var height = __measureHeight();
414
+ var width = Math.ceil(document.documentElement.getBoundingClientRect().width);
394
415
  if (height === lastReported || height <= 0) return;
395
416
  lastReported = height;
396
417
  var payload = { height: height, width: width };
397
418
  if (sizing.aspectRatio != null) payload.aspectRatio = sizing.aspectRatio;
398
419
  if (window.FrontMcpBridge && typeof window.FrontMcpBridge.setSize === 'function') {
399
- window.FrontMcpBridge.setSize(payload).catch(function() {});
420
+ window.FrontMcpBridge.setSize(payload).catch(function() {
421
+ // Forget a rejected report so the same height is sent again.
422
+ if (lastReported === height) lastReported = -1;
423
+ });
400
424
  }
401
425
  window.dispatchEvent(new CustomEvent('widget:resize', { detail: payload }));
402
426
  } catch (e) {}
@@ -417,9 +441,17 @@ function __initAutoResize() {
417
441
  window.__mcpResizeObserver.disconnect();
418
442
  }
419
443
  var ro = new ResizeObserver(function() { schedule(); });
420
- ro.observe(target);
444
+ for (var i = 0; i < targets.length; i++) ro.observe(targets[i]);
421
445
  window.__mcpResizeObserver = ro;
422
446
  } catch (e) {}
447
+ // Report once the bridge is ready (the report scheduled below is skipped
448
+ // while the handshake is still pending).
449
+ var readySent = false;
450
+ window.addEventListener('bridge:ready', function() {
451
+ if (readySent) return;
452
+ readySent = true;
453
+ schedule();
454
+ });
423
455
  // Report once on init so the host gets an initial measurement.
424
456
  schedule();
425
457
  }
@@ -467,6 +499,25 @@ function detectViewport() {
467
499
  return undefined;
468
500
  }
469
501
 
502
+ function __applyHostTheme(theme) {
503
+ // Follow a host-supplied theme: <meta name="color-scheme"> sets the frame's
504
+ // canvas and form controls (a widget's own :root color-scheme still wins),
505
+ // <html data-theme> is a styling hook. The OS fallback is never written.
506
+ if (theme !== 'light' && theme !== 'dark') return;
507
+ if (typeof document === 'undefined' || !document.documentElement) return;
508
+ try {
509
+ var meta = document.querySelector('meta[name="color-scheme"]');
510
+ var head = document.head || document.getElementsByTagName('head')[0];
511
+ if (!meta && head) {
512
+ meta = document.createElement('meta');
513
+ meta.setAttribute('name', 'color-scheme');
514
+ head.appendChild(meta);
515
+ }
516
+ if (meta) meta.setAttribute('content', theme);
517
+ document.documentElement.setAttribute('data-theme', theme);
518
+ } catch (e) {}
519
+ }
520
+
470
521
  function readInjectedData() {
471
522
  var data = { toolInput: {}, toolOutput: undefined, structuredContent: undefined };
472
523
  if (typeof window !== 'undefined') {
@@ -573,6 +624,8 @@ var ExtAppsAdapter = {
573
624
  pendingRequests: {},
574
625
  requestId: 0,
575
626
  hostCapabilities: {},
627
+ handshakeSettled: false,
628
+ pendingSize: null,
576
629
  canHandle: function() {
577
630
  if (typeof window === 'undefined') return false;
578
631
  if (window.parent === window) return false;
@@ -738,6 +791,7 @@ var ExtAppsAdapter = {
738
791
  var timeout = setTimeout(function() {
739
792
  delete self.pendingRequests[id];
740
793
  // Handshake timeout is non-fatal \u2014 notifications may still arrive
794
+ self.settleHandshake();
741
795
  resolve();
742
796
  }, 10000);
743
797
 
@@ -751,7 +805,9 @@ var ExtAppsAdapter = {
751
805
  supportsDisplayModes: true
752
806
  });
753
807
  if (result.hostContext) {
754
- Object.assign(context.hostContext, result.hostContext);
808
+ // Notify (not a silent merge) so onContextChange listeners and the
809
+ // host theme see the handshake's context.
810
+ context.notifyContextChange(result.hostContext);
755
811
  }
756
812
  // Send ui/notifications/initialized to tell the host the view is ready.
757
813
  // Per MCP Apps spec, the host waits for this before sending tool-result.
@@ -761,9 +817,10 @@ var ExtAppsAdapter = {
761
817
  method: 'ui/notifications/initialized',
762
818
  params: {}
763
819
  }, targetOrigin);
820
+ self.settleHandshake();
764
821
  resolve();
765
822
  },
766
- reject: function(err) { resolve(); }, // Non-fatal
823
+ reject: function(err) { self.settleHandshake(); resolve(); }, // Non-fatal
767
824
  timeout: timeout
768
825
  };
769
826
 
@@ -777,6 +834,18 @@ var ExtAppsAdapter = {
777
834
  performHandshake: function(context) {
778
835
  return this.sendHandshake(context);
779
836
  },
837
+ settleHandshake: function() {
838
+ // Deliver the latest size requested while no host origin was trusted.
839
+ this.handshakeSettled = true;
840
+ var pending = this.pendingSize;
841
+ if (!pending) return;
842
+ this.pendingSize = null;
843
+ this.sendRequest('ui/setSize', pending.params).then(function(result) {
844
+ for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].resolve(result);
845
+ }, function(err) {
846
+ for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].reject(err);
847
+ });
848
+ },
780
849
  callTool: function(context, name, args) {
781
850
  if (!this.hostCapabilities.serverTools && !this.hostCapabilities.serverToolProxy) {
782
851
  return Promise.reject(new Error('Server tool proxy not supported'));
@@ -800,11 +869,22 @@ var ExtAppsAdapter = {
800
869
  setSize: function(context, size) {
801
870
  // FrontMCP sizing channel \u2014 parallels ui/setDisplayMode. Reports the
802
871
  // measured/desired widget dimensions to the host.
803
- return this.sendRequest('ui/setSize', {
872
+ var params = {
804
873
  height: size && size.height,
805
874
  width: size && size.width,
806
875
  aspectRatio: size && size.aspectRatio
807
- });
876
+ };
877
+ if (!this.handshakeSettled && !this.trustedOrigin && this.trustedOrigins.length === 0) {
878
+ // No host origin yet: keep only the latest size and send it when the
879
+ // handshake settles; every caller's promise follows that one request.
880
+ var self = this;
881
+ if (!this.pendingSize) this.pendingSize = { params: params, waiters: [] };
882
+ this.pendingSize.params = params;
883
+ return new Promise(function(resolve, reject) {
884
+ self.pendingSize.waiters.push({ resolve: resolve, reject: reject });
885
+ });
886
+ }
887
+ return this.sendRequest('ui/setSize', params);
808
888
  },
809
889
  requestClose: function(context) {
810
890
  return this.sendRequest('ui/close', {});
@@ -1050,6 +1130,7 @@ function FrontMcpBridge() {
1050
1130
  toolResultListeners: [],
1051
1131
  notifyContextChange: function(changes) {
1052
1132
  Object.assign(this.hostContext, changes);
1133
+ if (changes && changes.theme) __applyHostTheme(changes.theme);
1053
1134
  for (var i = 0; i < this.contextListeners.length; i++) {
1054
1135
  try { this.contextListeners[i](changes); } catch(e) {}
1055
1136
  }
@@ -3449,8 +3530,24 @@ function isFrontmcpUiResolvable(...candidatePaths) {
3449
3530
  }
3450
3531
 
3451
3532
  // libs/uipack/src/component/transpiler.ts
3533
+ function loadEsbuild(filename) {
3534
+ try {
3535
+ return require("esbuild");
3536
+ } catch (err) {
3537
+ if (!isMissingEsbuild(err)) throw err;
3538
+ const subject = filename ? `FileSource widget "${filename}"` : "A FileSource widget";
3539
+ throw new Error(
3540
+ `${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,
3541
+ { cause: err }
3542
+ );
3543
+ }
3544
+ }
3545
+ function isMissingEsbuild(err) {
3546
+ if (!(err instanceof Error)) return false;
3547
+ return err.code === "MODULE_NOT_FOUND" && /Cannot find module ['"]esbuild['"]/.test(err.message);
3548
+ }
3452
3549
  function transpileReactSource(source, filename) {
3453
- const esbuild = require("esbuild");
3550
+ const esbuild = loadEsbuild(filename);
3454
3551
  const loader = filename?.endsWith(".tsx") ? "tsx" : "jsx";
3455
3552
  const result = esbuild.transformSync(source, {
3456
3553
  loader,
@@ -3469,7 +3566,7 @@ function bundleFileSource(source, filename, resolveDir, componentName, options =
3469
3566
  `FileSource widget "${filename}" requires the @frontmcp/ui package, which provides the React bridge mount that's injected at bundle time. Install it (e.g. \`npm install @frontmcp/ui\` or \`yarn add @frontmcp/ui\`) and try again.`
3470
3567
  );
3471
3568
  }
3472
- const esbuild = require("esbuild");
3569
+ const esbuild = loadEsbuild(filename);
3473
3570
  const mountCode = `
3474
3571
  // --- Auto-generated mount ---
3475
3572
  import { createElement as __h } from 'react';
@@ -3566,7 +3663,8 @@ if (__root) {
3566
3663
  } catch (err) {
3567
3664
  const message = err instanceof Error ? err.message : String(err);
3568
3665
  throw new Error(
3569
- `Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`
3666
+ `Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`,
3667
+ { cause: err }
3570
3668
  );
3571
3669
  }
3572
3670
  }
@@ -3628,6 +3726,37 @@ function resolveImportSource(source) {
3628
3726
  peerDependencies: []
3629
3727
  };
3630
3728
  }
3729
+ var BUILD_DIR_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "out"]);
3730
+ function missingWidgetError(filePath, cause) {
3731
+ const sourceWidget = findSourceWidget(filePath);
3732
+ const error = new Error(
3733
+ `FileSource widget not found (ENOENT): no file at "${filePath}". The widget source is read from this path when the tool is called, so it has to exist where the compiled tool runs \u2014 a path built from \`__dirname\` or \`import.meta.url\` points into the build output once the tool is compiled. tsc does not copy \`*.widget.tsx\` / \`*.widget.jsx\` files into its output; \`frontmcp build\` does, and any other build needs a step that copies them next to the compiled tool.` + (sourceWidget ? ` The source widget exists at "${sourceWidget}" \u2014 copy it to "${filePath}", or build with \`frontmcp build\`.` : ""),
3734
+ { cause }
3735
+ );
3736
+ error.code = "ENOENT";
3737
+ error.path = filePath;
3738
+ return error;
3739
+ }
3740
+ function findSourceWidget(filePath) {
3741
+ const path = require("path");
3742
+ const fs = require("fs");
3743
+ const parts = filePath.split(path.sep);
3744
+ for (let i = parts.length - 2; i >= 0; i--) {
3745
+ if (!BUILD_DIR_SEGMENTS.has(parts[i])) continue;
3746
+ const candidates = [[...parts.slice(0, i), "src", ...parts.slice(i + 1)]];
3747
+ if (parts.length - i > 2) candidates.push([...parts.slice(0, i), "src", ...parts.slice(i + 2)]);
3748
+ candidates.push([...parts.slice(0, i), ...parts.slice(i + 1)]);
3749
+ for (const candidate of candidates) {
3750
+ const candidatePath = candidate.join(path.sep);
3751
+ try {
3752
+ if (fs.existsSync(candidatePath)) return candidatePath;
3753
+ } catch {
3754
+ }
3755
+ }
3756
+ return void 0;
3757
+ }
3758
+ return void 0;
3759
+ }
3631
3760
  function resolveFileSource(source, options = {}) {
3632
3761
  const path = require("path");
3633
3762
  const ext = path.extname(source.file).toLowerCase();
@@ -3642,9 +3771,11 @@ function resolveFileSource(source, options = {}) {
3642
3771
  const isNotFound = err?.code === "ENOENT";
3643
3772
  if (isNotFound && wasRelative) {
3644
3773
  throw new Error(
3645
- `FileSource widget "${source.file}" not found at "${filePath}". Relative paths are resolved against process.cwd() ("${process.cwd()}"), not the tool file's directory. To anchor the path to the tool file, pass an absolute path \u2014 e.g. \`{ file: fileURLToPath(new URL('./widget.tsx', import.meta.url)) }\` from \`node:url\` (see issue #444).`
3774
+ `FileSource widget "${source.file}" not found at "${filePath}". Relative paths are resolved against process.cwd() ("${process.cwd()}"), not the tool file's directory. To anchor the path to the tool file, pass an absolute path \u2014 e.g. \`{ file: fileURLToPath(new URL('./widget.tsx', import.meta.url)) }\` from \`node:url\` (see issue #444).`,
3775
+ { cause: err }
3646
3776
  );
3647
3777
  }
3778
+ if (isNotFound) throw missingWidgetError(filePath, err);
3648
3779
  throw err;
3649
3780
  }
3650
3781
  const componentName = source.exportName || extractDefaultExportName(rawSource) || "Component";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/uipack",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "description": "FrontMCP UIpack - HTML shell builder, pluggable import resolver, and NPM component loader for MCP UI (React-free core)",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -61,6 +61,12 @@
61
61
  "typescript": "^5.9.3"
62
62
  },
63
63
  "peerDependencies": {
64
- "@frontmcp/lazy-zod": "1.8.4"
64
+ "@frontmcp/lazy-zod": "1.8.6",
65
+ "esbuild": ">=0.27.0 <1"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "esbuild": {
69
+ "optional": true
70
+ }
65
71
  }
66
72
  }
package/shell/index.js CHANGED
@@ -157,6 +157,23 @@ function __applySizingCss(sizing) {
157
157
  }
158
158
  }
159
159
 
160
+ function __measureHeight() {
161
+ // <html> at fit-content includes body margins and collapsed child margins;
162
+ // content overflowing a fixed-height body is added; a px max-height clamps.
163
+ var de = document.documentElement;
164
+ var body = document.body;
165
+ if (!de || !body) return 0;
166
+ var prev = de.style.height;
167
+ de.style.height = 'fit-content';
168
+ var dr = de.getBoundingClientRect();
169
+ var br = body.getBoundingClientRect();
170
+ var h = Math.max(dr.height, br.top + body.scrollHeight + Math.max(0, dr.bottom - br.bottom) - dr.top);
171
+ de.style.height = prev;
172
+ var maxHeight = getComputedStyle(de).maxHeight;
173
+ var mx = maxHeight && maxHeight.slice(-2) === 'px' ? parseFloat(maxHeight) : NaN;
174
+ return Math.ceil(isNaN(mx) ? h : Math.min(h, mx));
175
+ }
176
+
160
177
  function __initAutoResize() {
161
178
  if (typeof window === 'undefined') return;
162
179
  // Idempotent: a re-injected IIFE must not stack observers.
@@ -179,23 +196,30 @@ function __initAutoResize() {
179
196
  if (typeof ResizeObserver === 'undefined') return;
180
197
 
181
198
  function startObserving() {
182
- var target = document.getElementById('root') || document.body;
183
- if (!target) return;
199
+ if (!document.body) return;
200
+ var targets = [document.documentElement, document.body];
201
+ var root = document.getElementById('root');
202
+ if (root) targets.push(root);
184
203
 
185
204
  var rafId = null;
186
205
  var lastReported = -1;
187
206
  function report() {
188
207
  rafId = null;
189
208
  try {
190
- var rect = target.getBoundingClientRect();
191
- var height = Math.ceil(rect.height);
192
- var width = Math.ceil(rect.width);
209
+ // Before the handshake an ext-apps host can't receive the report; the
210
+ // bridge:ready listener below sends it once the bridge is up.
211
+ if (window.FrontMcpBridge && window.FrontMcpBridge.initialized === false) return;
212
+ var height = __measureHeight();
213
+ var width = Math.ceil(document.documentElement.getBoundingClientRect().width);
193
214
  if (height === lastReported || height <= 0) return;
194
215
  lastReported = height;
195
216
  var payload = { height: height, width: width };
196
217
  if (sizing.aspectRatio != null) payload.aspectRatio = sizing.aspectRatio;
197
218
  if (window.FrontMcpBridge && typeof window.FrontMcpBridge.setSize === 'function') {
198
- window.FrontMcpBridge.setSize(payload).catch(function() {});
219
+ window.FrontMcpBridge.setSize(payload).catch(function() {
220
+ // Forget a rejected report so the same height is sent again.
221
+ if (lastReported === height) lastReported = -1;
222
+ });
199
223
  }
200
224
  window.dispatchEvent(new CustomEvent('widget:resize', { detail: payload }));
201
225
  } catch (e) {}
@@ -216,9 +240,17 @@ function __initAutoResize() {
216
240
  window.__mcpResizeObserver.disconnect();
217
241
  }
218
242
  var ro = new ResizeObserver(function() { schedule(); });
219
- ro.observe(target);
243
+ for (var i = 0; i < targets.length; i++) ro.observe(targets[i]);
220
244
  window.__mcpResizeObserver = ro;
221
245
  } catch (e) {}
246
+ // Report once the bridge is ready (the report scheduled below is skipped
247
+ // while the handshake is still pending).
248
+ var readySent = false;
249
+ window.addEventListener('bridge:ready', function() {
250
+ if (readySent) return;
251
+ readySent = true;
252
+ schedule();
253
+ });
222
254
  // Report once on init so the host gets an initial measurement.
223
255
  schedule();
224
256
  }
@@ -266,6 +298,25 @@ function detectViewport() {
266
298
  return undefined;
267
299
  }
268
300
 
301
+ function __applyHostTheme(theme) {
302
+ // Follow a host-supplied theme: <meta name="color-scheme"> sets the frame's
303
+ // canvas and form controls (a widget's own :root color-scheme still wins),
304
+ // <html data-theme> is a styling hook. The OS fallback is never written.
305
+ if (theme !== 'light' && theme !== 'dark') return;
306
+ if (typeof document === 'undefined' || !document.documentElement) return;
307
+ try {
308
+ var meta = document.querySelector('meta[name="color-scheme"]');
309
+ var head = document.head || document.getElementsByTagName('head')[0];
310
+ if (!meta && head) {
311
+ meta = document.createElement('meta');
312
+ meta.setAttribute('name', 'color-scheme');
313
+ head.appendChild(meta);
314
+ }
315
+ if (meta) meta.setAttribute('content', theme);
316
+ document.documentElement.setAttribute('data-theme', theme);
317
+ } catch (e) {}
318
+ }
319
+
269
320
  function readInjectedData() {
270
321
  var data = { toolInput: {}, toolOutput: undefined, structuredContent: undefined };
271
322
  if (typeof window !== 'undefined') {
@@ -372,6 +423,8 @@ var ExtAppsAdapter = {
372
423
  pendingRequests: {},
373
424
  requestId: 0,
374
425
  hostCapabilities: {},
426
+ handshakeSettled: false,
427
+ pendingSize: null,
375
428
  canHandle: function() {
376
429
  if (typeof window === 'undefined') return false;
377
430
  if (window.parent === window) return false;
@@ -537,6 +590,7 @@ var ExtAppsAdapter = {
537
590
  var timeout = setTimeout(function() {
538
591
  delete self.pendingRequests[id];
539
592
  // Handshake timeout is non-fatal \u2014 notifications may still arrive
593
+ self.settleHandshake();
540
594
  resolve();
541
595
  }, 10000);
542
596
 
@@ -550,7 +604,9 @@ var ExtAppsAdapter = {
550
604
  supportsDisplayModes: true
551
605
  });
552
606
  if (result.hostContext) {
553
- Object.assign(context.hostContext, result.hostContext);
607
+ // Notify (not a silent merge) so onContextChange listeners and the
608
+ // host theme see the handshake's context.
609
+ context.notifyContextChange(result.hostContext);
554
610
  }
555
611
  // Send ui/notifications/initialized to tell the host the view is ready.
556
612
  // Per MCP Apps spec, the host waits for this before sending tool-result.
@@ -560,9 +616,10 @@ var ExtAppsAdapter = {
560
616
  method: 'ui/notifications/initialized',
561
617
  params: {}
562
618
  }, targetOrigin);
619
+ self.settleHandshake();
563
620
  resolve();
564
621
  },
565
- reject: function(err) { resolve(); }, // Non-fatal
622
+ reject: function(err) { self.settleHandshake(); resolve(); }, // Non-fatal
566
623
  timeout: timeout
567
624
  };
568
625
 
@@ -576,6 +633,18 @@ var ExtAppsAdapter = {
576
633
  performHandshake: function(context) {
577
634
  return this.sendHandshake(context);
578
635
  },
636
+ settleHandshake: function() {
637
+ // Deliver the latest size requested while no host origin was trusted.
638
+ this.handshakeSettled = true;
639
+ var pending = this.pendingSize;
640
+ if (!pending) return;
641
+ this.pendingSize = null;
642
+ this.sendRequest('ui/setSize', pending.params).then(function(result) {
643
+ for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].resolve(result);
644
+ }, function(err) {
645
+ for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].reject(err);
646
+ });
647
+ },
579
648
  callTool: function(context, name, args) {
580
649
  if (!this.hostCapabilities.serverTools && !this.hostCapabilities.serverToolProxy) {
581
650
  return Promise.reject(new Error('Server tool proxy not supported'));
@@ -599,11 +668,22 @@ var ExtAppsAdapter = {
599
668
  setSize: function(context, size) {
600
669
  // FrontMCP sizing channel \u2014 parallels ui/setDisplayMode. Reports the
601
670
  // measured/desired widget dimensions to the host.
602
- return this.sendRequest('ui/setSize', {
671
+ var params = {
603
672
  height: size && size.height,
604
673
  width: size && size.width,
605
674
  aspectRatio: size && size.aspectRatio
606
- });
675
+ };
676
+ if (!this.handshakeSettled && !this.trustedOrigin && this.trustedOrigins.length === 0) {
677
+ // No host origin yet: keep only the latest size and send it when the
678
+ // handshake settles; every caller's promise follows that one request.
679
+ var self = this;
680
+ if (!this.pendingSize) this.pendingSize = { params: params, waiters: [] };
681
+ this.pendingSize.params = params;
682
+ return new Promise(function(resolve, reject) {
683
+ self.pendingSize.waiters.push({ resolve: resolve, reject: reject });
684
+ });
685
+ }
686
+ return this.sendRequest('ui/setSize', params);
607
687
  },
608
688
  requestClose: function(context) {
609
689
  return this.sendRequest('ui/close', {});
@@ -849,6 +929,7 @@ function FrontMcpBridge() {
849
929
  toolResultListeners: [],
850
930
  notifyContextChange: function(changes) {
851
931
  Object.assign(this.hostContext, changes);
932
+ if (changes && changes.theme) __applyHostTheme(changes.theme);
852
933
  for (var i = 0; i < this.contextListeners.length; i++) {
853
934
  try { this.contextListeners[i](changes); } catch(e) {}
854
935
  }
@@ -404,8 +404,10 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
404
404
  */
405
405
  aspectRatio?: string | number;
406
406
  /**
407
- * Whether the widget should auto-report its content height to the host as it
408
- * changes (via a debounced `ResizeObserver` on `#root`).
407
+ * Whether the widget should auto-report its height to the host as it changes
408
+ * (via a debounced `ResizeObserver` on `<html>`, `<body>` and `#root`). The
409
+ * whole document is measured, margins included; the first report is sent once
410
+ * the host handshake completes.
409
411
  *
410
412
  * Only takes effect when the widget configures sizing — i.e. at least one
411
413
  * sizing field (`preferredHeight` / `minHeight` / `maxHeight` / `aspectRatio` /
@@ -1 +1 @@
1
- {"version":3,"file":"ui-config.d.ts","sourceRoot":"","sources":["../../src/types/ui-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui-config.d.ts","sourceRoot":"","sources":["../../src/types/ui-config.ts"],"names":[],"mappings":"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"}