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