sunpeak 0.20.34 → 0.20.36

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 (43) hide show
  1. package/bin/commands/inspect.mjs +63 -10
  2. package/bin/commands/test-init.mjs +57 -44
  3. package/bin/lib/test/test-fixtures.d.mts +9 -1
  4. package/bin/lib/test/test-fixtures.mjs +25 -7
  5. package/dist/chatgpt/index.cjs +1 -1
  6. package/dist/chatgpt/index.js +1 -1
  7. package/dist/claude/index.cjs +1 -1
  8. package/dist/claude/index.js +1 -1
  9. package/dist/embed.css +1 -1
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/inspector/app-types.d.ts +6 -4
  13. package/dist/inspector/index.cjs +1 -1
  14. package/dist/inspector/index.cjs.map +1 -1
  15. package/dist/inspector/index.d.ts +1 -1
  16. package/dist/inspector/index.js +1 -1
  17. package/dist/inspector/index.js.map +1 -1
  18. package/dist/inspector/inspector.d.ts +10 -4
  19. package/dist/inspector/simple-sidebar.d.ts +20 -6
  20. package/dist/inspector/use-inspector-state.d.ts +10 -0
  21. package/dist/{inspector-CJA_uM9g.cjs → inspector-BNWla95w.cjs} +307 -149
  22. package/dist/{inspector-CJA_uM9g.cjs.map → inspector-BNWla95w.cjs.map} +1 -1
  23. package/dist/{inspector-mGvDvMCR.js → inspector-CiuT_2yA.js} +307 -149
  24. package/dist/{inspector-mGvDvMCR.js.map → inspector-CiuT_2yA.js.map} +1 -1
  25. package/dist/style.css +6 -24
  26. package/package.json +1 -1
  27. package/template/dist/albums/albums.html +1 -1
  28. package/template/dist/albums/albums.json +1 -1
  29. package/template/dist/carousel/carousel.html +1 -1
  30. package/template/dist/carousel/carousel.json +1 -1
  31. package/template/dist/map/map.html +1 -1
  32. package/template/dist/map/map.json +1 -1
  33. package/template/dist/review/review.html +1 -1
  34. package/template/dist/review/review.json +1 -1
  35. package/template/tests/e2e/visual.spec.ts +0 -8
  36. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-chatgpt-darwin.png +0 -0
  37. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-chatgpt-linux.png +0 -0
  38. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-darwin.png +0 -0
  39. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-linux.png +0 -0
  40. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-chatgpt-darwin.png +0 -0
  41. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-chatgpt-linux.png +0 -0
  42. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-claude-darwin.png +0 -0
  43. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-claude-linux.png +0 -0
@@ -6434,6 +6434,7 @@ function IframeResource({ src, scriptSrc, html, hostContext, toolInput, toolInpu
6434
6434
  var DEFAULT_THEME = "dark";
6435
6435
  var DEFAULT_DISPLAY_MODE = "inline";
6436
6436
  var DEFAULT_PLATFORM = "desktop";
6437
+ var DEFAULT_SIDEBAR_WIDTH$1 = 260;
6437
6438
  /**
6438
6439
  * Parse URL params for initial inspector values.
6439
6440
  * Supported params:
@@ -6560,6 +6561,8 @@ function sanitizeStoredPrefs(raw) {
6560
6561
  if (typeof obj.hover === "boolean") prefs.hover = obj.hover;
6561
6562
  if (typeof obj.touch === "boolean") prefs.touch = obj.touch;
6562
6563
  if (typeof obj.screenWidth === "string" && VALID_SCREEN_WIDTHS.has(obj.screenWidth)) prefs.screenWidth = obj.screenWidth;
6564
+ if (typeof obj.sidebarWidth === "number" && Number.isFinite(obj.sidebarWidth)) prefs.sidebarWidth = Math.max(DEFAULT_SIDEBAR_WIDTH$1, Math.round(obj.sidebarWidth));
6565
+ if (typeof obj.rightSidebarWidth === "number" && Number.isFinite(obj.rightSidebarWidth)) prefs.rightSidebarWidth = Math.max(DEFAULT_SIDEBAR_WIDTH$1, Math.round(obj.rightSidebarWidth));
6563
6566
  return prefs;
6564
6567
  }
6565
6568
  function readStoredPrefs() {
@@ -6590,29 +6593,31 @@ function deriveContainerDimensions({ displayMode, containerHeight, containerWidt
6590
6593
  if (measuredContentWidth != null) return { maxWidth: measuredContentWidth };
6591
6594
  }
6592
6595
  function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolDataOnSimulationChange = false }) {
6593
- const simulationNames = Object.keys(simulations).filter((name) => simulations[name].resource).sort((a, b) => {
6596
+ const simulationNames = Object.keys(simulations).sort((a, b) => {
6594
6597
  const simA = simulations[a];
6595
6598
  const simB = simulations[b];
6596
- const resourceLabelA = simA.resource.title || simA.resource.name;
6597
- const resourceLabelB = simB.resource.title || simB.resource.name;
6598
- const labelA = `${resourceLabelA}: ${simA.tool.title || simA.tool.name}`;
6599
- const labelB = `${resourceLabelB}: ${simB.tool.title || simB.tool.name}`;
6599
+ const resourceLabelA = simA.resource ? `${simA.resource.title || simA.resource.name}: ` : "";
6600
+ const resourceLabelB = simB.resource ? `${simB.resource.title || simB.resource.name}: ` : "";
6601
+ const labelA = `${resourceLabelA}${simA.tool.title || simA.tool.name}`;
6602
+ const labelB = `${resourceLabelB}${simB.tool.title || simB.tool.name}`;
6600
6603
  return labelA.localeCompare(labelB);
6601
6604
  });
6605
+ const defaultSimulationName = simulationNames.find((name) => !!simulations[name]?.resource) ?? simulationNames[0] ?? "";
6602
6606
  const urlParams = useMemo(() => parseUrlParams(), []);
6603
6607
  const autoRun = urlParams.autoRun === true;
6604
6608
  const storedPrefs = useMemo(() => autoRun ? {} : readStoredPrefs(), [autoRun]);
6605
6609
  const [screenWidth, setScreenWidth] = useState(storedPrefs.screenWidth ?? "full");
6610
+ const [sidebarWidth, setSidebarWidth] = useState(storedPrefs.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH$1);
6611
+ const [rightSidebarWidth, setRightSidebarWidth] = useState(storedPrefs.rightSidebarWidth ?? DEFAULT_SIDEBAR_WIDTH$1);
6606
6612
  const isMobileWidth = (width) => width === "mobile-s" || width === "mobile-l";
6607
6613
  const [activeHost, setActiveHost] = useState(urlParams.host ?? storedPrefs.activeHost ?? defaultHost);
6608
6614
  const [selectedSimulationName, setSelectedSimulationName] = useState(useMemo(() => {
6609
- const defaultName = simulationNames[0] ?? "";
6610
- if (!urlParams.simulation) return defaultName;
6611
- return urlParams.simulation in simulations ? urlParams.simulation : defaultName;
6615
+ if (!urlParams.simulation) return defaultSimulationName;
6616
+ return urlParams.simulation in simulations ? urlParams.simulation : defaultSimulationName;
6612
6617
  }, [
6613
6618
  urlParams.simulation,
6614
6619
  simulations,
6615
- simulationNames
6620
+ defaultSimulationName
6616
6621
  ]));
6617
6622
  const selectedSim = simulations[selectedSimulationName];
6618
6623
  const [theme, setTheme] = useState(urlParams.theme ?? storedPrefs.theme ?? DEFAULT_THEME);
@@ -6651,7 +6656,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6651
6656
  platform,
6652
6657
  hover,
6653
6658
  touch,
6654
- screenWidth
6659
+ screenWidth,
6660
+ sidebarWidth,
6661
+ rightSidebarWidth
6655
6662
  };
6656
6663
  localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
6657
6664
  } catch {}
@@ -6667,7 +6674,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6667
6674
  platform,
6668
6675
  hover,
6669
6676
  touch,
6670
- screenWidth
6677
+ screenWidth,
6678
+ sidebarWidth,
6679
+ rightSidebarWidth
6671
6680
  ]);
6672
6681
  const [measuredContentWidth, setMeasuredContentWidth] = useState(void 0);
6673
6682
  const handleContentWidthChange = useCallback((width) => {
@@ -6731,6 +6740,7 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6731
6740
  const [toolResultJson, setToolResultJson] = useState(() => JSON.stringify(toolResult ?? null, null, 2));
6732
6741
  const [modelContextJson, setModelContextJson] = useState("null");
6733
6742
  const [modelContext, setModelContext] = useState(null);
6743
+ const [modelAppContext, setModelAppContext] = useState(null);
6734
6744
  const [editingField, setEditingField] = useState(null);
6735
6745
  const [toolInputError, setToolInputError] = useState("");
6736
6746
  const [toolResultError, setToolResultError] = useState("");
@@ -6750,8 +6760,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6750
6760
  setToolResultError("");
6751
6761
  }
6752
6762
  if (editingField !== "modelContext") {
6753
- setModelContextJson("null");
6754
6763
  setModelContext(null);
6764
+ setModelAppContext(null);
6765
+ setModelContextJson("null");
6755
6766
  setModelContextError("");
6756
6767
  }
6757
6768
  }, [
@@ -6776,6 +6787,10 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6776
6787
  };
6777
6788
  const handleUpdateModelContext = (content, structuredContent) => {
6778
6789
  setModelContextJson(JSON.stringify(structuredContent ?? content, null, 2));
6790
+ setModelAppContext(structuredContent === void 0 && content.length === 0 ? null : {
6791
+ content,
6792
+ ...structuredContent !== void 0 ? { structuredContent } : {}
6793
+ });
6779
6794
  };
6780
6795
  const validateJSON = (json, setJson, setError) => {
6781
6796
  setJson(json);
@@ -6824,6 +6839,10 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6824
6839
  setActiveHost,
6825
6840
  screenWidth,
6826
6841
  setScreenWidth,
6842
+ sidebarWidth,
6843
+ setSidebarWidth,
6844
+ rightSidebarWidth,
6845
+ setRightSidebarWidth,
6827
6846
  theme,
6828
6847
  setTheme,
6829
6848
  displayMode,
@@ -6857,6 +6876,8 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6857
6876
  effectiveToolResult,
6858
6877
  modelContext,
6859
6878
  setModelContext,
6879
+ modelAppContext,
6880
+ setModelAppContext,
6860
6881
  toolInputJson,
6861
6882
  setToolInputJson,
6862
6883
  toolInputError,
@@ -7052,9 +7073,10 @@ var useThemeContext = () => {
7052
7073
  if (context === void 0) throw new Error("useThemeContext must be used within a ThemeProvider");
7053
7074
  return context;
7054
7075
  };
7055
- //#endregion
7056
- //#region src/inspector/simple-sidebar.tsx
7057
- var DEFAULT_SIDEBAR_WIDTH = 260;
7076
+ function clampSidebarWidth(rawWidth, viewportWidth) {
7077
+ const maxWidth = Math.floor(viewportWidth / 3);
7078
+ return Math.max(260, Math.min(maxWidth, rawWidth));
7079
+ }
7058
7080
  function ChevronRightIcon() {
7059
7081
  return /* @__PURE__ */ jsx("svg", {
7060
7082
  width: "1em",
@@ -7068,19 +7090,34 @@ function ChevronRightIcon() {
7068
7090
  })
7069
7091
  });
7070
7092
  }
7071
- function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent = false }) {
7093
+ function SimpleSidebar({ children, controls, rightControls, sidebarWidth, rightSidebarWidth, onSidebarWidthChange, onRightSidebarWidthChange, headerRight, rootRef, fillParent = false }) {
7072
7094
  const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
7073
- const [sidebarWidth, setSidebarWidth] = React.useState(DEFAULT_SIDEBAR_WIDTH);
7095
+ const [internalSidebarWidth, setInternalSidebarWidth] = React.useState(260);
7096
+ const [internalRightSidebarWidth, setInternalRightSidebarWidth] = React.useState(260);
7074
7097
  const [isResizing, setIsResizing] = React.useState(false);
7098
+ const [isResizingRight, setIsResizingRight] = React.useState(false);
7099
+ const effectiveSidebarWidth = sidebarWidth ?? internalSidebarWidth;
7100
+ const effectiveRightSidebarWidth = rightSidebarWidth ?? internalRightSidebarWidth;
7101
+ const setSidebarWidth = React.useCallback((width) => {
7102
+ setInternalSidebarWidth(width);
7103
+ onSidebarWidthChange?.(width);
7104
+ }, [onSidebarWidthChange]);
7105
+ const setRightSidebarWidth = React.useCallback((width) => {
7106
+ setInternalRightSidebarWidth(width);
7107
+ onRightSidebarWidthChange?.(width);
7108
+ }, [onRightSidebarWidthChange]);
7075
7109
  const handleMouseDown = React.useCallback((e) => {
7076
7110
  e.preventDefault();
7077
7111
  setIsResizing(true);
7078
7112
  }, []);
7113
+ const handleRightMouseDown = React.useCallback((e) => {
7114
+ e.preventDefault();
7115
+ setIsResizingRight(true);
7116
+ }, []);
7079
7117
  React.useEffect(() => {
7080
7118
  if (!isResizing) return;
7081
7119
  const handleMouseMove = (e) => {
7082
- const maxWidth = Math.floor(window.innerWidth / 3);
7083
- setSidebarWidth(Math.min(maxWidth, Math.max(DEFAULT_SIDEBAR_WIDTH, e.clientX)));
7120
+ setSidebarWidth(clampSidebarWidth(e.clientX, window.innerWidth));
7084
7121
  };
7085
7122
  const handleMouseUp = () => {
7086
7123
  setIsResizing(false);
@@ -7091,12 +7128,27 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7091
7128
  document.removeEventListener("mousemove", handleMouseMove);
7092
7129
  document.removeEventListener("mouseup", handleMouseUp);
7093
7130
  };
7094
- }, [isResizing]);
7131
+ }, [isResizing, setSidebarWidth]);
7132
+ React.useEffect(() => {
7133
+ if (!isResizingRight) return;
7134
+ const handleMouseMove = (e) => {
7135
+ setRightSidebarWidth(clampSidebarWidth(window.innerWidth - e.clientX, window.innerWidth));
7136
+ };
7137
+ const handleMouseUp = () => {
7138
+ setIsResizingRight(false);
7139
+ };
7140
+ document.addEventListener("mousemove", handleMouseMove);
7141
+ document.addEventListener("mouseup", handleMouseUp);
7142
+ return () => {
7143
+ document.removeEventListener("mousemove", handleMouseMove);
7144
+ document.removeEventListener("mouseup", handleMouseUp);
7145
+ };
7146
+ }, [isResizingRight, setRightSidebarWidth]);
7095
7147
  return /* @__PURE__ */ jsxs("div", {
7096
7148
  ref: rootRef,
7097
7149
  className: `sunpeak-inspector-root flex ${fillParent ? "h-full w-full" : "h-screen w-full"} overflow-hidden relative`,
7098
7150
  children: [
7099
- isResizing && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 cursor-col-resize" }),
7151
+ (isResizing || isResizingRight) && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 cursor-col-resize" }),
7100
7152
  isDrawerOpen && /* @__PURE__ */ jsx("div", {
7101
7153
  className: "md:hidden fixed inset-0 bg-black/50 z-40 pointer-events-auto",
7102
7154
  onClick: (e) => {
@@ -7112,7 +7164,7 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7112
7164
  ${isDrawerOpen ? "max-md:translate-x-0" : "max-md:-translate-x-full"}
7113
7165
  `,
7114
7166
  style: {
7115
- width: sidebarWidth,
7167
+ width: effectiveSidebarWidth,
7116
7168
  borderRight: "1px solid var(--color-border-primary)"
7117
7169
  },
7118
7170
  children: [/* @__PURE__ */ jsx("div", {
@@ -7165,19 +7217,69 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7165
7217
  "aria-label": "Open sidebar",
7166
7218
  children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
7167
7219
  }), children]
7220
+ }),
7221
+ rightControls && /* @__PURE__ */ jsxs("aside", {
7222
+ className: "relative hidden md:flex flex-col bg-sidebar",
7223
+ style: {
7224
+ width: effectiveRightSidebarWidth,
7225
+ borderLeft: "1px solid var(--color-border-primary)"
7226
+ },
7227
+ children: [/* @__PURE__ */ jsx("div", {
7228
+ className: "flex-1 min-h-0 overflow-y-auto px-3 pb-3 pt-2",
7229
+ children: rightControls
7230
+ }), /* @__PURE__ */ jsx("div", {
7231
+ onMouseDown: handleRightMouseDown,
7232
+ className: "hidden md:block absolute top-0 left-0 w-1 h-full cursor-col-resize hover:bg-black/10 dark:hover:bg-white/10 active:bg-black/20 dark:active:bg-white/20 transition-colors"
7233
+ })]
7168
7234
  })
7169
7235
  ]
7170
7236
  });
7171
7237
  }
7172
7238
  var DOCS_BASE_URL$1 = "https://sunpeak.ai/docs";
7173
- function HelpIcon({ tooltip, docsPath }) {
7239
+ function HelpIcon({ tooltip, docsPath, placement = "right" }) {
7240
+ const linkRef = React.useRef(null);
7241
+ const [isTooltipVisible, setIsTooltipVisible] = React.useState(false);
7242
+ const [tooltipPosition, setTooltipPosition] = React.useState({
7243
+ left: 0,
7244
+ top: 0
7245
+ });
7246
+ const tooltipOffset = 8;
7247
+ const tooltipTransform = placement === "left" ? "translate(-100%, -50%)" : "translateY(-50%)";
7248
+ const setTooltipFromPoint = React.useCallback((clientX, clientY) => {
7249
+ setTooltipPosition({
7250
+ left: placement === "left" ? clientX - tooltipOffset : clientX + tooltipOffset,
7251
+ top: clientY
7252
+ });
7253
+ }, [placement]);
7254
+ const setTooltipFromIcon = React.useCallback(() => {
7255
+ const rect = linkRef.current?.getBoundingClientRect();
7256
+ if (!rect) return;
7257
+ setTooltipPosition({
7258
+ left: placement === "left" ? rect.left - tooltipOffset : rect.right + tooltipOffset,
7259
+ top: rect.top + rect.height / 2
7260
+ });
7261
+ }, [placement]);
7174
7262
  return /* @__PURE__ */ jsxs("a", {
7263
+ ref: linkRef,
7175
7264
  href: `${DOCS_BASE_URL$1}/${docsPath}`,
7176
7265
  target: "_blank",
7177
7266
  rel: "noopener noreferrer",
7178
7267
  "aria-label": tooltip,
7179
7268
  className: "group relative inline-flex items-center justify-center no-underline flex-shrink-0 transition-colors",
7180
7269
  style: { color: "var(--color-text-tertiary, var(--color-text-secondary))" },
7270
+ onMouseEnter: (e) => {
7271
+ setIsTooltipVisible(true);
7272
+ setTooltipFromPoint(e.clientX, e.clientY);
7273
+ },
7274
+ onMouseMove: (e) => {
7275
+ setTooltipFromPoint(e.clientX, e.clientY);
7276
+ },
7277
+ onMouseLeave: () => setIsTooltipVisible(false),
7278
+ onFocus: () => {
7279
+ setIsTooltipVisible(true);
7280
+ setTooltipFromIcon();
7281
+ },
7282
+ onBlur: () => setIsTooltipVisible(false),
7181
7283
  onClick: (e) => e.stopPropagation(),
7182
7284
  children: [/* @__PURE__ */ jsxs("svg", {
7183
7285
  width: "12",
@@ -7203,8 +7305,11 @@ function HelpIcon({ tooltip, docsPath }) {
7203
7305
  })]
7204
7306
  }), /* @__PURE__ */ jsx("span", {
7205
7307
  "aria-hidden": "true",
7206
- className: "pointer-events-none absolute left-full top-1/2 z-[200] ml-1.5 hidden -translate-y-1/2 whitespace-nowrap rounded px-2 py-1 text-[11px] font-normal leading-tight group-hover:block group-focus-within:block",
7308
+ className: `pointer-events-none fixed z-[1000] whitespace-nowrap rounded px-2 py-1 text-[11px] font-normal leading-tight ${isTooltipVisible ? "block" : "hidden"}`,
7207
7309
  style: {
7310
+ left: tooltipPosition.left,
7311
+ top: tooltipPosition.top,
7312
+ transform: tooltipTransform,
7208
7313
  backgroundColor: "var(--color-text-primary)",
7209
7314
  color: "var(--color-background-primary)"
7210
7315
  },
@@ -7212,7 +7317,7 @@ function HelpIcon({ tooltip, docsPath }) {
7212
7317
  })]
7213
7318
  });
7214
7319
  }
7215
- function SidebarControl({ label, children, tooltip, docsPath, "data-testid": testId }) {
7320
+ function SidebarControl({ label, children, tooltip, tooltipPlacement, docsPath, "data-testid": testId }) {
7216
7321
  return /* @__PURE__ */ jsxs("div", {
7217
7322
  className: "space-y-1",
7218
7323
  "data-testid": testId,
@@ -7221,15 +7326,17 @@ function SidebarControl({ label, children, tooltip, docsPath, "data-testid": tes
7221
7326
  style: { color: "var(--color-text-secondary)" },
7222
7327
  children: [label, tooltip && docsPath && /* @__PURE__ */ jsx(HelpIcon, {
7223
7328
  tooltip,
7224
- docsPath
7329
+ docsPath,
7330
+ placement: tooltipPlacement
7225
7331
  })]
7226
7332
  }), children]
7227
7333
  });
7228
7334
  }
7229
- function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, tooltip, docsPath, "data-testid": testId }) {
7335
+ function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, className, contentClassName, style, tooltip, tooltipPlacement, docsPath, "data-testid": testId }) {
7230
7336
  const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed);
7231
7337
  return /* @__PURE__ */ jsxs("div", {
7232
- className: "space-y-1",
7338
+ className: className ? `space-y-1 ${className}` : "space-y-1",
7339
+ style: isCollapsed ? void 0 : style,
7233
7340
  "data-testid": testId,
7234
7341
  children: [/* @__PURE__ */ jsxs("button", {
7235
7342
  onClick: () => setIsCollapsed(!isCollapsed),
@@ -7240,13 +7347,17 @@ function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, t
7240
7347
  className: "inline-flex items-center gap-1",
7241
7348
  children: [label, tooltip && docsPath && /* @__PURE__ */ jsx(HelpIcon, {
7242
7349
  tooltip,
7243
- docsPath
7350
+ docsPath,
7351
+ placement: tooltipPlacement
7244
7352
  })]
7245
7353
  }), /* @__PURE__ */ jsx("span", {
7246
7354
  className: "text-[8px]",
7247
7355
  children: isCollapsed ? "▶" : "▼"
7248
7356
  })]
7249
- }), !isCollapsed && children]
7357
+ }), !isCollapsed && /* @__PURE__ */ jsx("div", {
7358
+ className: contentClassName,
7359
+ children
7360
+ })]
7250
7361
  });
7251
7362
  }
7252
7363
  var formElementStyle = {
@@ -7321,7 +7432,7 @@ function SidebarInput({ value, onChange, applyOnBlur = false, autoComplete, plac
7321
7432
  }
7322
7433
  });
7323
7434
  }
7324
- function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7435
+ function SidebarCheckbox({ checked, onChange, label, tooltip, tooltipPlacement, docsPath }) {
7325
7436
  const id = React.useId();
7326
7437
  return /* @__PURE__ */ jsxs("div", {
7327
7438
  className: "flex items-center gap-1.5",
@@ -7341,24 +7452,25 @@ function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7341
7452
  }),
7342
7453
  tooltip && docsPath && /* @__PURE__ */ jsx(HelpIcon, {
7343
7454
  tooltip,
7344
- docsPath
7455
+ docsPath,
7456
+ placement: tooltipPlacement
7345
7457
  })
7346
7458
  ]
7347
7459
  });
7348
7460
  }
7349
- function SidebarTextarea({ value, onChange, onFocus, onBlur, placeholder, maxRows = 8, error, "data-testid": testId }) {
7461
+ function SidebarTextarea({ value, onChange, onFocus, onBlur, placeholder, maxRows = 8, fill = false, error, "data-testid": testId }) {
7350
7462
  const contentRows = value?.split("\n").length ?? 1;
7351
7463
  return /* @__PURE__ */ jsxs("div", {
7352
- className: "space-y-0.5",
7464
+ className: fill ? "flex h-full min-h-0 flex-col gap-0.5" : "space-y-0.5",
7353
7465
  children: [/* @__PURE__ */ jsx("textarea", {
7354
7466
  value,
7355
7467
  onChange: (e) => onChange(e.target.value),
7356
7468
  onFocus,
7357
7469
  onBlur,
7358
7470
  placeholder,
7359
- rows: Math.min(contentRows, maxRows),
7471
+ rows: fill ? void 0 : Math.min(contentRows, maxRows),
7360
7472
  "data-testid": testId,
7361
- className: "w-full text-[10px] font-mono rounded-md px-2 py-1.5 outline-none resize-y",
7473
+ className: `w-full text-[10px] font-mono rounded-md px-2 py-1.5 outline-none ${fill ? "h-full min-h-0 flex-1 resize-none" : "resize-y"}`,
7362
7474
  style: {
7363
7475
  ...formElementStyle,
7364
7476
  cursor: "text",
@@ -7447,10 +7559,9 @@ function flattenAppToSimulations(app) {
7447
7559
  }
7448
7560
  for (const appTool of app.tools) {
7449
7561
  const uri = getOutputTemplate(appTool.tool._meta);
7450
- if (!uri) continue;
7451
- const resource = resourcesByUri.get(uri);
7452
- if (!resource) continue;
7453
- const mcpResource = toMcpResource(resource);
7562
+ const resource = uri ? resourcesByUri.get(uri) : void 0;
7563
+ if (uri && !resource) console.warn(`[Inspector] Tool '${appTool.tool.name}' references unknown resource URI '${uri}'. The tool remains callable but has no UI to render.`);
7564
+ const mcpResource = resource ? toMcpResource(resource) : void 0;
7454
7565
  const sims = appTool.simulations && appTool.simulations.length > 0 ? appTool.simulations : [{ name: appTool.tool.name }];
7455
7566
  for (const sim of sims) {
7456
7567
  const key = `${appTool.tool.name}__${sim.name}`;
@@ -7458,10 +7569,12 @@ function flattenAppToSimulations(app) {
7458
7569
  result[key] = {
7459
7570
  name: key,
7460
7571
  displayName: sim.name,
7461
- resourceHtml: resource.html,
7572
+ ...resource ? {
7573
+ resourceHtml: resource.html,
7574
+ resource: mcpResource
7575
+ } : {},
7462
7576
  userMessage: sim.userMessage,
7463
7577
  tool: appTool.tool,
7464
- resource: mcpResource,
7465
7578
  toolInput: sim.toolInput,
7466
7579
  toolResult: sim.toolResult,
7467
7580
  serverTools: sim.serverTools
@@ -7537,7 +7650,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7537
7650
  const toolMap = React.useMemo(() => {
7538
7651
  const map = /* @__PURE__ */ new Map();
7539
7652
  for (const [simName, sim] of Object.entries(simulations)) {
7540
- if (!sim.resource) continue;
7541
7653
  const toolName = sim.tool.name;
7542
7654
  if (!map.has(toolName)) map.set(toolName, {
7543
7655
  tool: sim.tool,
@@ -7546,6 +7658,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7546
7658
  fixtureSimNames: []
7547
7659
  });
7548
7660
  const info = map.get(toolName);
7661
+ if (!info.resource && sim.resource) info.resource = sim.resource;
7549
7662
  info.simNames.push(simName);
7550
7663
  if (hasFixtureData(sim)) info.fixtureSimNames.push(simName);
7551
7664
  }
@@ -7558,6 +7671,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7558
7671
  const labelB = infoB.tool.title || b;
7559
7672
  return labelA.localeCompare(labelB);
7560
7673
  }), [toolMap]);
7674
+ const defaultToolName = React.useMemo(() => toolNames.find((name) => !!toolMap.get(name)?.resource) ?? toolNames[0] ?? "", [toolMap, toolNames]);
7561
7675
  const initUrlParams = React.useMemo(() => {
7562
7676
  if (typeof window === "undefined") return {
7563
7677
  tool: null,
@@ -7578,12 +7692,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7578
7692
  if (initUrlParams.simulation) {
7579
7693
  for (const [toolName, info] of toolMap) if (info.simNames.includes(initUrlParams.simulation)) return toolName;
7580
7694
  }
7581
- return toolNames[0] ?? "";
7695
+ return defaultToolName;
7582
7696
  });
7583
7697
  const prevToolNamesRef = React.useRef(toolNames);
7584
7698
  if (prevToolNamesRef.current !== toolNames) {
7585
7699
  prevToolNamesRef.current = toolNames;
7586
- if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(toolNames[0]);
7700
+ if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(defaultToolName);
7587
7701
  }
7588
7702
  const selectedToolInfo = toolMap.get(selectedToolName);
7589
7703
  const [activeSimulationName, setActiveSimulationName] = React.useState(() => {
@@ -7607,6 +7721,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7607
7721
  defaultHost,
7608
7722
  preserveToolDataOnSimulationChange: isLiveMcpRender
7609
7723
  });
7724
+ const resetAppContextForSelectionChange = () => {
7725
+ state.setModelContext(null);
7726
+ state.setModelAppContext(null);
7727
+ state.setModelContextJson("null");
7728
+ state.setModelContextError("");
7729
+ };
7610
7730
  const [serverUrl, setServerUrl] = React.useState(mcpServerUrl ?? "");
7611
7731
  const [authType, setAuthType] = React.useState("none");
7612
7732
  const [bearerToken, setBearerToken] = React.useState("");
@@ -7622,7 +7742,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7622
7742
  const [isRunning, setIsRunning] = React.useState(false);
7623
7743
  const [hasRun, setHasRun] = React.useState(false);
7624
7744
  const [showCheck, setShowCheck] = React.useState(false);
7625
- const prodResourcesId = React.useId();
7626
7745
  const [serverPreviewGeneration, setServerPreviewGeneration] = React.useState(0);
7627
7746
  const checkTimerRef = React.useRef(void 0);
7628
7747
  const oauthCleanupRef = React.useRef(void 0);
@@ -7662,7 +7781,14 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7662
7781
  const [chatStatus, setChatStatus] = React.useState("");
7663
7782
  const currentModelProvider = React.useMemo(() => modelProviderOptions.find((provider) => provider.id === modelProvider), [modelProvider, modelProviderOptions]);
7664
7783
  const selectedProviderModelOptions = React.useMemo(() => currentModelProvider?.models ?? [], [currentModelProvider?.models]);
7665
- const modelCallableTools = React.useMemo(() => Array.from(toolMap.values()).filter((info) => !!info.resource && isToolVisibleToModel(info.tool)).map((info) => info.tool), [toolMap]);
7784
+ const modelCallableTools = React.useMemo(() => {
7785
+ const map = /* @__PURE__ */ new Map();
7786
+ for (const sim of Object.values(simulations)) {
7787
+ if (!isToolVisibleToModel(sim.tool) || map.has(sim.tool.name)) continue;
7788
+ map.set(sim.tool.name, sim.tool);
7789
+ }
7790
+ return Array.from(map.values());
7791
+ }, [simulations]);
7666
7792
  React.useEffect(() => {
7667
7793
  setServerUrl(mcpServerUrl ?? "");
7668
7794
  }, [mcpServerUrl]);
@@ -8042,7 +8168,8 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8042
8168
  provider: modelProvider,
8043
8169
  modelId,
8044
8170
  messages,
8045
- tools: modelCallableTools
8171
+ tools: modelCallableTools,
8172
+ appContext: state.modelAppContext ?? void 0
8046
8173
  });
8047
8174
  else {
8048
8175
  const endpoint = inspectorApiEndpoint("/__sunpeak/model-chat", inspectorApiBaseUrl);
@@ -8052,7 +8179,8 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8052
8179
  body: JSON.stringify({
8053
8180
  provider: modelProvider,
8054
8181
  modelId,
8055
- messages
8182
+ messages,
8183
+ appContext: state.modelAppContext ?? void 0
8056
8184
  })
8057
8185
  });
8058
8186
  data = await readInspectorJson(res, endpoint);
@@ -8080,7 +8208,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8080
8208
  const assistantMessage = {
8081
8209
  id: `assistant-${Date.now()}`,
8082
8210
  role: "assistant",
8083
- content: data.text ?? (toolCalls.length > 0 ? "I called the MCP tool and rendered the app below." : "The model returned an empty response."),
8211
+ content: data.text ?? (rendersApp ? "I called the MCP tool and rendered the app below." : toolCalls.length > 0 ? "I called the MCP tool." : "The model returned an empty response."),
8084
8212
  toolCalls: toolCalls.map((call) => ({
8085
8213
  name: call.name,
8086
8214
  arguments: call.arguments,
@@ -8300,10 +8428,19 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8300
8428
  children: /* @__PURE__ */ jsx("span", {
8301
8429
  className: "text-sm text-center max-w-xs",
8302
8430
  style: { color: "var(--color-text-secondary)" },
8303
- 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"
8431
+ children: isEmbedded ? "No tools in this app" : isError ? "Could not connect to MCP server" : isConnected ? "No tools found on this server" : serverUrl ? "Connecting…" : "Enter an MCP server URL to get started"
8304
8432
  })
8305
8433
  });
8306
- } else if (showEmptyState) content = /* @__PURE__ */ jsx("div", {
8434
+ } else if (!selectedToolInfo?.resource) content = /* @__PURE__ */ jsx("div", {
8435
+ className: "h-full w-full flex items-center justify-center",
8436
+ style: { background: iframeBg },
8437
+ children: /* @__PURE__ */ jsx("span", {
8438
+ className: "text-sm text-center max-w-xs",
8439
+ style: { color: "var(--color-text-secondary)" },
8440
+ children: "Tool does not render a UI"
8441
+ })
8442
+ });
8443
+ else if (showEmptyState) content = /* @__PURE__ */ jsx("div", {
8307
8444
  className: "h-full w-full flex items-center justify-center",
8308
8445
  style: { background: iframeBg },
8309
8446
  children: /* @__PURE__ */ jsxs("span", {
@@ -8427,31 +8564,9 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8427
8564
  children: /* @__PURE__ */ jsx("path", { d: "M0 0L10 6L0 12V0Z" })
8428
8565
  }), "Run"]
8429
8566
  }) : void 0;
8430
- const headerProdResourcesControl = !hideInspectorModes && !demoMode && !isEmbedded ? /* @__PURE__ */ jsxs("div", {
8431
- className: "flex shrink-0 items-center gap-1.5 text-[11px] font-medium",
8432
- style: { color: "var(--color-text-secondary)" },
8433
- children: [
8434
- /* @__PURE__ */ jsx("input", {
8435
- id: prodResourcesId,
8436
- type: "checkbox",
8437
- checked: prodResources,
8438
- onChange: (event) => setProdResources(event.currentTarget.checked),
8439
- className: "h-3.5 w-3.5 accent-[var(--color-text-primary)]"
8440
- }),
8441
- /* @__PURE__ */ jsx("label", {
8442
- htmlFor: prodResourcesId,
8443
- className: "cursor-pointer select-none",
8444
- children: "Prod Resources"
8445
- }),
8446
- /* @__PURE__ */ jsx(HelpIcon, {
8447
- tooltip: "Load resources from dist/ builds instead of HMR",
8448
- docsPath: "app-framework/cli/dev#prod-tools-and-prod-resources-flags"
8449
- })
8450
- ]
8451
- }) : null;
8452
- const headerAction = runButton || headerProdResourcesControl ? /* @__PURE__ */ jsxs("div", {
8453
- className: "flex min-w-0 items-center gap-2",
8454
- children: [runButton, headerProdResourcesControl]
8567
+ const headerAction = runButton ? /* @__PURE__ */ jsx("div", {
8568
+ className: "flex min-w-0 items-center",
8569
+ children: runButton
8455
8570
  }) : void 0;
8456
8571
  const conversationContent = ShellConversation ? /* @__PURE__ */ jsx(ShellConversation, {
8457
8572
  screenWidth: state.screenWidth,
@@ -8474,6 +8589,11 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8474
8589
  children: content
8475
8590
  }) : content;
8476
8591
  const rootSizing = isEmbedded ? "h-full w-full" : "h-screen w-screen";
8592
+ const getJsonPanelFlexGrow = (value) => {
8593
+ const text = value || "";
8594
+ const lineCount = text.split("\n").length;
8595
+ return Math.max(1, Math.min(8, lineCount + Math.floor(text.length / 500)));
8596
+ };
8477
8597
  if (!showSidebar) return /* @__PURE__ */ jsx(ThemeProvider, {
8478
8598
  theme: state.theme,
8479
8599
  applyTheme,
@@ -8489,6 +8609,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8489
8609
  children: [/* @__PURE__ */ jsx(SimpleSidebar, {
8490
8610
  rootRef,
8491
8611
  fillParent: isEmbedded,
8612
+ sidebarWidth: state.sidebarWidth,
8613
+ rightSidebarWidth: state.rightSidebarWidth,
8614
+ onSidebarWidthChange: state.setSidebarWidth,
8615
+ onRightSidebarWidthChange: state.setRightSidebarWidth,
8492
8616
  controls: /* @__PURE__ */ jsxs("div", {
8493
8617
  className: "space-y-1",
8494
8618
  children: [
@@ -8513,7 +8637,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8513
8637
  })
8514
8638
  }), !demoMode && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
8515
8639
  label: "Authentication",
8516
- defaultCollapsed: authType === "none",
8640
+ defaultCollapsed: false,
8517
8641
  children: /* @__PURE__ */ jsxs("div", {
8518
8642
  className: "space-y-1",
8519
8643
  children: [
@@ -8597,70 +8721,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8597
8721
  ]
8598
8722
  })
8599
8723
  }, `auth-${authType === "none" ? "none" : "active"}`)] }),
8600
- canUseModelChat && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
8601
- label: "Model Chat",
8602
- defaultCollapsed: true,
8603
- tooltip: "Talk to this MCP server through a model",
8604
- docsPath: "testing/evals",
8605
- children: /* @__PURE__ */ jsxs("div", {
8606
- className: "space-y-2",
8607
- children: [/* @__PURE__ */ jsxs("div", {
8608
- className: "grid grid-cols-2 gap-2",
8609
- children: [/* @__PURE__ */ jsx(SidebarControl, {
8610
- label: "Provider",
8611
- children: /* @__PURE__ */ jsx(SidebarSelect, {
8612
- value: modelProvider,
8613
- onChange: handleModelProviderChange,
8614
- options: modelProviderOptions.map((provider) => ({
8615
- value: provider.id,
8616
- label: provider.label ?? provider.id
8617
- }))
8618
- })
8619
- }), /* @__PURE__ */ jsx(SidebarControl, {
8620
- label: "Model",
8621
- children: selectedProviderModelOptions.length > 0 ? /* @__PURE__ */ jsx(SidebarSelect, {
8622
- value: modelId,
8623
- onChange: setModelId,
8624
- options: selectedProviderModelOptions.map((model) => ({
8625
- value: model,
8626
- label: model
8627
- }))
8628
- }) : /* @__PURE__ */ jsx(SidebarInput, {
8629
- value: modelId,
8630
- onChange: setModelId,
8631
- applyOnBlur: true,
8632
- placeholder: getDefaultModelId(modelProvider)
8633
- })
8634
- })]
8635
- }), usesApiKeyUi && /* @__PURE__ */ jsxs(SidebarControl, {
8636
- label: "API Key",
8637
- children: [/* @__PURE__ */ jsxs("div", {
8638
- className: "flex gap-1",
8639
- children: [/* @__PURE__ */ jsx(SidebarInput, {
8640
- type: "password",
8641
- autoComplete: "new-password",
8642
- value: apiKeyDraft,
8643
- onChange: setApiKeyDraft,
8644
- placeholder: keyStatus.hasKey ? "Saved locally" : `Paste ${modelProvider} key`
8645
- }), /* @__PURE__ */ jsx("button", {
8646
- type: "button",
8647
- onClick: handleSaveApiKey,
8648
- disabled: isKeyStatusLoading || !apiKeyDraft && !keyStatus.hasKey,
8649
- className: "h-7 rounded-md px-2 text-xs font-medium transition-opacity disabled:opacity-40",
8650
- style: {
8651
- backgroundColor: "var(--color-text-primary)",
8652
- color: "var(--color-background-primary)"
8653
- },
8654
- children: apiKeyDraft ? "Save" : "Clear"
8655
- })]
8656
- }), /* @__PURE__ */ jsx("div", {
8657
- className: "mt-1 text-[9px]",
8658
- style: { color: "var(--color-text-secondary)" },
8659
- children: keyMessage || (isKeyStatusLoading ? "Checking saved key..." : keyStatus.hasKey ? `Key saved ${keyStatus.storage ?? "locally"}` : "Paste a key or use one already saved on this machine")
8660
- })]
8661
- })]
8662
- })
8663
- }),
8664
8724
  hasTools && /* @__PURE__ */ jsxs("div", {
8665
8725
  className: "grid grid-cols-2 gap-2",
8666
8726
  "data-testid": "tool-simulation-row",
@@ -8673,6 +8733,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8673
8733
  value: selectedToolName,
8674
8734
  onChange: (value) => {
8675
8735
  setIsLiveMcpRender(false);
8736
+ resetAppContextForSelectionChange();
8676
8737
  setSelectedToolName(value);
8677
8738
  },
8678
8739
  options: toolNames.map((name) => {
@@ -8705,6 +8766,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8705
8766
  onChange: (value) => {
8706
8767
  if (value === "__live__") return;
8707
8768
  setIsLiveMcpRender(false);
8769
+ resetAppContextForSelectionChange();
8708
8770
  setActiveSimulationName(value === "__none__" ? null : value);
8709
8771
  },
8710
8772
  options: [
@@ -8766,6 +8828,80 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8766
8828
  })
8767
8829
  })]
8768
8830
  }),
8831
+ !hideInspectorModes && !demoMode && !isEmbedded && /* @__PURE__ */ jsx("div", {
8832
+ className: "py-1",
8833
+ children: /* @__PURE__ */ jsx(SidebarCheckbox, {
8834
+ checked: prodResources,
8835
+ onChange: setProdResources,
8836
+ label: "Prod Resources",
8837
+ tooltip: "Load resources from dist/ builds instead of HMR",
8838
+ docsPath: "app-framework/cli/dev#prod-tools-and-prod-resources-flags"
8839
+ })
8840
+ }),
8841
+ canUseModelChat && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
8842
+ label: "Model Chat",
8843
+ defaultCollapsed: false,
8844
+ tooltip: "Talk to this MCP server through a model",
8845
+ docsPath: "testing/evals",
8846
+ children: /* @__PURE__ */ jsxs("div", {
8847
+ className: "space-y-1",
8848
+ children: [/* @__PURE__ */ jsxs("div", {
8849
+ className: "grid grid-cols-2 gap-2",
8850
+ children: [/* @__PURE__ */ jsx(SidebarControl, {
8851
+ label: "Provider",
8852
+ children: /* @__PURE__ */ jsx(SidebarSelect, {
8853
+ value: modelProvider,
8854
+ onChange: handleModelProviderChange,
8855
+ options: modelProviderOptions.map((provider) => ({
8856
+ value: provider.id,
8857
+ label: provider.label ?? provider.id
8858
+ }))
8859
+ })
8860
+ }), /* @__PURE__ */ jsx(SidebarControl, {
8861
+ label: "Model",
8862
+ children: selectedProviderModelOptions.length > 0 ? /* @__PURE__ */ jsx(SidebarSelect, {
8863
+ value: modelId,
8864
+ onChange: setModelId,
8865
+ options: selectedProviderModelOptions.map((model) => ({
8866
+ value: model,
8867
+ label: model
8868
+ }))
8869
+ }) : /* @__PURE__ */ jsx(SidebarInput, {
8870
+ value: modelId,
8871
+ onChange: setModelId,
8872
+ applyOnBlur: true,
8873
+ placeholder: getDefaultModelId(modelProvider)
8874
+ })
8875
+ })]
8876
+ }), usesApiKeyUi && /* @__PURE__ */ jsxs(SidebarControl, {
8877
+ label: "API Key",
8878
+ children: [/* @__PURE__ */ jsxs("div", {
8879
+ className: "flex gap-1",
8880
+ children: [/* @__PURE__ */ jsx(SidebarInput, {
8881
+ type: "password",
8882
+ autoComplete: "new-password",
8883
+ value: apiKeyDraft,
8884
+ onChange: setApiKeyDraft,
8885
+ placeholder: keyStatus.hasKey ? "Saved locally" : `Paste ${modelProvider} key`
8886
+ }), /* @__PURE__ */ jsx("button", {
8887
+ type: "button",
8888
+ onClick: handleSaveApiKey,
8889
+ disabled: isKeyStatusLoading || !apiKeyDraft && !keyStatus.hasKey,
8890
+ className: "h-7 rounded-md px-2 text-xs font-medium transition-opacity disabled:opacity-40",
8891
+ style: {
8892
+ backgroundColor: "var(--color-text-primary)",
8893
+ color: "var(--color-background-primary)"
8894
+ },
8895
+ children: apiKeyDraft ? "Save" : "Clear"
8896
+ })]
8897
+ }), /* @__PURE__ */ jsx("div", {
8898
+ className: "mt-1 text-[9px]",
8899
+ style: { color: "var(--color-text-secondary)" },
8900
+ children: keyMessage || (isKeyStatusLoading ? "Checking saved key..." : keyStatus.hasKey ? `Key saved ${keyStatus.storage ?? "locally"}` : "Paste a key or use one already saved on this machine")
8901
+ })]
8902
+ })]
8903
+ })
8904
+ }),
8769
8905
  /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
8770
8906
  label: "Host Context",
8771
8907
  defaultCollapsed: false,
@@ -9028,21 +9164,35 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9028
9164
  })
9029
9165
  ]
9030
9166
  })
9031
- }),
9167
+ })
9168
+ ]
9169
+ }),
9170
+ rightControls: /* @__PURE__ */ jsxs("div", {
9171
+ className: "flex h-full min-h-0 flex-col gap-3",
9172
+ children: [
9032
9173
  /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
9033
9174
  label: "App Context",
9034
- defaultCollapsed: true,
9175
+ defaultCollapsed: false,
9035
9176
  tooltip: "App-provided context shared with the model",
9036
9177
  docsPath: "app-framework/hooks/use-app-state",
9178
+ className: "flex min-h-0 flex-col",
9179
+ contentClassName: "min-h-0 flex-1",
9180
+ style: { flex: `${getJsonPanelFlexGrow(state.modelContextJson)} 1 0` },
9181
+ tooltipPlacement: "left",
9037
9182
  children: /* @__PURE__ */ jsx(SidebarTextarea, {
9038
9183
  value: state.modelContextJson,
9184
+ "data-testid": "app-context-textarea",
9039
9185
  onChange: (json) => state.validateJSON(json, state.setModelContextJson, state.setModelContextError),
9040
9186
  onFocus: () => state.setEditingField("modelContext"),
9041
9187
  onBlur: () => state.commitJSON(state.modelContextJson, state.setModelContextError, (parsed) => {
9042
- state.setModelContext(parsed);
9188
+ state.setModelContext(parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null);
9189
+ state.setModelAppContext(parsed == null ? null : {
9190
+ content: [],
9191
+ structuredContent: parsed
9192
+ });
9043
9193
  }),
9044
9194
  error: state.modelContextError,
9045
- maxRows: 8
9195
+ fill: true
9046
9196
  })
9047
9197
  }),
9048
9198
  /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
@@ -9050,6 +9200,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9050
9200
  defaultCollapsed: false,
9051
9201
  tooltip: "Arguments passed to the tool",
9052
9202
  docsPath: "app-framework/hooks/use-tool-data",
9203
+ className: "flex min-h-0 flex-col",
9204
+ contentClassName: "min-h-0 flex-1",
9205
+ style: { flex: `${getJsonPanelFlexGrow(state.toolInputJson)} 1 0` },
9206
+ tooltipPlacement: "left",
9053
9207
  children: /* @__PURE__ */ jsx(SidebarTextarea, {
9054
9208
  value: state.toolInputJson,
9055
9209
  "data-testid": "tool-input-textarea",
@@ -9057,7 +9211,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9057
9211
  onFocus: () => state.setEditingField("toolInput"),
9058
9212
  onBlur: () => state.commitJSON(state.toolInputJson, state.setToolInputError, (parsed) => state.setToolInput(parsed ?? {})),
9059
9213
  error: state.toolInputError,
9060
- maxRows: 8
9214
+ fill: true
9061
9215
  })
9062
9216
  }),
9063
9217
  /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
@@ -9066,6 +9220,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9066
9220
  tooltip: "Structured content returned by the tool",
9067
9221
  docsPath: "app-framework/hooks/use-tool-data",
9068
9222
  "data-testid": "tool-result-section",
9223
+ className: "flex min-h-0 flex-col",
9224
+ contentClassName: "min-h-0 flex-1",
9225
+ style: { flex: `${getJsonPanelFlexGrow(state.toolResultJson)} 1 0` },
9226
+ tooltipPlacement: "left",
9069
9227
  children: /* @__PURE__ */ jsx(SidebarTextarea, {
9070
9228
  value: state.toolResultJson,
9071
9229
  "data-testid": "tool-result-textarea",
@@ -9083,7 +9241,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9083
9241
  }
9084
9242
  }),
9085
9243
  error: state.toolResultError,
9086
- maxRows: 8
9244
+ fill: true
9087
9245
  })
9088
9246
  })
9089
9247
  ]
@@ -9102,4 +9260,4 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9102
9260
  //#endregion
9103
9261
  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 };
9104
9262
 
9105
- //# sourceMappingURL=inspector-mGvDvMCR.js.map
9263
+ //# sourceMappingURL=inspector-CiuT_2yA.js.map