sunpeak 0.20.23 → 0.20.29

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.
Files changed (62) hide show
  1. package/README.md +29 -4
  2. package/bin/commands/inspect.mjs +18 -0
  3. package/dist/chatgpt/index.cjs +1 -1
  4. package/dist/chatgpt/index.js +1 -1
  5. package/dist/claude/index.cjs +1 -1
  6. package/dist/claude/index.js +1 -1
  7. package/dist/embed.css +2 -0
  8. package/dist/host/chatgpt/index.cjs +1 -1
  9. package/dist/host/chatgpt/index.js +1 -1
  10. package/dist/index.cjs +3 -3
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/inspector/app-flatten.d.ts +7 -0
  15. package/dist/inspector/app-types.d.ts +83 -0
  16. package/dist/inspector/iframe-resource.d.ts +19 -1
  17. package/dist/inspector/index.cjs +3 -1
  18. package/dist/inspector/index.cjs.map +1 -1
  19. package/dist/inspector/index.d.ts +2 -0
  20. package/dist/inspector/index.js +3 -2
  21. package/dist/inspector/index.js.map +1 -1
  22. package/dist/inspector/inline-helper-script.d.ts +22 -0
  23. package/dist/inspector/inspector-api.d.ts +3 -0
  24. package/dist/inspector/inspector.d.ts +21 -1
  25. package/dist/inspector/simple-sidebar.d.ts +13 -1
  26. package/dist/inspector/use-inspector-state.d.ts +1 -0
  27. package/dist/inspector/use-mcp-connection.d.ts +1 -1
  28. package/dist/{inspector-CJNvLoHo.js → inspector-B1355aXh.js} +393 -49
  29. package/dist/inspector-B1355aXh.js.map +1 -0
  30. package/dist/{inspector-DtEighD9.cjs → inspector-CJPO4f12.cjs} +397 -47
  31. package/dist/inspector-CJPO4f12.cjs.map +1 -0
  32. package/dist/mcp/index.cjs +1 -1
  33. package/dist/mcp/index.cjs.map +1 -1
  34. package/dist/mcp/index.js +1 -1
  35. package/dist/mcp/index.js.map +1 -1
  36. package/dist/sandbox-proxy.html +173 -0
  37. package/dist/style.css +9 -1
  38. package/dist/types/simulation.d.ts +3 -8
  39. package/dist/{use-app-cSBm5Pjl.js → use-app-C2pGHlnF.js} +2 -2
  40. package/dist/{use-app-cSBm5Pjl.js.map → use-app-C2pGHlnF.js.map} +1 -1
  41. package/dist/{use-app-CxtSfkSF.cjs → use-app-DIWh7-3f.cjs} +2 -2
  42. package/dist/{use-app-CxtSfkSF.cjs.map → use-app-DIWh7-3f.cjs.map} +1 -1
  43. package/package.json +6 -3
  44. package/template/dist/albums/albums.html +1 -1
  45. package/template/dist/albums/albums.json +1 -1
  46. package/template/dist/carousel/carousel.html +1 -1
  47. package/template/dist/carousel/carousel.json +1 -1
  48. package/template/dist/map/map.html +1 -1
  49. package/template/dist/map/map.json +1 -1
  50. package/template/dist/review/review.html +1 -1
  51. package/template/dist/review/review.json +1 -1
  52. package/template/node_modules/.vite/deps/_metadata.json +3 -3
  53. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +1 -1
  54. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
  55. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +1 -1
  56. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
  57. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +1 -1
  58. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
  59. package/template/node_modules/.vite-mcp/deps/_metadata.json +22 -22
  60. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-claude-linux.png +0 -0
  61. package/dist/inspector-CJNvLoHo.js.map +0 -1
  62. package/dist/inspector-DtEighD9.cjs.map +0 -1
@@ -2,7 +2,7 @@ import { L as __require, _ as record, a as array, b as unknown, f as never, i as
2
2
  import { B as ResourceLinkSchema, C as ListPromptsRequestSchema, D as ListResourcesRequestSchema, E as ListResourceTemplatesResultSchema, F as PingRequestSchema, G as ToolSchema, I as PromptListChangedNotificationSchema, L as ReadResourceRequestSchema, N as LoggingMessageNotificationSchema, O as ListResourcesResultSchema, R as ReadResourceResultSchema, T as ListResourceTemplatesRequestSchema, V as ResourceListChangedNotificationSchema, W as ToolListChangedNotificationSchema, a as CallToolResultSchema, c as CreateMessageRequestSchema, i as CallToolRequestSchema, j as ListToolsResultSchema, m as EmbeddedResourceSchema, s as ContentBlockSchema, t as Protocol, v as ImplementationSchema, w as ListPromptsResultSchema, x as JSONRPCMessageSchema, z as RequestIdSchema } from "./protocol-kqfS1G0V.js";
3
3
  import * as React from "react";
4
4
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
- import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/lib/default-style-variables.ts
7
7
  var DEFAULT_STYLE_VARIABLES = {
8
8
  "--color-background-primary": "light-dark(#ffffff, #1a1a1a)",
@@ -4223,7 +4223,7 @@ registerHostShell({
4223
4223
  }`
4224
4224
  });
4225
4225
  //#endregion
4226
- //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__react-_3f5c1a6a4033ae62a19a2bb834f0e050/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
4226
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.2_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__react-_f5b843da9146ebea748e10ad8dfce46a/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
4227
4227
  ((X) => typeof __require < "u" ? __require : typeof Proxy < "u" ? new Proxy(X, { get: (Y, Z) => (typeof __require < "u" ? __require : Y)[Z] }) : X)(function(X) {
4228
4228
  if (typeof __require < "u") return __require.apply(this, arguments);
4229
4229
  throw Error("Dynamic require of \"" + X + "\" is not supported");
@@ -5545,6 +5545,145 @@ iframe { border: none; width: 100%; height: 100%; display: block; }
5545
5545
  </body>
5546
5546
  </html>`;
5547
5547
  }
5548
+ var SUNPEAK_INLINE_HELPER_SCRIPT = `
5549
+ (function() {
5550
+ if (window.sunpeak) return; // already installed (e.g. parent hot-reload)
5551
+ // Opt-out: resource HTML using the real MCP Apps SDK can suppress the
5552
+ // helper to avoid sending two ui/initialize requests. Manual lowercase
5553
+ // comparison so content="off" / "OFF" / "Off" all match (the Selectors
5554
+ // L4 case-insensitive flag isn't supported in all test environments).
5555
+ try {
5556
+ var metas = document.querySelectorAll('meta[name="sunpeak-helper"]');
5557
+ for (var mi = 0; mi < metas.length; mi++) {
5558
+ var contentAttr = metas[mi].getAttribute('content');
5559
+ if (contentAttr && contentAttr.toLowerCase() === 'off') return;
5560
+ }
5561
+ } catch (e) { /* document not ready or querySelector missing */ }
5562
+
5563
+ var listeners = {
5564
+ toolInput: [],
5565
+ toolInputPartial: [],
5566
+ toolResult: [],
5567
+ toolCancelled: [],
5568
+ hostContext: []
5569
+ };
5570
+ var last = {
5571
+ toolInput: undefined,
5572
+ toolInputPartial: undefined,
5573
+ toolResult: undefined,
5574
+ toolCancelled: undefined,
5575
+ hostContext: undefined
5576
+ };
5577
+ function dispatch(channel, value) {
5578
+ last[channel] = value;
5579
+ // Iterate over a SNAPSHOT — callbacks that unsubscribe themselves
5580
+ // mutate the live list, which would skip subsequent callbacks under a
5581
+ // for-by-index loop on the original array.
5582
+ var list = listeners[channel].slice();
5583
+ for (var i = 0; i < list.length; i++) {
5584
+ try { list[i](value); } catch (e) { console.error('[sunpeak] callback error:', e); }
5585
+ }
5586
+ }
5587
+ // Map channel names to the public method name for error messages.
5588
+ var channelMethodName = {
5589
+ toolInput: 'onToolInput',
5590
+ toolInputPartial: 'onToolInputPartial',
5591
+ toolResult: 'onToolResult',
5592
+ toolCancelled: 'onToolCancelled',
5593
+ hostContext: 'onHostContextChange'
5594
+ };
5595
+ function subscribe(channel) {
5596
+ return function(cb) {
5597
+ if (typeof cb !== 'function') {
5598
+ throw new TypeError('window.sunpeak.' + channelMethodName[channel] + ' expects a function');
5599
+ }
5600
+ listeners[channel].push(cb);
5601
+ if (last[channel] !== undefined) {
5602
+ try { cb(last[channel]); } catch (e) { console.error('[sunpeak] callback error:', e); }
5603
+ }
5604
+ return function unsubscribe() {
5605
+ var idx = listeners[channel].indexOf(cb);
5606
+ if (idx >= 0) listeners[channel].splice(idx, 1);
5607
+ };
5608
+ };
5609
+ }
5610
+
5611
+ window.sunpeak = {
5612
+ onToolInput: subscribe('toolInput'),
5613
+ onToolInputPartial: subscribe('toolInputPartial'),
5614
+ onToolResult: subscribe('toolResult'),
5615
+ onToolCancelled: subscribe('toolCancelled'),
5616
+ onHostContextChange: subscribe('hostContext')
5617
+ };
5618
+
5619
+ var nextId = 1;
5620
+ var pending = {};
5621
+
5622
+ function sendRequest(method, params) {
5623
+ var id = nextId++;
5624
+ return new Promise(function(resolve, reject) {
5625
+ pending[id] = { resolve: resolve, reject: reject };
5626
+ try {
5627
+ window.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params }, '*');
5628
+ } catch (e) {
5629
+ delete pending[id];
5630
+ reject(e);
5631
+ }
5632
+ });
5633
+ }
5634
+ function sendNotification(method, params) {
5635
+ try {
5636
+ window.parent.postMessage({ jsonrpc: '2.0', method: method, params: params || {} }, '*');
5637
+ } catch (e) { /* parent detached */ }
5638
+ }
5639
+
5640
+ window.addEventListener('message', function(ev) {
5641
+ // Only trust messages from the actual parent (the sandbox proxy).
5642
+ // Without this guard, a sibling iframe in the same browsing context or
5643
+ // a browser extension content script could forge JSON-RPC notifications
5644
+ // and drive the embedder's onToolResult/onToolInput callbacks with
5645
+ // attacker-controlled data.
5646
+ if (ev.source !== window.parent) return;
5647
+ var msg = ev.data;
5648
+ if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0') return;
5649
+ if (typeof msg.id !== 'undefined' && pending[msg.id]) {
5650
+ var p = pending[msg.id];
5651
+ delete pending[msg.id];
5652
+ if (msg.error) p.reject(new Error((msg.error && msg.error.message) || 'request error'));
5653
+ else p.resolve(msg.result);
5654
+ return;
5655
+ }
5656
+ if (msg.method === 'ui/notifications/tool-input') {
5657
+ dispatch('toolInput', (msg.params && msg.params.arguments) || {});
5658
+ } else if (msg.method === 'ui/notifications/tool-input-partial') {
5659
+ dispatch('toolInputPartial', (msg.params && msg.params.arguments) || {});
5660
+ } else if (msg.method === 'ui/notifications/tool-result') {
5661
+ // tool-result params are the CallToolResult directly per the spec.
5662
+ dispatch('toolResult', msg.params || {});
5663
+ } else if (msg.method === 'ui/notifications/tool-cancelled') {
5664
+ // Clear cached input / partial / result so a late onToolResult
5665
+ // subscriber doesn't get the cancelled-then-stale value replayed.
5666
+ // hostContext stays — the environment hasn't changed.
5667
+ last.toolInput = undefined;
5668
+ last.toolInputPartial = undefined;
5669
+ last.toolResult = undefined;
5670
+ dispatch('toolCancelled', msg.params || {});
5671
+ } else if (msg.method === 'ui/notifications/host-context-changed') {
5672
+ dispatch('hostContext', msg.params || {});
5673
+ }
5674
+ });
5675
+
5676
+ sendRequest('ui/initialize', {
5677
+ appInfo: { name: 'sunpeak-inline-helper', version: '1.0.0' },
5678
+ appCapabilities: {},
5679
+ protocolVersion: '2026-01-26'
5680
+ }).then(function() {
5681
+ sendNotification('ui/notifications/initialized');
5682
+ }).catch(function(err) {
5683
+ console.warn('[sunpeak] ui/initialize failed:', err && err.message);
5684
+ });
5685
+ })();
5686
+ `.trim();
5548
5687
  //#endregion
5549
5688
  //#region src/inspector/iframe-resource.tsx
5550
5689
  /**
@@ -5683,6 +5822,23 @@ requestAnimationFrame(function(){
5683
5822
  e.source.postMessage({jsonrpc:"2.0",method:"sunpeak/fence-ack",params:{fenceId:fid}},"*");
5684
5823
  });}});`;
5685
5824
  /**
5825
+ * Inject the paint-fence responder and (optionally) a platform runtime script
5826
+ * into a user-provided HTML document. Used for the `html` prop mode where the
5827
+ * embedder hands us a complete document from `mcpClient.readResource(...)` and
5828
+ * we need to splice in the same infrastructure that the `scriptSrc` wrapper
5829
+ * provides. The injection is placed before `</head>` when present, falling
5830
+ * back to the start of `<body>` or the document start.
5831
+ */
5832
+ function injectInfraScripts(html, platformScript) {
5833
+ const fenceTag = `<script data-sunpeak-fence>${PAINT_FENCE_SCRIPT}<\/script>`;
5834
+ const injection = `${platformScript ? `<script>${platformScript}<\/script>` : ""}${fenceTag}${`<script data-sunpeak-helper>${SUNPEAK_INLINE_HELPER_SCRIPT}<\/script>`}`;
5835
+ const headMatch = html.match(/<\/head\s*>/i);
5836
+ if (headMatch) return html.replace(headMatch[0], `${injection}${headMatch[0]}`);
5837
+ const bodyMatch = html.match(/<body([^>]*)>/i);
5838
+ if (bodyMatch) return html.replace(bodyMatch[0], `${bodyMatch[0]}${injection}`);
5839
+ return injection + html;
5840
+ }
5841
+ /**
5686
5842
  * Generates HTML wrapper for a script URL.
5687
5843
  * The MCP Apps SDK in the loaded script handles communication via PostMessageTransport.
5688
5844
  */
@@ -5746,7 +5902,7 @@ function buildIframeAllow(permissions) {
5746
5902
  * connects via PostMessageTransport to window.parent. The parent side uses
5747
5903
  * McpAppHost (wrapping AppBridge) to communicate.
5748
5904
  */
5749
- function IframeResource({ src, scriptSrc, hostContext, toolInput, toolInputPartial, toolResult, hostOptions, csp, permissions, prefersBorder, className, style, onDisplayModeReady, debugInjectState, injectOpenAIRuntime, sandboxUrl }) {
5905
+ function IframeResource({ src, scriptSrc, html, hostContext, toolInput, toolInputPartial, toolResult, hostOptions, csp, permissions, prefersBorder, className, style, onDisplayModeReady, debugInjectState, injectOpenAIRuntime, sandboxUrl }) {
5750
5906
  const iframeRef = useRef(null);
5751
5907
  const hostRef = useRef(null);
5752
5908
  const resourceUrl = src ?? scriptSrc;
@@ -5754,6 +5910,8 @@ function IframeResource({ src, scriptSrc, hostContext, toolInput, toolInputParti
5754
5910
  srcRef.current = src;
5755
5911
  const scriptSrcRef = useRef(scriptSrc);
5756
5912
  scriptSrcRef.current = scriptSrc;
5913
+ const htmlRef = useRef(html);
5914
+ htmlRef.current = html;
5757
5915
  const cspRef = useRef(csp);
5758
5916
  cspRef.current = csp;
5759
5917
  const hostContextRef = useRef(hostContext);
@@ -5803,9 +5961,20 @@ function IframeResource({ src, scriptSrc, hostContext, toolInput, toolInputParti
5803
5961
  onSandboxReady: () => {
5804
5962
  const currentSrc = srcRef.current;
5805
5963
  const currentScriptSrc = scriptSrcRef.current;
5964
+ const currentHtml = htmlRef.current;
5806
5965
  const currentHost = hostRef.current;
5807
5966
  if (!currentHost) return;
5808
- if (currentScriptSrc) {
5967
+ if (currentHtml) {
5968
+ const finalHtml = injectInfraScripts(currentHtml, injectOpenAIRuntimeRef.current ? MOCK_OPENAI_RUNTIME_SCRIPT : void 0);
5969
+ currentHost.sendSandboxResourceReady({
5970
+ html: finalHtml,
5971
+ sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
5972
+ });
5973
+ if (iframeRef.current) {
5974
+ iframeRef.current.style.opacity = "1";
5975
+ iframeRef.current.style.transition = "opacity 100ms";
5976
+ }
5977
+ } else if (currentScriptSrc) {
5809
5978
  const absoluteScriptSrc = currentScriptSrc.startsWith("/") ? `${window.location.origin}${currentScriptSrc}` : currentScriptSrc;
5810
5979
  const cspPolicy = generateCSP(cspRef.current, absoluteScriptSrc);
5811
5980
  const appHtml = generateScriptHtml(absoluteScriptSrc, hostContextRef.current?.theme ?? "dark", cspPolicy, injectOpenAIRuntimeRef.current ? MOCK_OPENAI_RUNTIME_SCRIPT : void 0);
@@ -5876,7 +6045,17 @@ function IframeResource({ src, scriptSrc, hostContext, toolInput, toolInputParti
5876
6045
  const borderStyle = prefersBorder ? { border: "1px solid var(--color-border-primary, #e5e7eb)" } : { border: "none" };
5877
6046
  const sandboxSrc = useMemo(() => {
5878
6047
  if (!sandboxUrl) return void 0;
5879
- const url = new URL("/proxy", sandboxUrl);
6048
+ let url;
6049
+ try {
6050
+ const parsed = new URL(sandboxUrl);
6051
+ url = parsed.pathname && parsed.pathname !== "/" ? parsed : new URL("/proxy", sandboxUrl);
6052
+ } catch {
6053
+ return;
6054
+ }
6055
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
6056
+ console.warn("[IframeResource] Ignoring non-http(s) sandboxUrl:", sandboxUrl);
6057
+ return;
6058
+ }
5880
6059
  if (injectOpenAIRuntime) url.searchParams.set("platform", "chatgpt");
5881
6060
  return url.toString();
5882
6061
  }, [sandboxUrl, injectOpenAIRuntime]);
@@ -6316,6 +6495,7 @@ function useInspectorState({ simulations, defaultHost = "chatgpt" }) {
6316
6495
  }, [toolResult, modelContext]);
6317
6496
  const resourceUrl = selectedSim?.resourceUrl;
6318
6497
  const resourceScript = selectedSim?.resourceScript;
6498
+ const resourceHtml = selectedSim?.resourceHtml;
6319
6499
  const csp = selectedSim?.resource ? extractResourceCSP(selectedSim.resource) : void 0;
6320
6500
  const resourceMeta = (selectedSim?.resource?._meta)?.ui;
6321
6501
  return {
@@ -6382,6 +6562,7 @@ function useInspectorState({ simulations, defaultHost = "chatgpt" }) {
6382
6562
  handleUpdateModelContext,
6383
6563
  resourceUrl,
6384
6564
  resourceScript,
6565
+ resourceHtml,
6385
6566
  csp,
6386
6567
  permissions: resourceMeta?.permissions,
6387
6568
  prefersBorder: resourceMeta?.prefersBorder ?? false,
@@ -6392,6 +6573,40 @@ function useInspectorState({ simulations, defaultHost = "chatgpt" }) {
6392
6573
  };
6393
6574
  }
6394
6575
  //#endregion
6576
+ //#region src/inspector/inspector-api.ts
6577
+ function inspectorApiEndpoint(path, apiBaseUrl) {
6578
+ if (!apiBaseUrl) return path;
6579
+ return `${apiBaseUrl.replace(/\/+$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
6580
+ }
6581
+ async function readInspectorJson(res, endpoint) {
6582
+ const text = await res.text();
6583
+ if (!text) return {};
6584
+ try {
6585
+ return JSON.parse(text);
6586
+ } catch {
6587
+ const contentType = res.headers.get("content-type");
6588
+ const preview = text.trim().replace(/\s+/g, " ").slice(0, 120);
6589
+ const typeHint = contentType ? ` (${contentType})` : "";
6590
+ throw new Error(`Expected JSON from ${endpoint} but received a non-JSON response${typeHint}: ${preview}`);
6591
+ }
6592
+ }
6593
+ function resolveInspectorResourceUrls(simulations, apiBaseUrl) {
6594
+ if (!apiBaseUrl || !simulations || typeof simulations !== "object") return simulations;
6595
+ const resolved = {};
6596
+ for (const [key, value] of Object.entries(simulations)) {
6597
+ if (!value || typeof value !== "object") {
6598
+ resolved[key] = value;
6599
+ continue;
6600
+ }
6601
+ const sim = value;
6602
+ resolved[key] = {
6603
+ ...sim,
6604
+ resourceUrl: typeof sim.resourceUrl === "string" && sim.resourceUrl.startsWith("/") ? inspectorApiEndpoint(sim.resourceUrl, apiBaseUrl) : sim.resourceUrl
6605
+ };
6606
+ }
6607
+ return resolved;
6608
+ }
6609
+ //#endregion
6395
6610
  //#region src/inspector/use-mcp-connection.ts
6396
6611
  /**
6397
6612
  * Hook for managing MCP server connection status via the dev server proxy.
@@ -6404,7 +6619,7 @@ function useInspectorState({ simulations, defaultHost = "chatgpt" }) {
6404
6619
  * once (or safely twice with cancellation), while explicit `reconnect()` calls
6405
6620
  * are triggered by the Inspector's URL-change effect.
6406
6621
  */
6407
- function useMcpConnection(initialServerUrl) {
6622
+ function useMcpConnection(initialServerUrl, inspectorApiBaseUrl) {
6408
6623
  const [status, setStatus] = useState(initialServerUrl ? "connecting" : "disconnected");
6409
6624
  const [error, setError] = useState();
6410
6625
  const [simulations, setSimulations] = useState();
@@ -6416,7 +6631,8 @@ function useMcpConnection(initialServerUrl) {
6416
6631
  try {
6417
6632
  const body = { url };
6418
6633
  if (auth && auth.type !== "none") body.auth = auth;
6419
- const res = await fetch("/__sunpeak/connect", {
6634
+ const endpoint = inspectorApiEndpoint("/__sunpeak/connect", inspectorApiBaseUrl);
6635
+ const res = await fetch(endpoint, {
6420
6636
  method: "POST",
6421
6637
  headers: { "Content-Type": "application/json" },
6422
6638
  body: JSON.stringify(body)
@@ -6424,7 +6640,7 @@ function useMcpConnection(initialServerUrl) {
6424
6640
  if (!res.ok) {
6425
6641
  let message;
6426
6642
  try {
6427
- const json = await res.json();
6643
+ const json = await readInspectorJson(res, endpoint);
6428
6644
  if (json.error) message = json.error;
6429
6645
  } catch {}
6430
6646
  if (!message) if (res.status === 404) message = "Server not found at this URL. Check the URL and make sure the server is running.";
@@ -6432,9 +6648,9 @@ function useMcpConnection(initialServerUrl) {
6432
6648
  else message = `Connection failed (${res.status})`;
6433
6649
  throw new Error(message);
6434
6650
  }
6435
- const data = await res.json();
6651
+ const data = await readInspectorJson(res, endpoint);
6436
6652
  setStatus("connected");
6437
- setSimulations(data.simulations ?? void 0);
6653
+ setSimulations(resolveInspectorResourceUrls(data.simulations, inspectorApiBaseUrl));
6438
6654
  } catch (err) {
6439
6655
  let message = err instanceof Error ? err.message : String(err);
6440
6656
  if (err instanceof TypeError && message === "Failed to fetch") message = "Cannot reach MCP server. Is it running?";
@@ -6442,20 +6658,21 @@ function useMcpConnection(initialServerUrl) {
6442
6658
  setStatus("error");
6443
6659
  setSimulations(void 0);
6444
6660
  }
6445
- }, []);
6661
+ }, [inspectorApiBaseUrl]);
6446
6662
  const setConnected = useCallback((sims) => {
6447
6663
  setHasReconnected(true);
6448
6664
  setStatus("connected");
6449
6665
  setError(void 0);
6450
- setSimulations(sims);
6451
- }, []);
6666
+ setSimulations(resolveInspectorResourceUrls(sims, inspectorApiBaseUrl));
6667
+ }, [inspectorApiBaseUrl]);
6452
6668
  useEffect(() => {
6453
6669
  if (!initialServerUrl) return;
6454
6670
  let cancelled = false;
6455
6671
  setStatus("connecting");
6456
6672
  (async () => {
6457
6673
  try {
6458
- const res = await fetch("/__sunpeak/list-tools");
6674
+ const endpoint = inspectorApiEndpoint("/__sunpeak/list-tools", inspectorApiBaseUrl);
6675
+ const res = await fetch(endpoint);
6459
6676
  if (cancelled) return;
6460
6677
  if (!res.ok) {
6461
6678
  const msg = res.status === 404 ? "MCP server not reachable. Is it running?" : `Health check failed (${res.status}). Check the MCP server logs.`;
@@ -6484,7 +6701,14 @@ function useMcpConnection(initialServerUrl) {
6484
6701
  //#endregion
6485
6702
  //#region src/inspector/theme-provider.tsx
6486
6703
  var ThemeProviderContext = React.createContext(void 0);
6487
- /** Default theme applier: sets data-theme attribute on document.documentElement */
6704
+ /**
6705
+ * Default theme applier: sets `data-theme` on `document.documentElement`.
6706
+ * Kept for callers using `ThemeProvider` outside the bundled `<Inspector />`
6707
+ * (e.g. custom-inspector builds composed from this package's primitives).
6708
+ * The bundled Inspector overrides this with a no-op applier and applies
6709
+ * theme to its own root element, so embedding it inside a host React app
6710
+ * leaves the host's document attributes untouched.
6711
+ */
6488
6712
  function defaultApplyTheme(theme) {
6489
6713
  if (typeof document !== "undefined") document.documentElement.setAttribute("data-theme", theme);
6490
6714
  }
@@ -6527,7 +6751,7 @@ function ChevronRightIcon() {
6527
6751
  })
6528
6752
  });
6529
6753
  }
6530
- function SimpleSidebar({ children, controls, headerRight }) {
6754
+ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent = false }) {
6531
6755
  const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
6532
6756
  const [sidebarWidth, setSidebarWidth] = React.useState(DEFAULT_SIDEBAR_WIDTH);
6533
6757
  const [isResizing, setIsResizing] = React.useState(false);
@@ -6552,7 +6776,8 @@ function SimpleSidebar({ children, controls, headerRight }) {
6552
6776
  };
6553
6777
  }, [isResizing]);
6554
6778
  return /* @__PURE__ */ jsxs("div", {
6555
- className: "sunpeak-inspector-root flex h-screen w-full overflow-hidden relative",
6779
+ ref: rootRef,
6780
+ className: `sunpeak-inspector-root flex ${fillParent ? "h-full w-full" : "h-screen w-full"} overflow-hidden relative`,
6556
6781
  children: [
6557
6782
  isResizing && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 cursor-col-resize" }),
6558
6783
  isDrawerOpen && /* @__PURE__ */ jsx("div", {
@@ -6882,13 +7107,85 @@ function resolveServerToolResult(mock, args) {
6882
7107
  for (const entry of mock) if (Object.entries(entry.when).every(([key, value]) => args != null && args[key] === value)) return entry.result;
6883
7108
  }
6884
7109
  //#endregion
7110
+ //#region src/inspector/app-flatten.ts
7111
+ /** Pull the output-template URI off a tool's _meta, if present. */
7112
+ function getOutputTemplate(toolMeta) {
7113
+ if (!toolMeta || typeof toolMeta !== "object") return void 0;
7114
+ const openai = toolMeta.openai;
7115
+ if (!openai || typeof openai !== "object") return void 0;
7116
+ const template = openai.outputTemplate;
7117
+ return typeof template === "string" ? template : void 0;
7118
+ }
7119
+ /** Build an MCP-shaped `Resource` from the embedder's input. Used purely for
7120
+ * sidebar metadata (CSP, permissions, prefersBorder); the actual HTML render
7121
+ * goes through `resourceHtml` on the resulting Simulation. */
7122
+ function toMcpResource(r) {
7123
+ return {
7124
+ uri: r.uri,
7125
+ mimeType: r.mimeType ?? "text/html",
7126
+ name: r.uri,
7127
+ ...r._meta ? { _meta: r._meta } : {}
7128
+ };
7129
+ }
7130
+ /**
7131
+ * Flatten an `InspectorApp` to the `Record<string, Simulation>` shape the
7132
+ * Inspector consumes internally. Returns an empty map if `app` is missing.
7133
+ */
7134
+ function flattenAppToSimulations(app) {
7135
+ if (!app) return {};
7136
+ const result = {};
7137
+ const resourcesByUri = /* @__PURE__ */ new Map();
7138
+ for (const r of app.resources) {
7139
+ if (resourcesByUri.has(r.uri)) console.warn(`[Inspector] Duplicate resource URI '${r.uri}' in app.resources — the second entry replaces the first.`);
7140
+ resourcesByUri.set(r.uri, r);
7141
+ }
7142
+ for (const appTool of app.tools) {
7143
+ const uri = getOutputTemplate(appTool.tool._meta);
7144
+ if (!uri) continue;
7145
+ const resource = resourcesByUri.get(uri);
7146
+ if (!resource) continue;
7147
+ const mcpResource = toMcpResource(resource);
7148
+ const sims = appTool.simulations && appTool.simulations.length > 0 ? appTool.simulations : [{ name: appTool.tool.name }];
7149
+ for (const sim of sims) {
7150
+ const key = `${appTool.tool.name}__${sim.name}`;
7151
+ if (key in result) console.warn(`[Inspector] Duplicate simulation name '${sim.name}' under tool '${appTool.tool.name}' — the second entry replaces the first.`);
7152
+ result[key] = {
7153
+ name: key,
7154
+ displayName: sim.name,
7155
+ resourceHtml: resource.html,
7156
+ userMessage: sim.userMessage,
7157
+ tool: appTool.tool,
7158
+ resource: mcpResource,
7159
+ toolInput: sim.toolInput,
7160
+ toolResult: sim.toolResult,
7161
+ serverTools: sim.serverTools
7162
+ };
7163
+ }
7164
+ }
7165
+ return result;
7166
+ }
7167
+ //#endregion
6885
7168
  //#region src/inspector/inspector.tsx
6886
7169
  var DOCS_BASE_URL = "https://sunpeak.ai/docs";
6887
7170
  /** Check whether a simulation has user-authored fixture data. */
6888
7171
  function hasFixtureData(sim) {
6889
7172
  return sim.toolResult != null || sim.toolInput != null || sim.serverTools != null;
6890
7173
  }
6891
- function Inspector({ children, simulations: initialSimulations = {}, appName = "Sunpeak", appIcon, defaultHost = "chatgpt", onCallTool, onCallToolDirect, defaultProdResources = false, hideInspectorModes = false, demoMode = false, sandboxUrl, mcpServerUrl }) {
7174
+ var EMPTY_SIMULATIONS = Object.freeze({});
7175
+ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_SIMULATIONS, appName: appNameProp, appIcon: appIconProp, defaultHost = "chatgpt", onCallTool, onCallToolDirect, defaultProdResources = false, hideInspectorModes = false, demoMode = false, sandboxUrl, mcpServerUrl, inspectorApiBaseUrl }) {
7176
+ const initialSimulations = React.useMemo(() => app ? flattenAppToSimulations(app) : initialSimulationsProp, [app, initialSimulationsProp]);
7177
+ const appName = app?.name ?? appNameProp ?? "Sunpeak";
7178
+ const appIcon = app?.icon ?? appIconProp;
7179
+ const isEmbedded = !!app;
7180
+ const conflictWarnedRef = React.useRef(false);
7181
+ React.useEffect(() => {
7182
+ if (conflictWarnedRef.current) return;
7183
+ if (app && initialSimulationsProp && Object.keys(initialSimulationsProp).length > 0) {
7184
+ conflictWarnedRef.current = true;
7185
+ console.warn("[Inspector] Both `app` and `simulations` were provided. `app` takes precedence; `simulations` is ignored.");
7186
+ }
7187
+ }, [app, initialSimulationsProp]);
7188
+ const rootRef = React.useRef(null);
6892
7189
  const [simulations, setSimulations] = React.useState(initialSimulations);
6893
7190
  React.useEffect(() => {
6894
7191
  setSimulations(initialSimulations);
@@ -6971,13 +7268,14 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
6971
7268
  const [oauthClientSecret, setOauthClientSecret] = React.useState("");
6972
7269
  const [oauthStatus, setOauthStatus] = React.useState("none");
6973
7270
  const [oauthError, setOauthError] = React.useState();
6974
- const connection = useMcpConnection(mcpServerUrl || void 0);
7271
+ const connection = useMcpConnection(isEmbedded ? void 0 : mcpServerUrl || void 0, inspectorApiBaseUrl);
6975
7272
  const [prodResources, setProdResources] = React.useState(state.urlProdResources ?? defaultProdResources);
6976
7273
  const showSidebar = state.urlSidebar !== false;
6977
7274
  const showDevOverlay = state.urlDevOverlay !== false;
6978
7275
  const [isRunning, setIsRunning] = React.useState(false);
6979
7276
  const [hasRun, setHasRun] = React.useState(false);
6980
7277
  const [showCheck, setShowCheck] = React.useState(false);
7278
+ const [serverPreviewGeneration, setServerPreviewGeneration] = React.useState(0);
6981
7279
  const checkTimerRef = React.useRef(void 0);
6982
7280
  const oauthCleanupRef = React.useRef(void 0);
6983
7281
  React.useEffect(() => {
@@ -7013,7 +7311,8 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7013
7311
  setOauthError(void 0);
7014
7312
  const popup = window.open("about:blank", `sunpeak-oauth-${Date.now()}`, "width=600,height=700,popup=yes");
7015
7313
  try {
7016
- const res = await fetch("/__sunpeak/oauth/start", {
7314
+ const endpoint = inspectorApiEndpoint("/__sunpeak/oauth/start", inspectorApiBaseUrl);
7315
+ const res = await fetch(endpoint, {
7017
7316
  method: "POST",
7018
7317
  headers: { "Content-Type": "application/json" },
7019
7318
  body: JSON.stringify({
@@ -7023,15 +7322,12 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7023
7322
  clientSecret: oauthClientSecret || void 0
7024
7323
  })
7025
7324
  });
7325
+ const data = await readInspectorJson(res, endpoint);
7026
7326
  if (!res.ok) {
7027
7327
  let message = `OAuth start failed (${res.status})`;
7028
- try {
7029
- const json = await res.json();
7030
- if (json.error) message = json.error;
7031
- } catch {}
7328
+ if (data.error) message = data.error;
7032
7329
  throw new Error(message);
7033
7330
  }
7034
- const data = await res.json();
7035
7331
  if (data.error) {
7036
7332
  popup?.close();
7037
7333
  setOauthError(data.error);
@@ -7045,12 +7341,22 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7045
7341
  return;
7046
7342
  }
7047
7343
  if (data.status === "redirect" && data.authUrl) {
7344
+ let parsedAuthUrl = null;
7345
+ try {
7346
+ parsedAuthUrl = new URL(data.authUrl);
7347
+ } catch {}
7348
+ if (!parsedAuthUrl || parsedAuthUrl.protocol !== "http:" && parsedAuthUrl.protocol !== "https:") {
7349
+ popup?.close();
7350
+ setOauthError("OAuth authorization URL is not a valid http(s) URL.");
7351
+ setOauthStatus("error");
7352
+ return;
7353
+ }
7048
7354
  if (!popup || popup.closed) {
7049
7355
  setOauthError("Popup was blocked. Allow popups for this site and try again.");
7050
7356
  setOauthStatus("error");
7051
7357
  return;
7052
7358
  }
7053
- popup.location.href = data.authUrl;
7359
+ popup.location.href = parsedAuthUrl.toString();
7054
7360
  let checkClosed;
7055
7361
  let bc;
7056
7362
  const cleanup = () => {
@@ -7102,11 +7408,14 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7102
7408
  oauthClientId,
7103
7409
  oauthClientSecret,
7104
7410
  demoMode,
7105
- connection
7411
+ connection,
7412
+ inspectorApiBaseUrl
7106
7413
  ]);
7107
7414
  React.useEffect(() => {
7108
- if (connection.simulations) setSimulations(connection.simulations);
7109
- else if (connection.status === "error" && connection.hasReconnected) setSimulations({});
7415
+ if (connection.simulations) {
7416
+ setSimulations(connection.simulations);
7417
+ setServerPreviewGeneration((generation) => generation + 1);
7418
+ } else if (connection.status === "error" && connection.hasReconnected) setSimulations({});
7110
7419
  }, [
7111
7420
  connection.simulations,
7112
7421
  connection.status,
@@ -7239,15 +7548,23 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7239
7548
  displayMode,
7240
7549
  setDisplayMode
7241
7550
  ]);
7242
- React.useLayoutEffect(() => {
7243
- const vars = activeShell?.styleVariables;
7244
- if (!vars) return;
7245
- const root = document.documentElement;
7246
- for (const [key, value] of Object.entries(vars)) if (value) root.style.setProperty(key, value);
7247
- }, [activeShell]);
7551
+ const prevStyleVarKeysRef = React.useRef([]);
7248
7552
  const prevPageStyleKeysRef = React.useRef([]);
7249
7553
  React.useLayoutEffect(() => {
7250
- const root = document.documentElement;
7554
+ const root = rootRef.current;
7555
+ if (!root) return;
7556
+ root.setAttribute("data-theme", state.theme);
7557
+ root.style.colorScheme = state.theme;
7558
+ for (const key of prevStyleVarKeysRef.current) root.style.removeProperty(key);
7559
+ const vars = activeShell?.styleVariables;
7560
+ if (vars) {
7561
+ const keys = [];
7562
+ for (const [key, value] of Object.entries(vars)) if (value) {
7563
+ root.style.setProperty(key, value);
7564
+ keys.push(key);
7565
+ }
7566
+ prevStyleVarKeysRef.current = keys;
7567
+ } else prevStyleVarKeysRef.current = [];
7251
7568
  for (const key of prevPageStyleKeysRef.current) root.style.removeProperty(key);
7252
7569
  const pageStyles = activeShell?.pageStyles;
7253
7570
  if (pageStyles) {
@@ -7258,7 +7575,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7258
7575
  }
7259
7576
  prevPageStyleKeysRef.current = keys;
7260
7577
  } else prevPageStyleKeysRef.current = [];
7261
- }, [activeShell]);
7578
+ }, [activeShell, state.theme]);
7262
7579
  React.useLayoutEffect(() => {
7263
7580
  const fontCss = activeShell?.fontCss;
7264
7581
  const id = "sunpeak-host-fonts";
@@ -7349,7 +7666,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7349
7666
  children: /* @__PURE__ */ jsx("span", {
7350
7667
  className: "text-sm text-center max-w-xs",
7351
7668
  style: { color: "var(--color-text-secondary)" },
7352
- children: isError ? "Could not connect to MCP server" : isConnected ? "No tools with UI resources found on this server" : serverUrl ? "Connecting…" : "Enter an MCP server URL to get started"
7669
+ children: isEmbedded ? "No tools with UI resources in this app" : isError ? "Could not connect to MCP server" : isConnected ? "No tools with UI resources found on this server" : serverUrl ? "Connecting…" : "Enter an MCP server URL to get started"
7353
7670
  })
7354
7671
  });
7355
7672
  } else if (showEmptyState) content = /* @__PURE__ */ jsx("div", {
@@ -7374,6 +7691,30 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7374
7691
  children: "Building…"
7375
7692
  })
7376
7693
  });
7694
+ else if (state.resourceHtml) content = /* @__PURE__ */ jsx("div", {
7695
+ className: "h-full w-full",
7696
+ style: { background: iframeBg },
7697
+ children: /* @__PURE__ */ jsx(IframeResource, {
7698
+ html: state.resourceHtml,
7699
+ hostContext,
7700
+ toolInput: state.toolInput,
7701
+ toolResult: state.effectiveToolResult,
7702
+ hostOptions: {
7703
+ hostInfo: activeShell?.hostInfo,
7704
+ hostCapabilities: activeShell?.hostCapabilities,
7705
+ onDisplayModeChange: state.handleDisplayModeChange,
7706
+ onUpdateModelContext: state.handleUpdateModelContext,
7707
+ onCallTool: handleCallTool
7708
+ },
7709
+ permissions: state.permissions,
7710
+ prefersBorder: state.prefersBorder,
7711
+ onDisplayModeReady: state.handleDisplayModeReady,
7712
+ debugInjectState: state.modelContext,
7713
+ injectOpenAIRuntime: state.activeHost === "chatgpt",
7714
+ sandboxUrl,
7715
+ className: "h-full w-full"
7716
+ }, `${state.activeHost}-${state.selectedSimulationName}-html`)
7717
+ });
7377
7718
  else if (effectiveResourceUrl) content = /* @__PURE__ */ jsx("div", {
7378
7719
  className: "h-full w-full",
7379
7720
  style: { background: iframeBg },
@@ -7396,7 +7737,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7396
7737
  injectOpenAIRuntime: state.activeHost === "chatgpt",
7397
7738
  sandboxUrl,
7398
7739
  className: "h-full w-full"
7399
- }, `${state.activeHost}-${state.selectedSimulationName}-${effectiveResourceUrl}-${prodResources}-${prodResourcesGeneration}`)
7740
+ }, `${state.activeHost}-${state.selectedSimulationName}-${effectiveResourceUrl}-${prodResources}-${prodResourcesGeneration}-${serverPreviewGeneration}`)
7400
7741
  });
7401
7742
  else if (!prodResources && state.resourceScript) content = /* @__PURE__ */ jsx("div", {
7402
7743
  className: "h-full w-full",
@@ -7424,7 +7765,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7424
7765
  }, `${state.activeHost}-${state.selectedSimulationName}-${state.resourceScript}`)
7425
7766
  });
7426
7767
  else content = children;
7427
- const applyTheme = activeShell?.applyTheme;
7768
+ const applyTheme = React.useCallback((_theme) => {}, []);
7428
7769
  const runButton = !demoMode && onCallTool && currentSim && activeSimulationName === null ? /* @__PURE__ */ jsxs("button", {
7429
7770
  type: "button",
7430
7771
  onClick: handleRun,
@@ -7464,11 +7805,13 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7464
7805
  headerAction: runButton,
7465
7806
  children: content
7466
7807
  }) : content;
7808
+ const rootSizing = isEmbedded ? "h-full w-full" : "h-screen w-screen";
7467
7809
  if (!showSidebar) return /* @__PURE__ */ jsx(ThemeProvider, {
7468
7810
  theme: state.theme,
7469
7811
  applyTheme,
7470
7812
  children: /* @__PURE__ */ jsx("div", {
7471
- className: "flex h-screen w-screen",
7813
+ ref: rootRef,
7814
+ className: `sunpeak-inspector-root flex ${rootSizing}`,
7472
7815
  children: conversationContent
7473
7816
  })
7474
7817
  });
@@ -7476,10 +7819,12 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7476
7819
  theme: state.theme,
7477
7820
  applyTheme,
7478
7821
  children: [/* @__PURE__ */ jsx(SimpleSidebar, {
7822
+ rootRef,
7823
+ fillParent: isEmbedded,
7479
7824
  controls: /* @__PURE__ */ jsxs("div", {
7480
7825
  className: "space-y-1",
7481
7826
  children: [
7482
- /* @__PURE__ */ jsx(SidebarControl, {
7827
+ !isEmbedded && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarControl, {
7483
7828
  label: /* @__PURE__ */ jsxs("span", {
7484
7829
  className: "flex items-center gap-1.5",
7485
7830
  children: ["MCP Server", serverUrl && !demoMode && /* @__PURE__ */ jsx("span", {
@@ -7498,8 +7843,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7498
7843
  placeholder: "http://localhost:8000/mcp",
7499
7844
  disabled: demoMode
7500
7845
  })
7501
- }),
7502
- !demoMode && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
7846
+ }), !demoMode && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
7503
7847
  label: "Authentication",
7504
7848
  defaultCollapsed: authType === "none",
7505
7849
  children: /* @__PURE__ */ jsxs("div", {
@@ -7584,8 +7928,8 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7584
7928
  })
7585
7929
  ]
7586
7930
  })
7587
- }, `auth-${authType === "none" ? "none" : "active"}`),
7588
- !hideInspectorModes && !demoMode && /* @__PURE__ */ jsx(SidebarCheckbox, {
7931
+ }, `auth-${authType === "none" ? "none" : "active"}`)] }),
7932
+ !hideInspectorModes && !demoMode && !isEmbedded && /* @__PURE__ */ jsx(SidebarCheckbox, {
7589
7933
  checked: prodResources,
7590
7934
  onChange: setProdResources,
7591
7935
  label: "Prod Resources",
@@ -7636,7 +7980,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
7636
7980
  label: selectedToolInfo && selectedToolInfo.fixtureSimNames.length > 0 ? "None (call server)" : "None"
7637
7981
  }], ...(selectedToolInfo?.fixtureSimNames ?? []).map((simName) => ({
7638
7982
  value: simName,
7639
- label: simName
7983
+ label: simulations[simName]?.displayName ?? simName
7640
7984
  }))]
7641
7985
  })
7642
7986
  })]
@@ -8016,6 +8360,6 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
8016
8360
  });
8017
8361
  }
8018
8362
  //#endregion
8019
- export { DEFAULT_STYLE_VARIABLES as C, cn as S, McpAppHost as _, SidebarControl as a, getRegisteredHosts as b, SidebarTextarea as c, ThemeProvider as d, useThemeContext as f, extractResourceCSP as g, IframeResource as h, SidebarCollapsibleControl as i, SidebarToggle as l, useInspectorState as m, resolveServerToolResult as n, SidebarInput as o, useMcpConnection as p, SidebarCheckbox as r, SidebarSelect as s, Inspector as t, SimpleSidebar as u, SCREEN_WIDTHS as v, registerHostShell as x, getHostShell as y };
8363
+ export { cn as C, registerHostShell as S, extractResourceCSP as _, SidebarCollapsibleControl as a, getHostShell as b, SidebarSelect as c, SimpleSidebar as d, ThemeProvider as f, IframeResource as g, useInspectorState as h, SidebarCheckbox as i, SidebarTextarea as l, useMcpConnection as m, flattenAppToSimulations as n, SidebarControl as o, useThemeContext as p, resolveServerToolResult as r, SidebarInput as s, Inspector as t, SidebarToggle as u, McpAppHost as v, DEFAULT_STYLE_VARIABLES as w, getRegisteredHosts as x, SCREEN_WIDTHS as y };
8020
8364
 
8021
- //# sourceMappingURL=inspector-CJNvLoHo.js.map
8365
+ //# sourceMappingURL=inspector-B1355aXh.js.map