sunpeak 0.20.35 → 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 (40) hide show
  1. package/bin/commands/inspect.mjs +16 -14
  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.js +1 -1
  15. package/dist/inspector/inspector.d.ts +5 -4
  16. package/dist/inspector/simple-sidebar.d.ts +20 -6
  17. package/dist/inspector/use-inspector-state.d.ts +4 -0
  18. package/dist/{inspector-DQ_vv1wj.cjs → inspector-BNWla95w.cjs} +291 -145
  19. package/dist/{inspector-DQ_vv1wj.cjs.map → inspector-BNWla95w.cjs.map} +1 -1
  20. package/dist/{inspector-D0TWNx_T.js → inspector-CiuT_2yA.js} +291 -145
  21. package/dist/{inspector-D0TWNx_T.js.map → inspector-CiuT_2yA.js.map} +1 -1
  22. package/dist/style.css +6 -24
  23. package/package.json +1 -1
  24. package/template/dist/albums/albums.html +1 -1
  25. package/template/dist/albums/albums.json +1 -1
  26. package/template/dist/carousel/carousel.html +1 -1
  27. package/template/dist/carousel/carousel.json +1 -1
  28. package/template/dist/map/map.html +1 -1
  29. package/template/dist/map/map.json +1 -1
  30. package/template/dist/review/review.html +1 -1
  31. package/template/dist/review/review.json +1 -1
  32. package/template/tests/e2e/visual.spec.ts +0 -8
  33. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-chatgpt-darwin.png +0 -0
  34. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-chatgpt-linux.png +0 -0
  35. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-darwin.png +0 -0
  36. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-linux.png +0 -0
  37. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-chatgpt-darwin.png +0 -0
  38. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-chatgpt-linux.png +0 -0
  39. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-claude-darwin.png +0 -0
  40. package/template/tests/e2e/visual.spec.ts-snapshots/albums-page-light-claude-linux.png +0 -0
@@ -6435,6 +6435,7 @@ function IframeResource({ src, scriptSrc, html, hostContext, toolInput, toolInpu
6435
6435
  var DEFAULT_THEME = "dark";
6436
6436
  var DEFAULT_DISPLAY_MODE = "inline";
6437
6437
  var DEFAULT_PLATFORM = "desktop";
6438
+ var DEFAULT_SIDEBAR_WIDTH$1 = 260;
6438
6439
  /**
6439
6440
  * Parse URL params for initial inspector values.
6440
6441
  * Supported params:
@@ -6561,6 +6562,8 @@ function sanitizeStoredPrefs(raw) {
6561
6562
  if (typeof obj.hover === "boolean") prefs.hover = obj.hover;
6562
6563
  if (typeof obj.touch === "boolean") prefs.touch = obj.touch;
6563
6564
  if (typeof obj.screenWidth === "string" && VALID_SCREEN_WIDTHS.has(obj.screenWidth)) prefs.screenWidth = obj.screenWidth;
6565
+ if (typeof obj.sidebarWidth === "number" && Number.isFinite(obj.sidebarWidth)) prefs.sidebarWidth = Math.max(DEFAULT_SIDEBAR_WIDTH$1, Math.round(obj.sidebarWidth));
6566
+ if (typeof obj.rightSidebarWidth === "number" && Number.isFinite(obj.rightSidebarWidth)) prefs.rightSidebarWidth = Math.max(DEFAULT_SIDEBAR_WIDTH$1, Math.round(obj.rightSidebarWidth));
6564
6567
  return prefs;
6565
6568
  }
6566
6569
  function readStoredPrefs() {
@@ -6591,29 +6594,31 @@ function deriveContainerDimensions({ displayMode, containerHeight, containerWidt
6591
6594
  if (measuredContentWidth != null) return { maxWidth: measuredContentWidth };
6592
6595
  }
6593
6596
  function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolDataOnSimulationChange = false }) {
6594
- const simulationNames = Object.keys(simulations).filter((name) => simulations[name].resource).sort((a, b) => {
6597
+ const simulationNames = Object.keys(simulations).sort((a, b) => {
6595
6598
  const simA = simulations[a];
6596
6599
  const simB = simulations[b];
6597
- const resourceLabelA = simA.resource.title || simA.resource.name;
6598
- const resourceLabelB = simB.resource.title || simB.resource.name;
6599
- const labelA = `${resourceLabelA}: ${simA.tool.title || simA.tool.name}`;
6600
- const labelB = `${resourceLabelB}: ${simB.tool.title || simB.tool.name}`;
6600
+ const resourceLabelA = simA.resource ? `${simA.resource.title || simA.resource.name}: ` : "";
6601
+ const resourceLabelB = simB.resource ? `${simB.resource.title || simB.resource.name}: ` : "";
6602
+ const labelA = `${resourceLabelA}${simA.tool.title || simA.tool.name}`;
6603
+ const labelB = `${resourceLabelB}${simB.tool.title || simB.tool.name}`;
6601
6604
  return labelA.localeCompare(labelB);
6602
6605
  });
6606
+ const defaultSimulationName = simulationNames.find((name) => !!simulations[name]?.resource) ?? simulationNames[0] ?? "";
6603
6607
  const urlParams = (0, react.useMemo)(() => parseUrlParams(), []);
6604
6608
  const autoRun = urlParams.autoRun === true;
6605
6609
  const storedPrefs = (0, react.useMemo)(() => autoRun ? {} : readStoredPrefs(), [autoRun]);
6606
6610
  const [screenWidth, setScreenWidth] = (0, react.useState)(storedPrefs.screenWidth ?? "full");
6611
+ const [sidebarWidth, setSidebarWidth] = (0, react.useState)(storedPrefs.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH$1);
6612
+ const [rightSidebarWidth, setRightSidebarWidth] = (0, react.useState)(storedPrefs.rightSidebarWidth ?? DEFAULT_SIDEBAR_WIDTH$1);
6607
6613
  const isMobileWidth = (width) => width === "mobile-s" || width === "mobile-l";
6608
6614
  const [activeHost, setActiveHost] = (0, react.useState)(urlParams.host ?? storedPrefs.activeHost ?? defaultHost);
6609
6615
  const [selectedSimulationName, setSelectedSimulationName] = (0, react.useState)((0, react.useMemo)(() => {
6610
- const defaultName = simulationNames[0] ?? "";
6611
- if (!urlParams.simulation) return defaultName;
6612
- return urlParams.simulation in simulations ? urlParams.simulation : defaultName;
6616
+ if (!urlParams.simulation) return defaultSimulationName;
6617
+ return urlParams.simulation in simulations ? urlParams.simulation : defaultSimulationName;
6613
6618
  }, [
6614
6619
  urlParams.simulation,
6615
6620
  simulations,
6616
- simulationNames
6621
+ defaultSimulationName
6617
6622
  ]));
6618
6623
  const selectedSim = simulations[selectedSimulationName];
6619
6624
  const [theme, setTheme] = (0, react.useState)(urlParams.theme ?? storedPrefs.theme ?? DEFAULT_THEME);
@@ -6652,7 +6657,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6652
6657
  platform,
6653
6658
  hover,
6654
6659
  touch,
6655
- screenWidth
6660
+ screenWidth,
6661
+ sidebarWidth,
6662
+ rightSidebarWidth
6656
6663
  };
6657
6664
  localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
6658
6665
  } catch {}
@@ -6668,7 +6675,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6668
6675
  platform,
6669
6676
  hover,
6670
6677
  touch,
6671
- screenWidth
6678
+ screenWidth,
6679
+ sidebarWidth,
6680
+ rightSidebarWidth
6672
6681
  ]);
6673
6682
  const [measuredContentWidth, setMeasuredContentWidth] = (0, react.useState)(void 0);
6674
6683
  const handleContentWidthChange = (0, react.useCallback)((width) => {
@@ -6753,6 +6762,8 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6753
6762
  }
6754
6763
  if (editingField !== "modelContext") {
6755
6764
  setModelContext(null);
6765
+ setModelAppContext(null);
6766
+ setModelContextJson("null");
6756
6767
  setModelContextError("");
6757
6768
  }
6758
6769
  }, [
@@ -6829,6 +6840,10 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6829
6840
  setActiveHost,
6830
6841
  screenWidth,
6831
6842
  setScreenWidth,
6843
+ sidebarWidth,
6844
+ setSidebarWidth,
6845
+ rightSidebarWidth,
6846
+ setRightSidebarWidth,
6832
6847
  theme,
6833
6848
  setTheme,
6834
6849
  displayMode,
@@ -7059,9 +7074,10 @@ var useThemeContext = () => {
7059
7074
  if (context === void 0) throw new Error("useThemeContext must be used within a ThemeProvider");
7060
7075
  return context;
7061
7076
  };
7062
- //#endregion
7063
- //#region src/inspector/simple-sidebar.tsx
7064
- var DEFAULT_SIDEBAR_WIDTH = 260;
7077
+ function clampSidebarWidth(rawWidth, viewportWidth) {
7078
+ const maxWidth = Math.floor(viewportWidth / 3);
7079
+ return Math.max(260, Math.min(maxWidth, rawWidth));
7080
+ }
7065
7081
  function ChevronRightIcon() {
7066
7082
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
7067
7083
  width: "1em",
@@ -7075,19 +7091,34 @@ function ChevronRightIcon() {
7075
7091
  })
7076
7092
  });
7077
7093
  }
7078
- function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent = false }) {
7094
+ function SimpleSidebar({ children, controls, rightControls, sidebarWidth, rightSidebarWidth, onSidebarWidthChange, onRightSidebarWidthChange, headerRight, rootRef, fillParent = false }) {
7079
7095
  const [isDrawerOpen, setIsDrawerOpen] = react.useState(false);
7080
- const [sidebarWidth, setSidebarWidth] = react.useState(DEFAULT_SIDEBAR_WIDTH);
7096
+ const [internalSidebarWidth, setInternalSidebarWidth] = react.useState(260);
7097
+ const [internalRightSidebarWidth, setInternalRightSidebarWidth] = react.useState(260);
7081
7098
  const [isResizing, setIsResizing] = react.useState(false);
7099
+ const [isResizingRight, setIsResizingRight] = react.useState(false);
7100
+ const effectiveSidebarWidth = sidebarWidth ?? internalSidebarWidth;
7101
+ const effectiveRightSidebarWidth = rightSidebarWidth ?? internalRightSidebarWidth;
7102
+ const setSidebarWidth = react.useCallback((width) => {
7103
+ setInternalSidebarWidth(width);
7104
+ onSidebarWidthChange?.(width);
7105
+ }, [onSidebarWidthChange]);
7106
+ const setRightSidebarWidth = react.useCallback((width) => {
7107
+ setInternalRightSidebarWidth(width);
7108
+ onRightSidebarWidthChange?.(width);
7109
+ }, [onRightSidebarWidthChange]);
7082
7110
  const handleMouseDown = react.useCallback((e) => {
7083
7111
  e.preventDefault();
7084
7112
  setIsResizing(true);
7085
7113
  }, []);
7114
+ const handleRightMouseDown = react.useCallback((e) => {
7115
+ e.preventDefault();
7116
+ setIsResizingRight(true);
7117
+ }, []);
7086
7118
  react.useEffect(() => {
7087
7119
  if (!isResizing) return;
7088
7120
  const handleMouseMove = (e) => {
7089
- const maxWidth = Math.floor(window.innerWidth / 3);
7090
- setSidebarWidth(Math.min(maxWidth, Math.max(DEFAULT_SIDEBAR_WIDTH, e.clientX)));
7121
+ setSidebarWidth(clampSidebarWidth(e.clientX, window.innerWidth));
7091
7122
  };
7092
7123
  const handleMouseUp = () => {
7093
7124
  setIsResizing(false);
@@ -7098,12 +7129,27 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7098
7129
  document.removeEventListener("mousemove", handleMouseMove);
7099
7130
  document.removeEventListener("mouseup", handleMouseUp);
7100
7131
  };
7101
- }, [isResizing]);
7132
+ }, [isResizing, setSidebarWidth]);
7133
+ react.useEffect(() => {
7134
+ if (!isResizingRight) return;
7135
+ const handleMouseMove = (e) => {
7136
+ setRightSidebarWidth(clampSidebarWidth(window.innerWidth - e.clientX, window.innerWidth));
7137
+ };
7138
+ const handleMouseUp = () => {
7139
+ setIsResizingRight(false);
7140
+ };
7141
+ document.addEventListener("mousemove", handleMouseMove);
7142
+ document.addEventListener("mouseup", handleMouseUp);
7143
+ return () => {
7144
+ document.removeEventListener("mousemove", handleMouseMove);
7145
+ document.removeEventListener("mouseup", handleMouseUp);
7146
+ };
7147
+ }, [isResizingRight, setRightSidebarWidth]);
7102
7148
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7103
7149
  ref: rootRef,
7104
7150
  className: `sunpeak-inspector-root flex ${fillParent ? "h-full w-full" : "h-screen w-full"} overflow-hidden relative`,
7105
7151
  children: [
7106
- isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "fixed inset-0 z-50 cursor-col-resize" }),
7152
+ (isResizing || isResizingRight) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "fixed inset-0 z-50 cursor-col-resize" }),
7107
7153
  isDrawerOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7108
7154
  className: "md:hidden fixed inset-0 bg-black/50 z-40 pointer-events-auto",
7109
7155
  onClick: (e) => {
@@ -7119,7 +7165,7 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7119
7165
  ${isDrawerOpen ? "max-md:translate-x-0" : "max-md:-translate-x-full"}
7120
7166
  `,
7121
7167
  style: {
7122
- width: sidebarWidth,
7168
+ width: effectiveSidebarWidth,
7123
7169
  borderRight: "1px solid var(--color-border-primary)"
7124
7170
  },
7125
7171
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -7172,19 +7218,69 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7172
7218
  "aria-label": "Open sidebar",
7173
7219
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {})
7174
7220
  }), children]
7221
+ }),
7222
+ rightControls && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
7223
+ className: "relative hidden md:flex flex-col bg-sidebar",
7224
+ style: {
7225
+ width: effectiveRightSidebarWidth,
7226
+ borderLeft: "1px solid var(--color-border-primary)"
7227
+ },
7228
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7229
+ className: "flex-1 min-h-0 overflow-y-auto px-3 pb-3 pt-2",
7230
+ children: rightControls
7231
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7232
+ onMouseDown: handleRightMouseDown,
7233
+ 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"
7234
+ })]
7175
7235
  })
7176
7236
  ]
7177
7237
  });
7178
7238
  }
7179
7239
  var DOCS_BASE_URL$1 = "https://sunpeak.ai/docs";
7180
- function HelpIcon({ tooltip, docsPath }) {
7240
+ function HelpIcon({ tooltip, docsPath, placement = "right" }) {
7241
+ const linkRef = react.useRef(null);
7242
+ const [isTooltipVisible, setIsTooltipVisible] = react.useState(false);
7243
+ const [tooltipPosition, setTooltipPosition] = react.useState({
7244
+ left: 0,
7245
+ top: 0
7246
+ });
7247
+ const tooltipOffset = 8;
7248
+ const tooltipTransform = placement === "left" ? "translate(-100%, -50%)" : "translateY(-50%)";
7249
+ const setTooltipFromPoint = react.useCallback((clientX, clientY) => {
7250
+ setTooltipPosition({
7251
+ left: placement === "left" ? clientX - tooltipOffset : clientX + tooltipOffset,
7252
+ top: clientY
7253
+ });
7254
+ }, [placement]);
7255
+ const setTooltipFromIcon = react.useCallback(() => {
7256
+ const rect = linkRef.current?.getBoundingClientRect();
7257
+ if (!rect) return;
7258
+ setTooltipPosition({
7259
+ left: placement === "left" ? rect.left - tooltipOffset : rect.right + tooltipOffset,
7260
+ top: rect.top + rect.height / 2
7261
+ });
7262
+ }, [placement]);
7181
7263
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
7264
+ ref: linkRef,
7182
7265
  href: `${DOCS_BASE_URL$1}/${docsPath}`,
7183
7266
  target: "_blank",
7184
7267
  rel: "noopener noreferrer",
7185
7268
  "aria-label": tooltip,
7186
7269
  className: "group relative inline-flex items-center justify-center no-underline flex-shrink-0 transition-colors",
7187
7270
  style: { color: "var(--color-text-tertiary, var(--color-text-secondary))" },
7271
+ onMouseEnter: (e) => {
7272
+ setIsTooltipVisible(true);
7273
+ setTooltipFromPoint(e.clientX, e.clientY);
7274
+ },
7275
+ onMouseMove: (e) => {
7276
+ setTooltipFromPoint(e.clientX, e.clientY);
7277
+ },
7278
+ onMouseLeave: () => setIsTooltipVisible(false),
7279
+ onFocus: () => {
7280
+ setIsTooltipVisible(true);
7281
+ setTooltipFromIcon();
7282
+ },
7283
+ onBlur: () => setIsTooltipVisible(false),
7188
7284
  onClick: (e) => e.stopPropagation(),
7189
7285
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
7190
7286
  width: "12",
@@ -7210,8 +7306,11 @@ function HelpIcon({ tooltip, docsPath }) {
7210
7306
  })]
7211
7307
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7212
7308
  "aria-hidden": "true",
7213
- 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",
7309
+ className: `pointer-events-none fixed z-[1000] whitespace-nowrap rounded px-2 py-1 text-[11px] font-normal leading-tight ${isTooltipVisible ? "block" : "hidden"}`,
7214
7310
  style: {
7311
+ left: tooltipPosition.left,
7312
+ top: tooltipPosition.top,
7313
+ transform: tooltipTransform,
7215
7314
  backgroundColor: "var(--color-text-primary)",
7216
7315
  color: "var(--color-background-primary)"
7217
7316
  },
@@ -7219,7 +7318,7 @@ function HelpIcon({ tooltip, docsPath }) {
7219
7318
  })]
7220
7319
  });
7221
7320
  }
7222
- function SidebarControl({ label, children, tooltip, docsPath, "data-testid": testId }) {
7321
+ function SidebarControl({ label, children, tooltip, tooltipPlacement, docsPath, "data-testid": testId }) {
7223
7322
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7224
7323
  className: "space-y-1",
7225
7324
  "data-testid": testId,
@@ -7228,15 +7327,17 @@ function SidebarControl({ label, children, tooltip, docsPath, "data-testid": tes
7228
7327
  style: { color: "var(--color-text-secondary)" },
7229
7328
  children: [label, tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7230
7329
  tooltip,
7231
- docsPath
7330
+ docsPath,
7331
+ placement: tooltipPlacement
7232
7332
  })]
7233
7333
  }), children]
7234
7334
  });
7235
7335
  }
7236
- function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, tooltip, docsPath, "data-testid": testId }) {
7336
+ function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, className, contentClassName, style, tooltip, tooltipPlacement, docsPath, "data-testid": testId }) {
7237
7337
  const [isCollapsed, setIsCollapsed] = react.useState(defaultCollapsed);
7238
7338
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7239
- className: "space-y-1",
7339
+ className: className ? `space-y-1 ${className}` : "space-y-1",
7340
+ style: isCollapsed ? void 0 : style,
7240
7341
  "data-testid": testId,
7241
7342
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7242
7343
  onClick: () => setIsCollapsed(!isCollapsed),
@@ -7247,13 +7348,17 @@ function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, t
7247
7348
  className: "inline-flex items-center gap-1",
7248
7349
  children: [label, tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7249
7350
  tooltip,
7250
- docsPath
7351
+ docsPath,
7352
+ placement: tooltipPlacement
7251
7353
  })]
7252
7354
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7253
7355
  className: "text-[8px]",
7254
7356
  children: isCollapsed ? "▶" : "▼"
7255
7357
  })]
7256
- }), !isCollapsed && children]
7358
+ }), !isCollapsed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7359
+ className: contentClassName,
7360
+ children
7361
+ })]
7257
7362
  });
7258
7363
  }
7259
7364
  var formElementStyle = {
@@ -7328,7 +7433,7 @@ function SidebarInput({ value, onChange, applyOnBlur = false, autoComplete, plac
7328
7433
  }
7329
7434
  });
7330
7435
  }
7331
- function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7436
+ function SidebarCheckbox({ checked, onChange, label, tooltip, tooltipPlacement, docsPath }) {
7332
7437
  const id = react.useId();
7333
7438
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7334
7439
  className: "flex items-center gap-1.5",
@@ -7348,24 +7453,25 @@ function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7348
7453
  }),
7349
7454
  tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7350
7455
  tooltip,
7351
- docsPath
7456
+ docsPath,
7457
+ placement: tooltipPlacement
7352
7458
  })
7353
7459
  ]
7354
7460
  });
7355
7461
  }
7356
- function SidebarTextarea({ value, onChange, onFocus, onBlur, placeholder, maxRows = 8, error, "data-testid": testId }) {
7462
+ function SidebarTextarea({ value, onChange, onFocus, onBlur, placeholder, maxRows = 8, fill = false, error, "data-testid": testId }) {
7357
7463
  const contentRows = value?.split("\n").length ?? 1;
7358
7464
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7359
- className: "space-y-0.5",
7465
+ className: fill ? "flex h-full min-h-0 flex-col gap-0.5" : "space-y-0.5",
7360
7466
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
7361
7467
  value,
7362
7468
  onChange: (e) => onChange(e.target.value),
7363
7469
  onFocus,
7364
7470
  onBlur,
7365
7471
  placeholder,
7366
- rows: Math.min(contentRows, maxRows),
7472
+ rows: fill ? void 0 : Math.min(contentRows, maxRows),
7367
7473
  "data-testid": testId,
7368
- className: "w-full text-[10px] font-mono rounded-md px-2 py-1.5 outline-none resize-y",
7474
+ 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"}`,
7369
7475
  style: {
7370
7476
  ...formElementStyle,
7371
7477
  cursor: "text",
@@ -7454,10 +7560,9 @@ function flattenAppToSimulations(app) {
7454
7560
  }
7455
7561
  for (const appTool of app.tools) {
7456
7562
  const uri = getOutputTemplate(appTool.tool._meta);
7457
- if (!uri) continue;
7458
- const resource = resourcesByUri.get(uri);
7459
- if (!resource) continue;
7460
- const mcpResource = toMcpResource(resource);
7563
+ const resource = uri ? resourcesByUri.get(uri) : void 0;
7564
+ 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.`);
7565
+ const mcpResource = resource ? toMcpResource(resource) : void 0;
7461
7566
  const sims = appTool.simulations && appTool.simulations.length > 0 ? appTool.simulations : [{ name: appTool.tool.name }];
7462
7567
  for (const sim of sims) {
7463
7568
  const key = `${appTool.tool.name}__${sim.name}`;
@@ -7465,10 +7570,12 @@ function flattenAppToSimulations(app) {
7465
7570
  result[key] = {
7466
7571
  name: key,
7467
7572
  displayName: sim.name,
7468
- resourceHtml: resource.html,
7573
+ ...resource ? {
7574
+ resourceHtml: resource.html,
7575
+ resource: mcpResource
7576
+ } : {},
7469
7577
  userMessage: sim.userMessage,
7470
7578
  tool: appTool.tool,
7471
- resource: mcpResource,
7472
7579
  toolInput: sim.toolInput,
7473
7580
  toolResult: sim.toolResult,
7474
7581
  serverTools: sim.serverTools
@@ -7544,7 +7651,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7544
7651
  const toolMap = react.useMemo(() => {
7545
7652
  const map = /* @__PURE__ */ new Map();
7546
7653
  for (const [simName, sim] of Object.entries(simulations)) {
7547
- if (!sim.resource) continue;
7548
7654
  const toolName = sim.tool.name;
7549
7655
  if (!map.has(toolName)) map.set(toolName, {
7550
7656
  tool: sim.tool,
@@ -7553,6 +7659,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7553
7659
  fixtureSimNames: []
7554
7660
  });
7555
7661
  const info = map.get(toolName);
7662
+ if (!info.resource && sim.resource) info.resource = sim.resource;
7556
7663
  info.simNames.push(simName);
7557
7664
  if (hasFixtureData(sim)) info.fixtureSimNames.push(simName);
7558
7665
  }
@@ -7565,6 +7672,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7565
7672
  const labelB = infoB.tool.title || b;
7566
7673
  return labelA.localeCompare(labelB);
7567
7674
  }), [toolMap]);
7675
+ const defaultToolName = react.useMemo(() => toolNames.find((name) => !!toolMap.get(name)?.resource) ?? toolNames[0] ?? "", [toolMap, toolNames]);
7568
7676
  const initUrlParams = react.useMemo(() => {
7569
7677
  if (typeof window === "undefined") return {
7570
7678
  tool: null,
@@ -7585,12 +7693,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7585
7693
  if (initUrlParams.simulation) {
7586
7694
  for (const [toolName, info] of toolMap) if (info.simNames.includes(initUrlParams.simulation)) return toolName;
7587
7695
  }
7588
- return toolNames[0] ?? "";
7696
+ return defaultToolName;
7589
7697
  });
7590
7698
  const prevToolNamesRef = react.useRef(toolNames);
7591
7699
  if (prevToolNamesRef.current !== toolNames) {
7592
7700
  prevToolNamesRef.current = toolNames;
7593
- if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(toolNames[0]);
7701
+ if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(defaultToolName);
7594
7702
  }
7595
7703
  const selectedToolInfo = toolMap.get(selectedToolName);
7596
7704
  const [activeSimulationName, setActiveSimulationName] = react.useState(() => {
@@ -7614,6 +7722,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7614
7722
  defaultHost,
7615
7723
  preserveToolDataOnSimulationChange: isLiveMcpRender
7616
7724
  });
7725
+ const resetAppContextForSelectionChange = () => {
7726
+ state.setModelContext(null);
7727
+ state.setModelAppContext(null);
7728
+ state.setModelContextJson("null");
7729
+ state.setModelContextError("");
7730
+ };
7617
7731
  const [serverUrl, setServerUrl] = react.useState(mcpServerUrl ?? "");
7618
7732
  const [authType, setAuthType] = react.useState("none");
7619
7733
  const [bearerToken, setBearerToken] = react.useState("");
@@ -7629,7 +7743,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7629
7743
  const [isRunning, setIsRunning] = react.useState(false);
7630
7744
  const [hasRun, setHasRun] = react.useState(false);
7631
7745
  const [showCheck, setShowCheck] = react.useState(false);
7632
- const prodResourcesId = react.useId();
7633
7746
  const [serverPreviewGeneration, setServerPreviewGeneration] = react.useState(0);
7634
7747
  const checkTimerRef = react.useRef(void 0);
7635
7748
  const oauthCleanupRef = react.useRef(void 0);
@@ -7669,7 +7782,14 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7669
7782
  const [chatStatus, setChatStatus] = react.useState("");
7670
7783
  const currentModelProvider = react.useMemo(() => modelProviderOptions.find((provider) => provider.id === modelProvider), [modelProvider, modelProviderOptions]);
7671
7784
  const selectedProviderModelOptions = react.useMemo(() => currentModelProvider?.models ?? [], [currentModelProvider?.models]);
7672
- const modelCallableTools = react.useMemo(() => Array.from(toolMap.values()).filter((info) => !!info.resource && isToolVisibleToModel(info.tool)).map((info) => info.tool), [toolMap]);
7785
+ const modelCallableTools = react.useMemo(() => {
7786
+ const map = /* @__PURE__ */ new Map();
7787
+ for (const sim of Object.values(simulations)) {
7788
+ if (!isToolVisibleToModel(sim.tool) || map.has(sim.tool.name)) continue;
7789
+ map.set(sim.tool.name, sim.tool);
7790
+ }
7791
+ return Array.from(map.values());
7792
+ }, [simulations]);
7673
7793
  react.useEffect(() => {
7674
7794
  setServerUrl(mcpServerUrl ?? "");
7675
7795
  }, [mcpServerUrl]);
@@ -8089,7 +8209,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8089
8209
  const assistantMessage = {
8090
8210
  id: `assistant-${Date.now()}`,
8091
8211
  role: "assistant",
8092
- content: data.text ?? (toolCalls.length > 0 ? "I called the MCP tool and rendered the app below." : "The model returned an empty response."),
8212
+ 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."),
8093
8213
  toolCalls: toolCalls.map((call) => ({
8094
8214
  name: call.name,
8095
8215
  arguments: call.arguments,
@@ -8309,10 +8429,19 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8309
8429
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8310
8430
  className: "text-sm text-center max-w-xs",
8311
8431
  style: { color: "var(--color-text-secondary)" },
8312
- 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"
8432
+ 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"
8313
8433
  })
8314
8434
  });
8315
- } else if (showEmptyState) content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8435
+ } else if (!selectedToolInfo?.resource) content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8436
+ className: "h-full w-full flex items-center justify-center",
8437
+ style: { background: iframeBg },
8438
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8439
+ className: "text-sm text-center max-w-xs",
8440
+ style: { color: "var(--color-text-secondary)" },
8441
+ children: "Tool does not render a UI"
8442
+ })
8443
+ });
8444
+ else if (showEmptyState) content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8316
8445
  className: "h-full w-full flex items-center justify-center",
8317
8446
  style: { background: iframeBg },
8318
8447
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -8436,31 +8565,9 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8436
8565
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M0 0L10 6L0 12V0Z" })
8437
8566
  }), "Run"]
8438
8567
  }) : void 0;
8439
- const headerProdResourcesControl = !hideInspectorModes && !demoMode && !isEmbedded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8440
- className: "flex shrink-0 items-center gap-1.5 text-[11px] font-medium",
8441
- style: { color: "var(--color-text-secondary)" },
8442
- children: [
8443
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8444
- id: prodResourcesId,
8445
- type: "checkbox",
8446
- checked: prodResources,
8447
- onChange: (event) => setProdResources(event.currentTarget.checked),
8448
- className: "h-3.5 w-3.5 accent-[var(--color-text-primary)]"
8449
- }),
8450
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8451
- htmlFor: prodResourcesId,
8452
- className: "cursor-pointer select-none",
8453
- children: "Prod Resources"
8454
- }),
8455
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
8456
- tooltip: "Load resources from dist/ builds instead of HMR",
8457
- docsPath: "app-framework/cli/dev#prod-tools-and-prod-resources-flags"
8458
- })
8459
- ]
8460
- }) : null;
8461
- const headerAction = runButton || headerProdResourcesControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8462
- className: "flex min-w-0 items-center gap-2",
8463
- children: [runButton, headerProdResourcesControl]
8568
+ const headerAction = runButton ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8569
+ className: "flex min-w-0 items-center",
8570
+ children: runButton
8464
8571
  }) : void 0;
8465
8572
  const conversationContent = ShellConversation ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShellConversation, {
8466
8573
  screenWidth: state.screenWidth,
@@ -8483,6 +8590,11 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8483
8590
  children: content
8484
8591
  }) : content;
8485
8592
  const rootSizing = isEmbedded ? "h-full w-full" : "h-screen w-screen";
8593
+ const getJsonPanelFlexGrow = (value) => {
8594
+ const text = value || "";
8595
+ const lineCount = text.split("\n").length;
8596
+ return Math.max(1, Math.min(8, lineCount + Math.floor(text.length / 500)));
8597
+ };
8486
8598
  if (!showSidebar) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeProvider, {
8487
8599
  theme: state.theme,
8488
8600
  applyTheme,
@@ -8498,6 +8610,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8498
8610
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SimpleSidebar, {
8499
8611
  rootRef,
8500
8612
  fillParent: isEmbedded,
8613
+ sidebarWidth: state.sidebarWidth,
8614
+ rightSidebarWidth: state.rightSidebarWidth,
8615
+ onSidebarWidthChange: state.setSidebarWidth,
8616
+ onRightSidebarWidthChange: state.setRightSidebarWidth,
8501
8617
  controls: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8502
8618
  className: "space-y-1",
8503
8619
  children: [
@@ -8522,7 +8638,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8522
8638
  })
8523
8639
  }), !demoMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8524
8640
  label: "Authentication",
8525
- defaultCollapsed: authType === "none",
8641
+ defaultCollapsed: false,
8526
8642
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8527
8643
  className: "space-y-1",
8528
8644
  children: [
@@ -8606,70 +8722,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8606
8722
  ]
8607
8723
  })
8608
8724
  }, `auth-${authType === "none" ? "none" : "active"}`)] }),
8609
- canUseModelChat && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8610
- label: "Model Chat",
8611
- defaultCollapsed: true,
8612
- tooltip: "Talk to this MCP server through a model",
8613
- docsPath: "testing/evals",
8614
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8615
- className: "space-y-2",
8616
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8617
- className: "grid grid-cols-2 gap-2",
8618
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8619
- label: "Provider",
8620
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8621
- value: modelProvider,
8622
- onChange: handleModelProviderChange,
8623
- options: modelProviderOptions.map((provider) => ({
8624
- value: provider.id,
8625
- label: provider.label ?? provider.id
8626
- }))
8627
- })
8628
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8629
- label: "Model",
8630
- children: selectedProviderModelOptions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8631
- value: modelId,
8632
- onChange: setModelId,
8633
- options: selectedProviderModelOptions.map((model) => ({
8634
- value: model,
8635
- label: model
8636
- }))
8637
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8638
- value: modelId,
8639
- onChange: setModelId,
8640
- applyOnBlur: true,
8641
- placeholder: getDefaultModelId(modelProvider)
8642
- })
8643
- })]
8644
- }), usesApiKeyUi && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SidebarControl, {
8645
- label: "API Key",
8646
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8647
- className: "flex gap-1",
8648
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8649
- type: "password",
8650
- autoComplete: "new-password",
8651
- value: apiKeyDraft,
8652
- onChange: setApiKeyDraft,
8653
- placeholder: keyStatus.hasKey ? "Saved locally" : `Paste ${modelProvider} key`
8654
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8655
- type: "button",
8656
- onClick: handleSaveApiKey,
8657
- disabled: isKeyStatusLoading || !apiKeyDraft && !keyStatus.hasKey,
8658
- className: "h-7 rounded-md px-2 text-xs font-medium transition-opacity disabled:opacity-40",
8659
- style: {
8660
- backgroundColor: "var(--color-text-primary)",
8661
- color: "var(--color-background-primary)"
8662
- },
8663
- children: apiKeyDraft ? "Save" : "Clear"
8664
- })]
8665
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8666
- className: "mt-1 text-[9px]",
8667
- style: { color: "var(--color-text-secondary)" },
8668
- children: keyMessage || (isKeyStatusLoading ? "Checking saved key..." : keyStatus.hasKey ? `Key saved ${keyStatus.storage ?? "locally"}` : "Paste a key or use one already saved on this machine")
8669
- })]
8670
- })]
8671
- })
8672
- }),
8673
8725
  hasTools && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8674
8726
  className: "grid grid-cols-2 gap-2",
8675
8727
  "data-testid": "tool-simulation-row",
@@ -8682,6 +8734,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8682
8734
  value: selectedToolName,
8683
8735
  onChange: (value) => {
8684
8736
  setIsLiveMcpRender(false);
8737
+ resetAppContextForSelectionChange();
8685
8738
  setSelectedToolName(value);
8686
8739
  },
8687
8740
  options: toolNames.map((name) => {
@@ -8714,6 +8767,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8714
8767
  onChange: (value) => {
8715
8768
  if (value === "__live__") return;
8716
8769
  setIsLiveMcpRender(false);
8770
+ resetAppContextForSelectionChange();
8717
8771
  setActiveSimulationName(value === "__none__" ? null : value);
8718
8772
  },
8719
8773
  options: [
@@ -8775,6 +8829,80 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8775
8829
  })
8776
8830
  })]
8777
8831
  }),
8832
+ !hideInspectorModes && !demoMode && !isEmbedded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8833
+ className: "py-1",
8834
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCheckbox, {
8835
+ checked: prodResources,
8836
+ onChange: setProdResources,
8837
+ label: "Prod Resources",
8838
+ tooltip: "Load resources from dist/ builds instead of HMR",
8839
+ docsPath: "app-framework/cli/dev#prod-tools-and-prod-resources-flags"
8840
+ })
8841
+ }),
8842
+ canUseModelChat && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8843
+ label: "Model Chat",
8844
+ defaultCollapsed: false,
8845
+ tooltip: "Talk to this MCP server through a model",
8846
+ docsPath: "testing/evals",
8847
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8848
+ className: "space-y-1",
8849
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8850
+ className: "grid grid-cols-2 gap-2",
8851
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8852
+ label: "Provider",
8853
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8854
+ value: modelProvider,
8855
+ onChange: handleModelProviderChange,
8856
+ options: modelProviderOptions.map((provider) => ({
8857
+ value: provider.id,
8858
+ label: provider.label ?? provider.id
8859
+ }))
8860
+ })
8861
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8862
+ label: "Model",
8863
+ children: selectedProviderModelOptions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8864
+ value: modelId,
8865
+ onChange: setModelId,
8866
+ options: selectedProviderModelOptions.map((model) => ({
8867
+ value: model,
8868
+ label: model
8869
+ }))
8870
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8871
+ value: modelId,
8872
+ onChange: setModelId,
8873
+ applyOnBlur: true,
8874
+ placeholder: getDefaultModelId(modelProvider)
8875
+ })
8876
+ })]
8877
+ }), usesApiKeyUi && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SidebarControl, {
8878
+ label: "API Key",
8879
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8880
+ className: "flex gap-1",
8881
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8882
+ type: "password",
8883
+ autoComplete: "new-password",
8884
+ value: apiKeyDraft,
8885
+ onChange: setApiKeyDraft,
8886
+ placeholder: keyStatus.hasKey ? "Saved locally" : `Paste ${modelProvider} key`
8887
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8888
+ type: "button",
8889
+ onClick: handleSaveApiKey,
8890
+ disabled: isKeyStatusLoading || !apiKeyDraft && !keyStatus.hasKey,
8891
+ className: "h-7 rounded-md px-2 text-xs font-medium transition-opacity disabled:opacity-40",
8892
+ style: {
8893
+ backgroundColor: "var(--color-text-primary)",
8894
+ color: "var(--color-background-primary)"
8895
+ },
8896
+ children: apiKeyDraft ? "Save" : "Clear"
8897
+ })]
8898
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8899
+ className: "mt-1 text-[9px]",
8900
+ style: { color: "var(--color-text-secondary)" },
8901
+ children: keyMessage || (isKeyStatusLoading ? "Checking saved key..." : keyStatus.hasKey ? `Key saved ${keyStatus.storage ?? "locally"}` : "Paste a key or use one already saved on this machine")
8902
+ })]
8903
+ })]
8904
+ })
8905
+ }),
8778
8906
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8779
8907
  label: "Host Context",
8780
8908
  defaultCollapsed: false,
@@ -9037,14 +9165,24 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9037
9165
  })
9038
9166
  ]
9039
9167
  })
9040
- }),
9168
+ })
9169
+ ]
9170
+ }),
9171
+ rightControls: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9172
+ className: "flex h-full min-h-0 flex-col gap-3",
9173
+ children: [
9041
9174
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
9042
9175
  label: "App Context",
9043
- defaultCollapsed: true,
9176
+ defaultCollapsed: false,
9044
9177
  tooltip: "App-provided context shared with the model",
9045
9178
  docsPath: "app-framework/hooks/use-app-state",
9179
+ className: "flex min-h-0 flex-col",
9180
+ contentClassName: "min-h-0 flex-1",
9181
+ style: { flex: `${getJsonPanelFlexGrow(state.modelContextJson)} 1 0` },
9182
+ tooltipPlacement: "left",
9046
9183
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9047
9184
  value: state.modelContextJson,
9185
+ "data-testid": "app-context-textarea",
9048
9186
  onChange: (json) => state.validateJSON(json, state.setModelContextJson, state.setModelContextError),
9049
9187
  onFocus: () => state.setEditingField("modelContext"),
9050
9188
  onBlur: () => state.commitJSON(state.modelContextJson, state.setModelContextError, (parsed) => {
@@ -9055,7 +9193,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9055
9193
  });
9056
9194
  }),
9057
9195
  error: state.modelContextError,
9058
- maxRows: 8
9196
+ fill: true
9059
9197
  })
9060
9198
  }),
9061
9199
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
@@ -9063,6 +9201,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9063
9201
  defaultCollapsed: false,
9064
9202
  tooltip: "Arguments passed to the tool",
9065
9203
  docsPath: "app-framework/hooks/use-tool-data",
9204
+ className: "flex min-h-0 flex-col",
9205
+ contentClassName: "min-h-0 flex-1",
9206
+ style: { flex: `${getJsonPanelFlexGrow(state.toolInputJson)} 1 0` },
9207
+ tooltipPlacement: "left",
9066
9208
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9067
9209
  value: state.toolInputJson,
9068
9210
  "data-testid": "tool-input-textarea",
@@ -9070,7 +9212,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9070
9212
  onFocus: () => state.setEditingField("toolInput"),
9071
9213
  onBlur: () => state.commitJSON(state.toolInputJson, state.setToolInputError, (parsed) => state.setToolInput(parsed ?? {})),
9072
9214
  error: state.toolInputError,
9073
- maxRows: 8
9215
+ fill: true
9074
9216
  })
9075
9217
  }),
9076
9218
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
@@ -9079,6 +9221,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9079
9221
  tooltip: "Structured content returned by the tool",
9080
9222
  docsPath: "app-framework/hooks/use-tool-data",
9081
9223
  "data-testid": "tool-result-section",
9224
+ className: "flex min-h-0 flex-col",
9225
+ contentClassName: "min-h-0 flex-1",
9226
+ style: { flex: `${getJsonPanelFlexGrow(state.toolResultJson)} 1 0` },
9227
+ tooltipPlacement: "left",
9082
9228
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9083
9229
  value: state.toolResultJson,
9084
9230
  "data-testid": "tool-result-textarea",
@@ -9096,7 +9242,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9096
9242
  }
9097
9243
  }),
9098
9244
  error: state.toolResultError,
9099
- maxRows: 8
9245
+ fill: true
9100
9246
  })
9101
9247
  })
9102
9248
  ]
@@ -9258,4 +9404,4 @@ Object.defineProperty(exports, "useThemeContext", {
9258
9404
  }
9259
9405
  });
9260
9406
 
9261
- //# sourceMappingURL=inspector-DQ_vv1wj.cjs.map
9407
+ //# sourceMappingURL=inspector-BNWla95w.cjs.map