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
@@ -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) => {
@@ -6732,6 +6741,7 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6732
6741
  const [toolResultJson, setToolResultJson] = (0, react.useState)(() => JSON.stringify(toolResult ?? null, null, 2));
6733
6742
  const [modelContextJson, setModelContextJson] = (0, react.useState)("null");
6734
6743
  const [modelContext, setModelContext] = (0, react.useState)(null);
6744
+ const [modelAppContext, setModelAppContext] = (0, react.useState)(null);
6735
6745
  const [editingField, setEditingField] = (0, react.useState)(null);
6736
6746
  const [toolInputError, setToolInputError] = (0, react.useState)("");
6737
6747
  const [toolResultError, setToolResultError] = (0, react.useState)("");
@@ -6751,8 +6761,9 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6751
6761
  setToolResultError("");
6752
6762
  }
6753
6763
  if (editingField !== "modelContext") {
6754
- setModelContextJson("null");
6755
6764
  setModelContext(null);
6765
+ setModelAppContext(null);
6766
+ setModelContextJson("null");
6756
6767
  setModelContextError("");
6757
6768
  }
6758
6769
  }, [
@@ -6777,6 +6788,10 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6777
6788
  };
6778
6789
  const handleUpdateModelContext = (content, structuredContent) => {
6779
6790
  setModelContextJson(JSON.stringify(structuredContent ?? content, null, 2));
6791
+ setModelAppContext(structuredContent === void 0 && content.length === 0 ? null : {
6792
+ content,
6793
+ ...structuredContent !== void 0 ? { structuredContent } : {}
6794
+ });
6780
6795
  };
6781
6796
  const validateJSON = (json, setJson, setError) => {
6782
6797
  setJson(json);
@@ -6825,6 +6840,10 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6825
6840
  setActiveHost,
6826
6841
  screenWidth,
6827
6842
  setScreenWidth,
6843
+ sidebarWidth,
6844
+ setSidebarWidth,
6845
+ rightSidebarWidth,
6846
+ setRightSidebarWidth,
6828
6847
  theme,
6829
6848
  setTheme,
6830
6849
  displayMode,
@@ -6858,6 +6877,8 @@ function useInspectorState({ simulations, defaultHost = "chatgpt", preserveToolD
6858
6877
  effectiveToolResult,
6859
6878
  modelContext,
6860
6879
  setModelContext,
6880
+ modelAppContext,
6881
+ setModelAppContext,
6861
6882
  toolInputJson,
6862
6883
  setToolInputJson,
6863
6884
  toolInputError,
@@ -7053,9 +7074,10 @@ var useThemeContext = () => {
7053
7074
  if (context === void 0) throw new Error("useThemeContext must be used within a ThemeProvider");
7054
7075
  return context;
7055
7076
  };
7056
- //#endregion
7057
- //#region src/inspector/simple-sidebar.tsx
7058
- 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
+ }
7059
7081
  function ChevronRightIcon() {
7060
7082
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
7061
7083
  width: "1em",
@@ -7069,19 +7091,34 @@ function ChevronRightIcon() {
7069
7091
  })
7070
7092
  });
7071
7093
  }
7072
- function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent = false }) {
7094
+ function SimpleSidebar({ children, controls, rightControls, sidebarWidth, rightSidebarWidth, onSidebarWidthChange, onRightSidebarWidthChange, headerRight, rootRef, fillParent = false }) {
7073
7095
  const [isDrawerOpen, setIsDrawerOpen] = react.useState(false);
7074
- const [sidebarWidth, setSidebarWidth] = react.useState(DEFAULT_SIDEBAR_WIDTH);
7096
+ const [internalSidebarWidth, setInternalSidebarWidth] = react.useState(260);
7097
+ const [internalRightSidebarWidth, setInternalRightSidebarWidth] = react.useState(260);
7075
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]);
7076
7110
  const handleMouseDown = react.useCallback((e) => {
7077
7111
  e.preventDefault();
7078
7112
  setIsResizing(true);
7079
7113
  }, []);
7114
+ const handleRightMouseDown = react.useCallback((e) => {
7115
+ e.preventDefault();
7116
+ setIsResizingRight(true);
7117
+ }, []);
7080
7118
  react.useEffect(() => {
7081
7119
  if (!isResizing) return;
7082
7120
  const handleMouseMove = (e) => {
7083
- const maxWidth = Math.floor(window.innerWidth / 3);
7084
- setSidebarWidth(Math.min(maxWidth, Math.max(DEFAULT_SIDEBAR_WIDTH, e.clientX)));
7121
+ setSidebarWidth(clampSidebarWidth(e.clientX, window.innerWidth));
7085
7122
  };
7086
7123
  const handleMouseUp = () => {
7087
7124
  setIsResizing(false);
@@ -7092,12 +7129,27 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7092
7129
  document.removeEventListener("mousemove", handleMouseMove);
7093
7130
  document.removeEventListener("mouseup", handleMouseUp);
7094
7131
  };
7095
- }, [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]);
7096
7148
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7097
7149
  ref: rootRef,
7098
7150
  className: `sunpeak-inspector-root flex ${fillParent ? "h-full w-full" : "h-screen w-full"} overflow-hidden relative`,
7099
7151
  children: [
7100
- 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" }),
7101
7153
  isDrawerOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7102
7154
  className: "md:hidden fixed inset-0 bg-black/50 z-40 pointer-events-auto",
7103
7155
  onClick: (e) => {
@@ -7113,7 +7165,7 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7113
7165
  ${isDrawerOpen ? "max-md:translate-x-0" : "max-md:-translate-x-full"}
7114
7166
  `,
7115
7167
  style: {
7116
- width: sidebarWidth,
7168
+ width: effectiveSidebarWidth,
7117
7169
  borderRight: "1px solid var(--color-border-primary)"
7118
7170
  },
7119
7171
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -7166,19 +7218,69 @@ function SimpleSidebar({ children, controls, headerRight, rootRef, fillParent =
7166
7218
  "aria-label": "Open sidebar",
7167
7219
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {})
7168
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
+ })]
7169
7235
  })
7170
7236
  ]
7171
7237
  });
7172
7238
  }
7173
7239
  var DOCS_BASE_URL$1 = "https://sunpeak.ai/docs";
7174
- 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]);
7175
7263
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
7264
+ ref: linkRef,
7176
7265
  href: `${DOCS_BASE_URL$1}/${docsPath}`,
7177
7266
  target: "_blank",
7178
7267
  rel: "noopener noreferrer",
7179
7268
  "aria-label": tooltip,
7180
7269
  className: "group relative inline-flex items-center justify-center no-underline flex-shrink-0 transition-colors",
7181
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),
7182
7284
  onClick: (e) => e.stopPropagation(),
7183
7285
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
7184
7286
  width: "12",
@@ -7204,8 +7306,11 @@ function HelpIcon({ tooltip, docsPath }) {
7204
7306
  })]
7205
7307
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7206
7308
  "aria-hidden": "true",
7207
- 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"}`,
7208
7310
  style: {
7311
+ left: tooltipPosition.left,
7312
+ top: tooltipPosition.top,
7313
+ transform: tooltipTransform,
7209
7314
  backgroundColor: "var(--color-text-primary)",
7210
7315
  color: "var(--color-background-primary)"
7211
7316
  },
@@ -7213,7 +7318,7 @@ function HelpIcon({ tooltip, docsPath }) {
7213
7318
  })]
7214
7319
  });
7215
7320
  }
7216
- function SidebarControl({ label, children, tooltip, docsPath, "data-testid": testId }) {
7321
+ function SidebarControl({ label, children, tooltip, tooltipPlacement, docsPath, "data-testid": testId }) {
7217
7322
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7218
7323
  className: "space-y-1",
7219
7324
  "data-testid": testId,
@@ -7222,15 +7327,17 @@ function SidebarControl({ label, children, tooltip, docsPath, "data-testid": tes
7222
7327
  style: { color: "var(--color-text-secondary)" },
7223
7328
  children: [label, tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7224
7329
  tooltip,
7225
- docsPath
7330
+ docsPath,
7331
+ placement: tooltipPlacement
7226
7332
  })]
7227
7333
  }), children]
7228
7334
  });
7229
7335
  }
7230
- 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 }) {
7231
7337
  const [isCollapsed, setIsCollapsed] = react.useState(defaultCollapsed);
7232
7338
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7233
- className: "space-y-1",
7339
+ className: className ? `space-y-1 ${className}` : "space-y-1",
7340
+ style: isCollapsed ? void 0 : style,
7234
7341
  "data-testid": testId,
7235
7342
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7236
7343
  onClick: () => setIsCollapsed(!isCollapsed),
@@ -7241,13 +7348,17 @@ function SidebarCollapsibleControl({ label, children, defaultCollapsed = true, t
7241
7348
  className: "inline-flex items-center gap-1",
7242
7349
  children: [label, tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7243
7350
  tooltip,
7244
- docsPath
7351
+ docsPath,
7352
+ placement: tooltipPlacement
7245
7353
  })]
7246
7354
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7247
7355
  className: "text-[8px]",
7248
7356
  children: isCollapsed ? "▶" : "▼"
7249
7357
  })]
7250
- }), !isCollapsed && children]
7358
+ }), !isCollapsed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7359
+ className: contentClassName,
7360
+ children
7361
+ })]
7251
7362
  });
7252
7363
  }
7253
7364
  var formElementStyle = {
@@ -7322,7 +7433,7 @@ function SidebarInput({ value, onChange, applyOnBlur = false, autoComplete, plac
7322
7433
  }
7323
7434
  });
7324
7435
  }
7325
- function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7436
+ function SidebarCheckbox({ checked, onChange, label, tooltip, tooltipPlacement, docsPath }) {
7326
7437
  const id = react.useId();
7327
7438
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7328
7439
  className: "flex items-center gap-1.5",
@@ -7342,24 +7453,25 @@ function SidebarCheckbox({ checked, onChange, label, tooltip, docsPath }) {
7342
7453
  }),
7343
7454
  tooltip && docsPath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
7344
7455
  tooltip,
7345
- docsPath
7456
+ docsPath,
7457
+ placement: tooltipPlacement
7346
7458
  })
7347
7459
  ]
7348
7460
  });
7349
7461
  }
7350
- 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 }) {
7351
7463
  const contentRows = value?.split("\n").length ?? 1;
7352
7464
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7353
- className: "space-y-0.5",
7465
+ className: fill ? "flex h-full min-h-0 flex-col gap-0.5" : "space-y-0.5",
7354
7466
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
7355
7467
  value,
7356
7468
  onChange: (e) => onChange(e.target.value),
7357
7469
  onFocus,
7358
7470
  onBlur,
7359
7471
  placeholder,
7360
- rows: Math.min(contentRows, maxRows),
7472
+ rows: fill ? void 0 : Math.min(contentRows, maxRows),
7361
7473
  "data-testid": testId,
7362
- 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"}`,
7363
7475
  style: {
7364
7476
  ...formElementStyle,
7365
7477
  cursor: "text",
@@ -7448,10 +7560,9 @@ function flattenAppToSimulations(app) {
7448
7560
  }
7449
7561
  for (const appTool of app.tools) {
7450
7562
  const uri = getOutputTemplate(appTool.tool._meta);
7451
- if (!uri) continue;
7452
- const resource = resourcesByUri.get(uri);
7453
- if (!resource) continue;
7454
- 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;
7455
7566
  const sims = appTool.simulations && appTool.simulations.length > 0 ? appTool.simulations : [{ name: appTool.tool.name }];
7456
7567
  for (const sim of sims) {
7457
7568
  const key = `${appTool.tool.name}__${sim.name}`;
@@ -7459,10 +7570,12 @@ function flattenAppToSimulations(app) {
7459
7570
  result[key] = {
7460
7571
  name: key,
7461
7572
  displayName: sim.name,
7462
- resourceHtml: resource.html,
7573
+ ...resource ? {
7574
+ resourceHtml: resource.html,
7575
+ resource: mcpResource
7576
+ } : {},
7463
7577
  userMessage: sim.userMessage,
7464
7578
  tool: appTool.tool,
7465
- resource: mcpResource,
7466
7579
  toolInput: sim.toolInput,
7467
7580
  toolResult: sim.toolResult,
7468
7581
  serverTools: sim.serverTools
@@ -7538,7 +7651,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7538
7651
  const toolMap = react.useMemo(() => {
7539
7652
  const map = /* @__PURE__ */ new Map();
7540
7653
  for (const [simName, sim] of Object.entries(simulations)) {
7541
- if (!sim.resource) continue;
7542
7654
  const toolName = sim.tool.name;
7543
7655
  if (!map.has(toolName)) map.set(toolName, {
7544
7656
  tool: sim.tool,
@@ -7547,6 +7659,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7547
7659
  fixtureSimNames: []
7548
7660
  });
7549
7661
  const info = map.get(toolName);
7662
+ if (!info.resource && sim.resource) info.resource = sim.resource;
7550
7663
  info.simNames.push(simName);
7551
7664
  if (hasFixtureData(sim)) info.fixtureSimNames.push(simName);
7552
7665
  }
@@ -7559,6 +7672,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7559
7672
  const labelB = infoB.tool.title || b;
7560
7673
  return labelA.localeCompare(labelB);
7561
7674
  }), [toolMap]);
7675
+ const defaultToolName = react.useMemo(() => toolNames.find((name) => !!toolMap.get(name)?.resource) ?? toolNames[0] ?? "", [toolMap, toolNames]);
7562
7676
  const initUrlParams = react.useMemo(() => {
7563
7677
  if (typeof window === "undefined") return {
7564
7678
  tool: null,
@@ -7579,12 +7693,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7579
7693
  if (initUrlParams.simulation) {
7580
7694
  for (const [toolName, info] of toolMap) if (info.simNames.includes(initUrlParams.simulation)) return toolName;
7581
7695
  }
7582
- return toolNames[0] ?? "";
7696
+ return defaultToolName;
7583
7697
  });
7584
7698
  const prevToolNamesRef = react.useRef(toolNames);
7585
7699
  if (prevToolNamesRef.current !== toolNames) {
7586
7700
  prevToolNamesRef.current = toolNames;
7587
- if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(toolNames[0]);
7701
+ if (toolNames.length > 0 && !toolMap.has(selectedToolName)) setSelectedToolName(defaultToolName);
7588
7702
  }
7589
7703
  const selectedToolInfo = toolMap.get(selectedToolName);
7590
7704
  const [activeSimulationName, setActiveSimulationName] = react.useState(() => {
@@ -7608,6 +7722,12 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7608
7722
  defaultHost,
7609
7723
  preserveToolDataOnSimulationChange: isLiveMcpRender
7610
7724
  });
7725
+ const resetAppContextForSelectionChange = () => {
7726
+ state.setModelContext(null);
7727
+ state.setModelAppContext(null);
7728
+ state.setModelContextJson("null");
7729
+ state.setModelContextError("");
7730
+ };
7611
7731
  const [serverUrl, setServerUrl] = react.useState(mcpServerUrl ?? "");
7612
7732
  const [authType, setAuthType] = react.useState("none");
7613
7733
  const [bearerToken, setBearerToken] = react.useState("");
@@ -7623,7 +7743,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7623
7743
  const [isRunning, setIsRunning] = react.useState(false);
7624
7744
  const [hasRun, setHasRun] = react.useState(false);
7625
7745
  const [showCheck, setShowCheck] = react.useState(false);
7626
- const prodResourcesId = react.useId();
7627
7746
  const [serverPreviewGeneration, setServerPreviewGeneration] = react.useState(0);
7628
7747
  const checkTimerRef = react.useRef(void 0);
7629
7748
  const oauthCleanupRef = react.useRef(void 0);
@@ -7663,7 +7782,14 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
7663
7782
  const [chatStatus, setChatStatus] = react.useState("");
7664
7783
  const currentModelProvider = react.useMemo(() => modelProviderOptions.find((provider) => provider.id === modelProvider), [modelProvider, modelProviderOptions]);
7665
7784
  const selectedProviderModelOptions = react.useMemo(() => currentModelProvider?.models ?? [], [currentModelProvider?.models]);
7666
- 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]);
7667
7793
  react.useEffect(() => {
7668
7794
  setServerUrl(mcpServerUrl ?? "");
7669
7795
  }, [mcpServerUrl]);
@@ -8043,7 +8169,8 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8043
8169
  provider: modelProvider,
8044
8170
  modelId,
8045
8171
  messages,
8046
- tools: modelCallableTools
8172
+ tools: modelCallableTools,
8173
+ appContext: state.modelAppContext ?? void 0
8047
8174
  });
8048
8175
  else {
8049
8176
  const endpoint = inspectorApiEndpoint("/__sunpeak/model-chat", inspectorApiBaseUrl);
@@ -8053,7 +8180,8 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8053
8180
  body: JSON.stringify({
8054
8181
  provider: modelProvider,
8055
8182
  modelId,
8056
- messages
8183
+ messages,
8184
+ appContext: state.modelAppContext ?? void 0
8057
8185
  })
8058
8186
  });
8059
8187
  data = await readInspectorJson(res, endpoint);
@@ -8081,7 +8209,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8081
8209
  const assistantMessage = {
8082
8210
  id: `assistant-${Date.now()}`,
8083
8211
  role: "assistant",
8084
- 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."),
8085
8213
  toolCalls: toolCalls.map((call) => ({
8086
8214
  name: call.name,
8087
8215
  arguments: call.arguments,
@@ -8301,10 +8429,19 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8301
8429
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8302
8430
  className: "text-sm text-center max-w-xs",
8303
8431
  style: { color: "var(--color-text-secondary)" },
8304
- 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"
8305
8433
  })
8306
8434
  });
8307
- } 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", {
8308
8445
  className: "h-full w-full flex items-center justify-center",
8309
8446
  style: { background: iframeBg },
8310
8447
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -8428,31 +8565,9 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8428
8565
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M0 0L10 6L0 12V0Z" })
8429
8566
  }), "Run"]
8430
8567
  }) : void 0;
8431
- const headerProdResourcesControl = !hideInspectorModes && !demoMode && !isEmbedded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8432
- className: "flex shrink-0 items-center gap-1.5 text-[11px] font-medium",
8433
- style: { color: "var(--color-text-secondary)" },
8434
- children: [
8435
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8436
- id: prodResourcesId,
8437
- type: "checkbox",
8438
- checked: prodResources,
8439
- onChange: (event) => setProdResources(event.currentTarget.checked),
8440
- className: "h-3.5 w-3.5 accent-[var(--color-text-primary)]"
8441
- }),
8442
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8443
- htmlFor: prodResourcesId,
8444
- className: "cursor-pointer select-none",
8445
- children: "Prod Resources"
8446
- }),
8447
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelpIcon, {
8448
- tooltip: "Load resources from dist/ builds instead of HMR",
8449
- docsPath: "app-framework/cli/dev#prod-tools-and-prod-resources-flags"
8450
- })
8451
- ]
8452
- }) : null;
8453
- const headerAction = runButton || headerProdResourcesControl ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8454
- className: "flex min-w-0 items-center gap-2",
8455
- 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
8456
8571
  }) : void 0;
8457
8572
  const conversationContent = ShellConversation ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShellConversation, {
8458
8573
  screenWidth: state.screenWidth,
@@ -8475,6 +8590,11 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8475
8590
  children: content
8476
8591
  }) : content;
8477
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
+ };
8478
8598
  if (!showSidebar) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeProvider, {
8479
8599
  theme: state.theme,
8480
8600
  applyTheme,
@@ -8490,6 +8610,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8490
8610
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SimpleSidebar, {
8491
8611
  rootRef,
8492
8612
  fillParent: isEmbedded,
8613
+ sidebarWidth: state.sidebarWidth,
8614
+ rightSidebarWidth: state.rightSidebarWidth,
8615
+ onSidebarWidthChange: state.setSidebarWidth,
8616
+ onRightSidebarWidthChange: state.setRightSidebarWidth,
8493
8617
  controls: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8494
8618
  className: "space-y-1",
8495
8619
  children: [
@@ -8514,7 +8638,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8514
8638
  })
8515
8639
  }), !demoMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8516
8640
  label: "Authentication",
8517
- defaultCollapsed: authType === "none",
8641
+ defaultCollapsed: false,
8518
8642
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8519
8643
  className: "space-y-1",
8520
8644
  children: [
@@ -8598,70 +8722,6 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8598
8722
  ]
8599
8723
  })
8600
8724
  }, `auth-${authType === "none" ? "none" : "active"}`)] }),
8601
- canUseModelChat && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8602
- label: "Model Chat",
8603
- defaultCollapsed: true,
8604
- tooltip: "Talk to this MCP server through a model",
8605
- docsPath: "testing/evals",
8606
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8607
- className: "space-y-2",
8608
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8609
- className: "grid grid-cols-2 gap-2",
8610
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8611
- label: "Provider",
8612
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8613
- value: modelProvider,
8614
- onChange: handleModelProviderChange,
8615
- options: modelProviderOptions.map((provider) => ({
8616
- value: provider.id,
8617
- label: provider.label ?? provider.id
8618
- }))
8619
- })
8620
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarControl, {
8621
- label: "Model",
8622
- children: selectedProviderModelOptions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSelect, {
8623
- value: modelId,
8624
- onChange: setModelId,
8625
- options: selectedProviderModelOptions.map((model) => ({
8626
- value: model,
8627
- label: model
8628
- }))
8629
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8630
- value: modelId,
8631
- onChange: setModelId,
8632
- applyOnBlur: true,
8633
- placeholder: getDefaultModelId(modelProvider)
8634
- })
8635
- })]
8636
- }), usesApiKeyUi && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SidebarControl, {
8637
- label: "API Key",
8638
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8639
- className: "flex gap-1",
8640
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarInput, {
8641
- type: "password",
8642
- autoComplete: "new-password",
8643
- value: apiKeyDraft,
8644
- onChange: setApiKeyDraft,
8645
- placeholder: keyStatus.hasKey ? "Saved locally" : `Paste ${modelProvider} key`
8646
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8647
- type: "button",
8648
- onClick: handleSaveApiKey,
8649
- disabled: isKeyStatusLoading || !apiKeyDraft && !keyStatus.hasKey,
8650
- className: "h-7 rounded-md px-2 text-xs font-medium transition-opacity disabled:opacity-40",
8651
- style: {
8652
- backgroundColor: "var(--color-text-primary)",
8653
- color: "var(--color-background-primary)"
8654
- },
8655
- children: apiKeyDraft ? "Save" : "Clear"
8656
- })]
8657
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8658
- className: "mt-1 text-[9px]",
8659
- style: { color: "var(--color-text-secondary)" },
8660
- children: keyMessage || (isKeyStatusLoading ? "Checking saved key..." : keyStatus.hasKey ? `Key saved ${keyStatus.storage ?? "locally"}` : "Paste a key or use one already saved on this machine")
8661
- })]
8662
- })]
8663
- })
8664
- }),
8665
8725
  hasTools && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8666
8726
  className: "grid grid-cols-2 gap-2",
8667
8727
  "data-testid": "tool-simulation-row",
@@ -8674,6 +8734,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8674
8734
  value: selectedToolName,
8675
8735
  onChange: (value) => {
8676
8736
  setIsLiveMcpRender(false);
8737
+ resetAppContextForSelectionChange();
8677
8738
  setSelectedToolName(value);
8678
8739
  },
8679
8740
  options: toolNames.map((name) => {
@@ -8706,6 +8767,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8706
8767
  onChange: (value) => {
8707
8768
  if (value === "__live__") return;
8708
8769
  setIsLiveMcpRender(false);
8770
+ resetAppContextForSelectionChange();
8709
8771
  setActiveSimulationName(value === "__none__" ? null : value);
8710
8772
  },
8711
8773
  options: [
@@ -8767,6 +8829,80 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
8767
8829
  })
8768
8830
  })]
8769
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
+ }),
8770
8906
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
8771
8907
  label: "Host Context",
8772
8908
  defaultCollapsed: false,
@@ -9029,21 +9165,35 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9029
9165
  })
9030
9166
  ]
9031
9167
  })
9032
- }),
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: [
9033
9174
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
9034
9175
  label: "App Context",
9035
- defaultCollapsed: true,
9176
+ defaultCollapsed: false,
9036
9177
  tooltip: "App-provided context shared with the model",
9037
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",
9038
9183
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9039
9184
  value: state.modelContextJson,
9185
+ "data-testid": "app-context-textarea",
9040
9186
  onChange: (json) => state.validateJSON(json, state.setModelContextJson, state.setModelContextError),
9041
9187
  onFocus: () => state.setEditingField("modelContext"),
9042
9188
  onBlur: () => state.commitJSON(state.modelContextJson, state.setModelContextError, (parsed) => {
9043
- state.setModelContext(parsed);
9189
+ state.setModelContext(parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null);
9190
+ state.setModelAppContext(parsed == null ? null : {
9191
+ content: [],
9192
+ structuredContent: parsed
9193
+ });
9044
9194
  }),
9045
9195
  error: state.modelContextError,
9046
- maxRows: 8
9196
+ fill: true
9047
9197
  })
9048
9198
  }),
9049
9199
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
@@ -9051,6 +9201,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9051
9201
  defaultCollapsed: false,
9052
9202
  tooltip: "Arguments passed to the tool",
9053
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",
9054
9208
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9055
9209
  value: state.toolInputJson,
9056
9210
  "data-testid": "tool-input-textarea",
@@ -9058,7 +9212,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9058
9212
  onFocus: () => state.setEditingField("toolInput"),
9059
9213
  onBlur: () => state.commitJSON(state.toolInputJson, state.setToolInputError, (parsed) => state.setToolInput(parsed ?? {})),
9060
9214
  error: state.toolInputError,
9061
- maxRows: 8
9215
+ fill: true
9062
9216
  })
9063
9217
  }),
9064
9218
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsibleControl, {
@@ -9067,6 +9221,10 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9067
9221
  tooltip: "Structured content returned by the tool",
9068
9222
  docsPath: "app-framework/hooks/use-tool-data",
9069
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",
9070
9228
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarTextarea, {
9071
9229
  value: state.toolResultJson,
9072
9230
  "data-testid": "tool-result-textarea",
@@ -9084,7 +9242,7 @@ function Inspector({ children, app, simulations: initialSimulationsProp = EMPTY_
9084
9242
  }
9085
9243
  }),
9086
9244
  error: state.toolResultError,
9087
- maxRows: 8
9245
+ fill: true
9088
9246
  })
9089
9247
  })
9090
9248
  ]
@@ -9246,4 +9404,4 @@ Object.defineProperty(exports, "useThemeContext", {
9246
9404
  }
9247
9405
  });
9248
9406
 
9249
- //# sourceMappingURL=inspector-CJA_uM9g.cjs.map
9407
+ //# sourceMappingURL=inspector-BNWla95w.cjs.map