sunpeak 0.17.4 → 0.17.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/bin/commands/dev.mjs +4 -3
  2. package/bin/commands/inspect.mjs +58 -33
  3. package/dist/chatgpt/globals.css +5 -0
  4. package/dist/chatgpt/index.cjs +2 -2
  5. package/dist/chatgpt/index.js +2 -2
  6. package/dist/claude/index.cjs +1 -1
  7. package/dist/claude/index.js +1 -1
  8. package/dist/index.cjs +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/mcp/index.cjs +1 -1
  11. package/dist/mcp/index.cjs.map +1 -1
  12. package/dist/mcp/index.js +1 -1
  13. package/dist/mcp/index.js.map +1 -1
  14. package/dist/mcp/types.d.ts +7 -0
  15. package/dist/simulator/index.cjs +2 -2
  16. package/dist/simulator/index.cjs.map +1 -1
  17. package/dist/simulator/index.js +2 -2
  18. package/dist/simulator/index.js.map +1 -1
  19. package/dist/simulator/simulator-url.d.ts +32 -41
  20. package/dist/simulator/simulator.d.ts +14 -10
  21. package/dist/simulator/use-mcp-connection.d.ts +12 -7
  22. package/dist/simulator/use-simulator-state.d.ts +1 -1
  23. package/dist/{simulator-Dl8B-Ljb.js → simulator-BijjlOXb.js} +278 -143
  24. package/dist/simulator-BijjlOXb.js.map +1 -0
  25. package/dist/{simulator-CH9hs0N6.cjs → simulator-DqWETA_1.cjs} +278 -143
  26. package/dist/simulator-DqWETA_1.cjs.map +1 -0
  27. package/dist/{simulator-url-CozKF1jf.cjs → simulator-url-3ATCsPOT.cjs} +11 -30
  28. package/dist/simulator-url-3ATCsPOT.cjs.map +1 -0
  29. package/dist/{simulator-url-KoS_ToP6.js → simulator-url-BbuuWa7S.js} +11 -30
  30. package/dist/simulator-url-BbuuWa7S.js.map +1 -0
  31. package/dist/style.css +5 -0
  32. package/package.json +1 -1
  33. package/template/dist/albums/albums.html +1 -1
  34. package/template/dist/albums/albums.json +1 -1
  35. package/template/dist/carousel/carousel.html +1 -1
  36. package/template/dist/carousel/carousel.json +1 -1
  37. package/template/dist/map/map.html +1 -1
  38. package/template/dist/map/map.json +1 -1
  39. package/template/dist/review/review.html +1 -1
  40. package/template/dist/review/review.json +1 -1
  41. package/template/tests/e2e/albums.spec.ts +3 -9
  42. package/template/tests/e2e/carousel.spec.ts +3 -9
  43. package/template/tests/e2e/map.spec.ts +3 -9
  44. package/template/tests/e2e/review.spec.ts +3 -9
  45. package/dist/simulator-CH9hs0N6.cjs.map +0 -1
  46. package/dist/simulator-Dl8B-Ljb.js.map +0 -1
  47. package/dist/simulator-url-CozKF1jf.cjs.map +0 -1
  48. package/dist/simulator-url-KoS_ToP6.js.map +0 -1
@@ -159,11 +159,11 @@ export async function dev(projectRoot = process.cwd(), args = []) {
159
159
  // Parse --no-begging flag
160
160
  const noBegging = args.includes('--no-begging');
161
161
 
162
- // Parse --prod-tools and --prod-resources flags
162
+ // Parse flags
163
163
  const isProdTools = args.includes('--prod-tools');
164
164
  const isProdResources = args.includes('--prod-resources');
165
165
 
166
- if (isProdTools) console.log('Prod Tools enabled by default (toggle in simulator sidebar)');
166
+ if (isProdTools) console.log('Prod Tools: MCP tool calls will use real handlers instead of simulation mocks');
167
167
  if (isProdResources) console.log('Prod Resources: resources will use production-built HTML from dist/');
168
168
 
169
169
  console.log(`Starting dev server on port ${port}...`);
@@ -496,6 +496,8 @@ if (import.meta.hot) {
496
496
  // In --prod-resources mode, don't pass viteServer so the MCP server serves pre-built HTML.
497
497
  // Otherwise, pass it so ChatGPT gets Vite HMR.
498
498
  viteServer: isProdResources ? undefined : mcpViteServer,
499
+ // When --prod-tools is set, UI tool calls use real handlers instead of simulation mocks.
500
+ prodTools: isProdTools,
499
501
  });
500
502
 
501
503
  // Wait for the MCP server to be listening before starting the inspector
@@ -520,7 +522,6 @@ if (import.meta.hot) {
520
522
  name: serverDisplayName,
521
523
  sandboxUrl: sandbox.url,
522
524
  frameworkMode: true,
523
- defaultProdTools: isProdTools,
524
525
  defaultProdResources: isProdResources,
525
526
  projectRoot,
526
527
  noBegging,
@@ -206,11 +206,11 @@ function mergeSimulationFixtures(dir, simulations) {
206
206
  * Vite plugin that serves virtual modules for the inspect entry point.
207
207
  *
208
208
  * @param {Record<string, object>} simulations - Simulation objects
209
- * @param {string|null} serverUrl - MCP server URL (null in framework mode to hide server UI)
209
+ * @param {string} serverUrl - MCP server URL
210
210
  * @param {string} appName - Display name
211
211
  * @param {string|null} appIcon - Icon URL or emoji
212
212
  * @param {string} sandboxUrl - Sandbox server URL
213
- * @param {{ defaultProdTools?: boolean, defaultProdResources?: boolean }} [modeFlags] - Mode toggles
213
+ * @param {{ defaultProdResources?: boolean, hideSimulatorModes?: boolean }} [modeFlags] - Mode toggles
214
214
  */
215
215
  function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, sandboxUrl, modeFlags = {}) {
216
216
  const ENTRY_ID = 'virtual:sunpeak-inspect-entry';
@@ -224,13 +224,6 @@ function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, s
224
224
  load(id) {
225
225
  if (id !== RESOLVED_ENTRY_ID) return;
226
226
 
227
- // In framework mode (serverUrl is null), don't pass mcpServerUrl to the
228
- // Simulator — this enables the prod-tools/prod-resources toggles and hides
229
- // the server URL input in the sidebar.
230
- const mcpServerUrlProp = serverUrl != null
231
- ? `mcpServerUrl: ${JSON.stringify(serverUrl)},`
232
- : '';
233
-
234
227
  return `
235
228
  import { createElement, StrictMode } from 'react';
236
229
  import { createRoot } from 'react-dom/client';
@@ -242,8 +235,8 @@ const simulations = ${JSON.stringify(simulations)};
242
235
  const appName = ${JSON.stringify(appName ?? 'MCP Inspector')};
243
236
  const appIcon = ${JSON.stringify(appIcon ?? null)};
244
237
  const sandboxUrl = ${JSON.stringify(sandboxUrl)};
245
- const defaultProdTools = ${JSON.stringify(modeFlags.defaultProdTools ?? false)};
246
238
  const defaultProdResources = ${JSON.stringify(modeFlags.defaultProdResources ?? false)};
239
+ const hideSimulatorModes = ${JSON.stringify(modeFlags.hideSimulatorModes ?? false)};
247
240
 
248
241
  const onCallTool = async (params) => {
249
242
  const res = await fetch('/__sunpeak/call-tool', {
@@ -268,14 +261,14 @@ root.render(
268
261
  createElement(StrictMode, null,
269
262
  createElement(Simulator, {
270
263
  simulations,
271
- ${mcpServerUrlProp}
264
+ mcpServerUrl: ${JSON.stringify(serverUrl)},
272
265
  appName,
273
266
  appIcon,
274
267
  sandboxUrl,
275
268
  onCallTool,
276
269
  onCallToolDirect,
277
- defaultProdTools,
278
270
  defaultProdResources,
271
+ hideSimulatorModes,
279
272
  })
280
273
  )
281
274
  );
@@ -287,9 +280,10 @@ root.render(
287
280
  /**
288
281
  * Vite plugin for MCP server proxy endpoints.
289
282
  * @param {() => import('@modelcontextprotocol/sdk/client/index.js').Client} getClient
290
- * @param {{ callToolDirect?: (name: string, args: Record<string, unknown>) => Promise<object> }} [pluginOpts]
283
+ * @param {(client: import('@modelcontextprotocol/sdk/client/index.js').Client) => void} setClient
284
+ * @param {{ callToolDirect?: (name: string, args: Record<string, unknown>) => Promise<object>, simulationsDir?: string | null }} [pluginOpts]
291
285
  */
292
- function sunpeakInspectEndpointsPlugin(getClient, pluginOpts = {}) {
286
+ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
293
287
  return {
294
288
  name: 'sunpeak-inspect-endpoints',
295
289
  configureServer(server) {
@@ -390,11 +384,8 @@ function sunpeakInspectEndpointsPlugin(getClient, pluginOpts = {}) {
390
384
  }
391
385
  });
392
386
 
393
- // Reconnect to a new server URL.
394
- // Currently acknowledges without actually reconnecting the MCP client
395
- // connection is established at startup. Changing the URL in the sidebar
396
- // requires restarting the inspect server. This endpoint exists so the
397
- // useMcpConnection hook can verify the server is reachable.
387
+ // Reconnect to a new MCP server URL.
388
+ // Creates a new MCP client connection and replaces the current one.
398
389
  server.middlewares.use('/__sunpeak/connect', async (req, res) => {
399
390
  if (req.method !== 'POST') {
400
391
  res.writeHead(405);
@@ -402,12 +393,47 @@ function sunpeakInspectEndpointsPlugin(getClient, pluginOpts = {}) {
402
393
  return;
403
394
  }
404
395
 
396
+ const body = await readRequestBody(req);
397
+ let parsed;
405
398
  try {
406
- // Verify the MCP client is still connected by listing tools
407
- const client = getClient();
408
- await client.listTools();
399
+ parsed = JSON.parse(body);
400
+ } catch {
401
+ res.writeHead(400, { 'Content-Type': 'application/json' });
402
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
403
+ return;
404
+ }
405
+
406
+ const url = parsed.url;
407
+ if (!url) {
408
+ // No URL provided — just verify current connection
409
+ try {
410
+ const client = getClient();
411
+ await client.listTools();
412
+ res.writeHead(200, { 'Content-Type': 'application/json' });
413
+ res.end(JSON.stringify({ status: 'ok' }));
414
+ } catch (err) {
415
+ res.writeHead(500, { 'Content-Type': 'application/json' });
416
+ res.end(JSON.stringify({ error: err.message }));
417
+ }
418
+ return;
419
+ }
420
+
421
+ try {
422
+ // Close old connection (best effort)
423
+ try { await getClient().close(); } catch { /* ignore */ }
424
+
425
+ // Create new connection
426
+ const newConnection = await createMcpConnection(url);
427
+ setClient(newConnection.client);
428
+
429
+ // Discover tools and resources from the new server
430
+ const simulations = await discoverSimulations(newConnection.client);
431
+ // Merge fixture data so simulations have mock toolInput/toolResult
432
+ if (pluginOpts.simulationsDir) {
433
+ mergeSimulationFixtures(pluginOpts.simulationsDir, simulations);
434
+ }
409
435
  res.writeHead(200, { 'Content-Type': 'application/json' });
410
- res.end(JSON.stringify({ status: 'ok' }));
436
+ res.end(JSON.stringify({ status: 'ok', simulations }));
411
437
  } catch (err) {
412
438
  res.writeHead(500, { 'Content-Type': 'application/json' });
413
439
  res.end(JSON.stringify({ error: err.message }));
@@ -476,8 +502,7 @@ function readRequestBody(req) {
476
502
  * @param {number} [opts.port] - Dev server port (default: 3000)
477
503
  * @param {string} [opts.name] - App name override
478
504
  * @param {string} [opts.sandboxUrl] - Existing sandbox server URL (skips creating one)
479
- * @param {boolean} [opts.frameworkMode] - If true, hide server URL UI and show mode toggles
480
- * @param {boolean} [opts.defaultProdTools] - Initial prod tools state
505
+ * @param {boolean} [opts.frameworkMode] - If true, show framework-only controls (Prod Resources)
481
506
  * @param {boolean} [opts.defaultProdResources] - Initial prod resources state
482
507
  * @param {string} [opts.projectRoot] - Project directory for serving /dist/ files (prod resources)
483
508
  * @param {boolean} [opts.noBegging] - Suppress star message
@@ -493,7 +518,6 @@ export async function inspectServer(opts) {
493
518
  name: nameOverride,
494
519
  sandboxUrl: existingSandboxUrl,
495
520
  frameworkMode = false,
496
- defaultProdTools = false,
497
521
  defaultProdResources = false,
498
522
  projectRoot = null,
499
523
  noBegging = false,
@@ -552,6 +576,7 @@ export async function inspectServer(opts) {
552
576
  mergeSimulationFixtures(simulationsDir, simulations);
553
577
  }
554
578
 
579
+
555
580
  // Start or reuse sandbox server
556
581
  let sandbox;
557
582
  let ownsSandbox = false;
@@ -590,9 +615,7 @@ export async function inspectServer(opts) {
590
615
  </body>
591
616
  </html>`;
592
617
 
593
- // In framework mode, don't pass serverUrl to the Simulator (hides the server
594
- // URL input in the sidebar, enables prod-tools/prod-resources toggles).
595
- const simulatorServerUrl = frameworkMode ? null : serverArg;
618
+ const simulatorServerUrl = serverArg;
596
619
 
597
620
  // Create the Vite server.
598
621
  // Use the sunpeak package dir as root to avoid scanning the user's project
@@ -608,11 +631,13 @@ export async function inspectServer(opts) {
608
631
  serverAppName,
609
632
  serverAppIcon,
610
633
  sandbox.url,
611
- { defaultProdTools, defaultProdResources }
634
+ { defaultProdResources, hideSimulatorModes: !frameworkMode }
635
+ ),
636
+ sunpeakInspectEndpointsPlugin(
637
+ () => mcpConnection.client,
638
+ (newClient) => { mcpConnection.client = newClient; },
639
+ { callToolDirect: opts.callToolDirect, simulationsDir }
612
640
  ),
613
- sunpeakInspectEndpointsPlugin(() => mcpConnection.client, {
614
- callToolDirect: opts.callToolDirect,
615
- }),
616
641
  // Serve /dist/{name}/{name}.html from the project directory (for Prod Resources mode).
617
642
  // The Simulator polls these paths via HEAD to check if built resources exist.
618
643
  // Only intercepts .html files under /dist/ — other /dist/ paths (like sunpeak's
@@ -80,6 +80,7 @@
80
80
  --color-black: #000;
81
81
  --color-white: #fff;
82
82
  --spacing: .25rem;
83
+ --container-xs: 20rem;
83
84
  --text-xs: .75rem;
84
85
  --text-xs--line-height: calc(1 / .75);
85
86
  --text-sm: .875rem;
@@ -901,6 +902,10 @@
901
902
  max-width: 100%;
902
903
  }
903
904
 
905
+ .max-w-xs {
906
+ max-width: var(--container-xs);
907
+ }
908
+
904
909
  .min-w-0 {
905
910
  min-width: calc(var(--spacing) * 0);
906
911
  }
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../chunk-9hOWP6kD.cjs");
3
3
  require("../protocol-jbxhzcnS.cjs");
4
- const require_simulator = require("../simulator-CH9hs0N6.cjs");
5
- const require_simulator_url = require("../simulator-url-CozKF1jf.cjs");
4
+ const require_simulator = require("../simulator-DqWETA_1.cjs");
5
+ const require_simulator_url = require("../simulator-url-3ATCsPOT.cjs");
6
6
  const require_discovery = require("../discovery-Clu4uHp1.cjs");
7
7
  //#region src/chatgpt/index.ts
8
8
  var chatgpt_exports = /* @__PURE__ */ require_chunk.__exportAll({
@@ -1,7 +1,7 @@
1
1
  import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
2
2
  import "../protocol-DJmRaBzO.js";
3
- import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Simulator, v as SCREEN_WIDTHS } from "../simulator-Dl8B-Ljb.js";
4
- import { t as createSimulatorUrl } from "../simulator-url-KoS_ToP6.js";
3
+ import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Simulator, v as SCREEN_WIDTHS } from "../simulator-BijjlOXb.js";
4
+ import { t as createSimulatorUrl } from "../simulator-url-BbuuWa7S.js";
5
5
  import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-Cgoegt62.js";
6
6
  //#region src/chatgpt/index.ts
7
7
  var chatgpt_exports = /* @__PURE__ */ __exportAll({
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../chunk-9hOWP6kD.cjs");
3
3
  require("../protocol-jbxhzcnS.cjs");
4
- const require_simulator = require("../simulator-CH9hs0N6.cjs");
4
+ const require_simulator = require("../simulator-DqWETA_1.cjs");
5
5
  exports.Simulator = require_simulator.Simulator;
@@ -1,3 +1,3 @@
1
1
  import "../protocol-DJmRaBzO.js";
2
- import { t as Simulator } from "../simulator-Dl8B-Ljb.js";
2
+ import { t as Simulator } from "../simulator-BijjlOXb.js";
3
3
  export { Simulator };
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-9hOWP6kD.cjs");
3
3
  const require_protocol = require("./protocol-jbxhzcnS.cjs");
4
4
  const require_use_app = require("./use-app-D2h-aiyr.cjs");
5
- const require_simulator = require("./simulator-CH9hs0N6.cjs");
5
+ const require_simulator = require("./simulator-DqWETA_1.cjs");
6
6
  const require_host_index = require("./host/index.cjs");
7
7
  const require_simulator_index = require("./simulator/index.cjs");
8
8
  const require_chatgpt_index = require("./chatgpt/index.cjs");
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $ as literal, L as RequestIdSchema, Q as boolean, R as ResourceLinkSchema, U as ToolSchema, X as _undefined, Z as array, _ as ImplementationSchema, a as CallToolResultSchema, at as unknown, et as number, it as union, nt as record, p as EmbeddedResourceSchema, rt as string, s as ContentBlockSchema, tt as object } from "./protocol-DJmRaBzO.js";
2
2
  import { $ as w, A as UX, B as g, C as PQ, D as T, E as S, F as _Q, G as m, H as jQ, I as a, J as p, K as n, L as b, M as W, N as WQ, O as TQ, P as _, Q as t, R as d, S as P, T as RX, U as k, V as h, W as l, X as r, Y as q, Z as s, _ as K, a as B, b as NQ, c as CQ, d as FQ, et as wQ, f as G, g as J, h as IQ, i as AQ, j as V, k as U, l as EQ, m as I, n as AppProvider, nt as z, o as BQ, p as GQ, q as o, r as A, rt as zQ, s as C, t as useApp, tt as x, u as F, v as L, w as R, x as O, y as LQ, z as e } from "./use-app-X7JbGskk.js";
3
- import { S as DEFAULT_STYLE_VARIABLES } from "./simulator-Dl8B-Ljb.js";
3
+ import { S as DEFAULT_STYLE_VARIABLES } from "./simulator-BijjlOXb.js";
4
4
  import { detectHost, detectPlatform, isChatGPT, isClaude } from "./host/index.js";
5
5
  import { t as simulator_exports } from "./simulator/index.js";
6
6
  import { t as chatgpt_exports } from "./chatgpt/index.js";
@@ -9192,7 +9192,7 @@ function createAppServer(config, simulations, viteMode) {
9192
9192
  const argsStr = argKeys.length > 0 ? `{${argKeys.join(", ")}}` : "{}";
9193
9193
  const hasMockResult = toolResult?.structuredContent != null;
9194
9194
  const realHandler = simulation.handler;
9195
- if (realHandler && !hasMockResult) {
9195
+ if (realHandler && (config.prodTools || !hasMockResult)) {
9196
9196
  console.log(`[MCP] CallTool: ${tool.name}${argsStr} → live handler`);
9197
9197
  try {
9198
9198
  const result = await realHandler(args, extra);