sunpeak 0.10.6 → 0.10.7

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 (33) hide show
  1. package/bin/commands/mcp.mjs +213 -46
  2. package/dist/chatgpt/index.cjs +1 -1
  3. package/dist/chatgpt/index.js +1 -1
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/mcp/entry.cjs +2 -1
  7. package/dist/mcp/entry.cjs.map +1 -1
  8. package/dist/mcp/entry.js +2 -1
  9. package/dist/mcp/entry.js.map +1 -1
  10. package/dist/mcp/index.cjs +1 -1
  11. package/dist/mcp/index.js +1 -1
  12. package/dist/mcp/types.d.ts +7 -0
  13. package/dist/{server-CnRhUNGQ.js → server-BLKltt88.js} +124 -28
  14. package/dist/{server-CnRhUNGQ.js.map → server-BLKltt88.js.map} +1 -1
  15. package/dist/{server-B-T6Y3-J.cjs → server-D_oRdZjX.cjs} +124 -28
  16. package/dist/{server-B-T6Y3-J.cjs.map → server-D_oRdZjX.cjs.map} +1 -1
  17. package/dist/{simulator-url-pSDp_VWO.cjs → simulator-url-B6DZi3vV.cjs} +25 -14
  18. package/dist/simulator-url-B6DZi3vV.cjs.map +1 -0
  19. package/dist/{simulator-url-BUKX-wRa.js → simulator-url-izFV6mji.js} +24 -13
  20. package/dist/simulator-url-izFV6mji.js.map +1 -0
  21. package/package.json +1 -1
  22. package/template/dist/albums/albums.js +4 -4
  23. package/template/dist/albums/albums.json +1 -1
  24. package/template/dist/carousel/carousel.js +3 -3
  25. package/template/dist/carousel/carousel.json +1 -1
  26. package/template/dist/map/map.js +8 -8
  27. package/template/dist/map/map.json +1 -1
  28. package/template/dist/review/review.js +3 -3
  29. package/template/dist/review/review.json +1 -1
  30. package/template/node_modules/.vite/deps/_metadata.json +22 -22
  31. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  32. package/dist/simulator-url-BUKX-wRa.js.map +0 -1
  33. package/dist/simulator-url-pSDp_VWO.cjs.map +0 -1
@@ -4821,7 +4821,7 @@ union([
4821
4821
  ListTasksResultSchema,
4822
4822
  CreateTaskResultSchema
4823
4823
  ]);
4824
- function readResourceHtml(distPath) {
4824
+ function readResourceHtmlProd(distPath) {
4825
4825
  const htmlPath = path.resolve(distPath);
4826
4826
  if (!fs.existsSync(htmlPath)) {
4827
4827
  throw new Error(
@@ -4843,12 +4843,76 @@ ${jsContents}
4843
4843
  </body>
4844
4844
  </html>`;
4845
4845
  }
4846
- function createAppServer(config2) {
4847
- const { name = "sunpeak-app", version: version2 = "0.1.0", simulations } = config2;
4846
+ function getViteResourceHtml(srcPath) {
4847
+ const fileName = srcPath.split("/").pop()?.replace(/-resource\.tsx$/, "") ?? "";
4848
+ const componentName = fileName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("") + "Resource";
4849
+ const devServerUrl = "http://localhost:6766";
4850
+ const entryParams = new URLSearchParams({ src: srcPath, component: componentName });
4851
+ const virtualModuleUrl = `${devServerUrl}/@id/virtual:sunpeak-entry?${entryParams.toString()}`;
4852
+ return `<!DOCTYPE html>
4853
+ <html>
4854
+ <head>
4855
+ <meta charset="UTF-8">
4856
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4857
+ </head>
4858
+ <body>
4859
+ <script type="module">
4860
+ import { injectIntoGlobalHook } from "${devServerUrl}/@react-refresh";
4861
+ injectIntoGlobalHook(window);
4862
+ window.$RefreshReg$ = () => {};
4863
+ window.$RefreshSig$ = () => (type) => type;
4864
+ window.__vite_plugin_react_preamble_installed__ = true;
4865
+ <\/script>
4866
+ <script type="module" src="${devServerUrl}/@vite/client"><\/script>
4867
+ <script type="module">
4868
+ // Local network access check (matching skybridge)
4869
+ (async () => {
4870
+ if (!navigator.permissions?.query) return;
4871
+ const protocol = window.location.protocol;
4872
+ if (protocol !== 'http:' && protocol !== 'https:') return;
4873
+ const host = window.location.hostname;
4874
+ const isLoopback = host === 'localhost' || /^127\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.test(host) || host === '::1';
4875
+ if (isLoopback) return;
4876
+ try {
4877
+ const status = await navigator.permissions.query({ name: "local-network-access" });
4878
+ if (status.state === "denied") {
4879
+ document.getElementById('root').innerHTML = '<div style="background:#fef2f2;border:2px solid #ef4444;border-radius:8px;padding:16px;text-align:center;font-family:system-ui,sans-serif;"><div style="color:#ef4444;font-size:18px;font-weight:600;margin-bottom:8px;">Local network access permission is denied</div><div style="color:#ef4444;font-size:14px;">Please enable it in your browser settings. <a href="https://developer.chrome.com/blog/local-network-access" target="_blank" style="color:#ef4444;text-decoration:underline;">Learn more</a></div></div>';
4880
+ }
4881
+ } catch (e) {}
4882
+ })();
4883
+ <\/script>
4884
+ <div id="root"></div>
4885
+ <script type="module" src="${virtualModuleUrl}"><\/script>
4886
+ </body>
4887
+ </html>`;
4888
+ }
4889
+ function getResourceHtml(simulation, viteMode) {
4890
+ if (viteMode && simulation.srcPath) {
4891
+ return getViteResourceHtml(simulation.srcPath);
4892
+ }
4893
+ return readResourceHtmlProd(simulation.distPath);
4894
+ }
4895
+ const DEV_SERVER_URL = "http://localhost:6766";
4896
+ const HMR_WS_URL = "ws://localhost:24678";
4897
+ function injectViteCSP(existingMeta) {
4898
+ const meta = existingMeta ?? {};
4899
+ const widgetCSP = meta["openai/widgetCSP"] ?? {};
4900
+ const existingResourceDomains = widgetCSP["resource_domains"] ?? [];
4901
+ const resourceDomains = existingResourceDomains.includes(DEV_SERVER_URL) ? existingResourceDomains : [...existingResourceDomains, DEV_SERVER_URL];
4902
+ const existingConnectDomains = widgetCSP["connect_domains"] ?? [];
4903
+ const connectDomains = existingConnectDomains.includes(HMR_WS_URL) ? existingConnectDomains : [...existingConnectDomains, HMR_WS_URL];
4904
+ return {
4905
+ ...meta,
4906
+ "openai/widgetCSP": {
4907
+ ...widgetCSP,
4908
+ resource_domains: resourceDomains,
4909
+ connect_domains: connectDomains
4910
+ }
4911
+ };
4912
+ }
4913
+ function createAppServer(config2, simulations, viteMode) {
4914
+ const { name = "sunpeak-app", version: version2 = "0.1.0" } = config2;
4848
4915
  const toolInputParser = zod.z.object({});
4849
- const resourceContentMap = new Map(
4850
- simulations.map((simulation) => [simulation.tool.name, readResourceHtml(simulation.distPath)])
4851
- );
4852
4916
  const devTimestamp = Date.now().toString(36);
4853
4917
  const resources = simulations.map((simulation) => {
4854
4918
  const resource = simulation.resource;
@@ -4872,11 +4936,13 @@ function createAppServer(config2) {
4872
4936
  simulation.callToolResult ?? { structuredContent: null, _meta: {} }
4873
4937
  ])
4874
4938
  );
4875
- const resourceMap = new Map(
4939
+ const uriToSimulation = new Map(
4940
+ resources.map((resource, index) => [resource.uri, simulations[index]])
4941
+ );
4942
+ const resourceMetaMap = new Map(
4876
4943
  resources.map((resource, index) => [
4877
4944
  resource.uri,
4878
4945
  {
4879
- content: resourceContentMap.get(simulations[index].tool.name),
4880
4946
  resource,
4881
4947
  _meta: simulations[index].resource._meta
4882
4948
  }
@@ -4895,24 +4961,35 @@ function createAppServer(config2) {
4895
4961
  }
4896
4962
  );
4897
4963
  server.setRequestHandler(ListResourcesRequestSchema, async (_request) => {
4898
- console.log(`[MCP] ListResources → ${resources.length} resource(s)`);
4964
+ console.log(
4965
+ `[MCP] ListResources → ${resources.length} resource(s)${viteMode ? " (vite mode)" : ""}`
4966
+ );
4967
+ if (viteMode) {
4968
+ const resourcesWithCsp = resources.map((resource) => ({
4969
+ ...resource,
4970
+ _meta: injectViteCSP(resource._meta)
4971
+ }));
4972
+ return { resources: resourcesWithCsp };
4973
+ }
4899
4974
  return { resources };
4900
4975
  });
4901
4976
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
4902
4977
  const requestedUri = request.params.uri;
4903
- const resourceData = resourceMap.get(requestedUri);
4904
- if (!resourceData) {
4978
+ const simulation = uriToSimulation.get(requestedUri);
4979
+ const meta = resourceMetaMap.get(requestedUri);
4980
+ if (!simulation || !meta) {
4905
4981
  throw new Error(`Unknown resource: ${requestedUri}`);
4906
4982
  }
4907
- const sizeKB = (resourceData.content.length / 1024).toFixed(1);
4908
- console.log(`[MCP] ReadResource: ${requestedUri} ${sizeKB}KB`);
4983
+ const content = getResourceHtml(simulation, viteMode);
4984
+ const sizeKB = (content.length / 1024).toFixed(1);
4985
+ console.log(`[MCP] ReadResource: ${requestedUri} → ${sizeKB}KB${viteMode ? " (vite)" : ""}`);
4909
4986
  return {
4910
4987
  contents: [
4911
4988
  {
4912
- uri: resourceData.resource.uri,
4913
- mimeType: resourceData.resource.mimeType,
4914
- text: resourceData.content,
4915
- _meta: resourceData._meta
4989
+ uri: meta.resource.uri,
4990
+ mimeType: meta.resource.mimeType,
4991
+ text: content,
4992
+ _meta: viteMode ? injectViteCSP(meta._meta) : meta._meta
4916
4993
  }
4917
4994
  ]
4918
4995
  };
@@ -4951,9 +5028,9 @@ function createAppServer(config2) {
4951
5028
  const sessions = /* @__PURE__ */ new Map();
4952
5029
  const ssePath = "/mcp";
4953
5030
  const postPath = "/mcp/messages";
4954
- async function handleSseRequest(res, config2) {
5031
+ async function handleSseRequest(res, config2, simulations, viteMode) {
4955
5032
  res.setHeader("Access-Control-Allow-Origin", "*");
4956
- const server = createAppServer(config2);
5033
+ const server = createAppServer(config2, simulations, viteMode);
4957
5034
  const transport = new sse_js.SSEServerTransport(postPath, res);
4958
5035
  const sessionId = transport.sessionId;
4959
5036
  sessions.set(sessionId, { server, transport });
@@ -4979,7 +5056,7 @@ async function handleSseRequest(res, config2) {
4979
5056
  }
4980
5057
  async function handlePostMessage(req, res, url) {
4981
5058
  res.setHeader("Access-Control-Allow-Origin", "*");
4982
- res.setHeader("Access-Control-Allow-Headers", "content-type");
5059
+ res.setHeader("Access-Control-Allow-Headers", "content-type, ngrok-skip-browser-warning");
4983
5060
  const sessionId = url.searchParams.get("sessionId");
4984
5061
  if (!sessionId) {
4985
5062
  res.writeHead(400).end("Missing sessionId query parameter");
@@ -5002,32 +5079,48 @@ async function handlePostMessage(req, res, url) {
5002
5079
  function runMCPServer(config2) {
5003
5080
  const portEnv = Number(process.env.PORT ?? 6766);
5004
5081
  const port = config2.port ?? (Number.isFinite(portEnv) ? portEnv : 6766);
5082
+ const { simulations } = config2;
5083
+ const viteServer = config2.viteServer;
5084
+ const viteMode = !!viteServer;
5005
5085
  const httpServer = node_http.createServer(async (req, res) => {
5006
5086
  if (!req.url) {
5007
5087
  res.writeHead(400).end("Missing URL");
5008
5088
  return;
5009
5089
  }
5010
5090
  const url = new node_url.URL(req.url, `http://${req.headers.host ?? "localhost"}`);
5011
- console.log(`[HTTP] ${req.method} ${url.pathname}`);
5012
- if (req.method === "OPTIONS" && (url.pathname === ssePath || url.pathname === postPath)) {
5091
+ if (req.method === "OPTIONS") {
5013
5092
  res.writeHead(204, {
5014
5093
  "Access-Control-Allow-Origin": "*",
5015
5094
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
5016
- "Access-Control-Allow-Headers": "content-type"
5095
+ "Access-Control-Allow-Headers": "content-type, ngrok-skip-browser-warning"
5017
5096
  });
5018
5097
  res.end();
5019
5098
  return;
5020
5099
  }
5021
5100
  if (req.method === "GET" && url.pathname === ssePath) {
5022
- await handleSseRequest(res, config2);
5101
+ console.log(`[HTTP] ${req.method} ${url.pathname}`);
5102
+ await handleSseRequest(res, config2, simulations, viteMode);
5023
5103
  return;
5024
5104
  }
5025
5105
  if (req.method === "POST" && url.pathname === postPath) {
5106
+ console.log(`[HTTP] ${req.method} ${url.pathname}`);
5026
5107
  await handlePostMessage(req, res, url);
5027
5108
  return;
5028
5109
  }
5110
+ if (viteServer) {
5111
+ res.setHeader("Access-Control-Allow-Origin", "*");
5112
+ res.setHeader("Access-Control-Allow-Headers", "content-type, ngrok-skip-browser-warning");
5113
+ viteServer.middlewares(req, res);
5114
+ return;
5115
+ }
5116
+ console.log(`[HTTP] ${req.method} ${url.pathname} → 404`);
5029
5117
  res.writeHead(404).end("Not Found");
5030
5118
  });
5119
+ if (viteServer) {
5120
+ httpServer.on("upgrade", (request, socket, head) => {
5121
+ viteServer.ws.handleUpgrade(request, socket, head);
5122
+ });
5123
+ }
5031
5124
  httpServer.on("clientError", (err, socket) => {
5032
5125
  console.error("HTTP client error", err);
5033
5126
  socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
@@ -5036,8 +5129,11 @@ function runMCPServer(config2) {
5036
5129
  console.log(`Sunpeak MCP server listening on http://localhost:${port}`);
5037
5130
  console.log(` SSE stream: GET http://localhost:${port}${ssePath}`);
5038
5131
  console.log(` Message post endpoint: POST http://localhost:${port}${postPath}?sessionId=...`);
5132
+ if (viteMode) {
5133
+ console.log(` Vite HMR: enabled (source files served with hot reload)`);
5134
+ }
5039
5135
  });
5040
- const shutdown = () => {
5136
+ const shutdown = async () => {
5041
5137
  console.log("\nShutting down MCP server...");
5042
5138
  httpServer.close(() => {
5043
5139
  console.log("MCP server closed");
@@ -5048,8 +5144,8 @@ function runMCPServer(config2) {
5048
5144
  process.exit(1);
5049
5145
  }, 5e3);
5050
5146
  };
5051
- process.on("SIGTERM", shutdown);
5052
- process.on("SIGINT", shutdown);
5147
+ process.on("SIGTERM", () => void shutdown());
5148
+ process.on("SIGINT", () => void shutdown());
5053
5149
  }
5054
5150
  exports.runMCPServer = runMCPServer;
5055
- //# sourceMappingURL=server-B-T6Y3-J.cjs.map
5151
+ //# sourceMappingURL=server-D_oRdZjX.cjs.map