sunpeak 0.10.7 → 0.11.1

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 (103) hide show
  1. package/README.md +44 -19
  2. package/bin/commands/dev.mjs +173 -12
  3. package/bin/sunpeak.js +3 -11
  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 +1 -1
  9. package/dist/mcp/entry.js +1 -1
  10. package/dist/mcp/favicon.d.ts +2 -0
  11. package/dist/mcp/index.cjs +3 -1
  12. package/dist/mcp/index.cjs.map +1 -1
  13. package/dist/mcp/index.d.ts +1 -0
  14. package/dist/mcp/index.js +3 -1
  15. package/dist/{server-BLKltt88.js → server-BI9Y531R.js} +31 -3
  16. package/dist/{server-BLKltt88.js.map → server-BI9Y531R.js.map} +1 -1
  17. package/dist/{server-D_oRdZjX.cjs → server-CcLDAGBE.cjs} +31 -3
  18. package/dist/{server-D_oRdZjX.cjs.map → server-CcLDAGBE.cjs.map} +1 -1
  19. package/dist/{simulator-url-B6DZi3vV.cjs → simulator-url-CYMOGoB1.cjs} +5 -5
  20. package/dist/{simulator-url-B6DZi3vV.cjs.map → simulator-url-CYMOGoB1.cjs.map} +1 -1
  21. package/dist/{simulator-url-izFV6mji.js → simulator-url-DG79-dU3.js} +4 -4
  22. package/dist/{simulator-url-izFV6mji.js.map → simulator-url-DG79-dU3.js.map} +1 -1
  23. package/package.json +1 -1
  24. package/template/README.md +6 -7
  25. package/template/_gitignore +4 -0
  26. package/template/dist/albums/albums.json +1 -1
  27. package/template/dist/carousel/carousel.json +1 -1
  28. package/template/dist/map/map.json +1 -1
  29. package/template/dist/review/review.json +1 -1
  30. package/template/index.html +0 -1
  31. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +7 -7
  32. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +1 -1
  33. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +7 -7
  34. package/template/node_modules/.vite/deps/_metadata.json +33 -33
  35. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  36. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Avatar.js +96 -0
  37. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Avatar.js.map +7 -0
  38. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Button.js +625 -0
  39. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Button.js.map +7 -0
  40. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Checkbox.js +33 -0
  41. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Checkbox.js.map +7 -0
  42. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Icon.js +1498 -0
  43. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Icon.js.map +7 -0
  44. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Input.js +13 -0
  45. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Input.js.map +7 -0
  46. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_SegmentedControl.js +103 -0
  47. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_SegmentedControl.js.map +7 -0
  48. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Select.js +3680 -0
  49. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Select.js.map +7 -0
  50. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Textarea.js +95 -0
  51. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Textarea.js.map +7 -0
  52. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_theme.js +45 -0
  53. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_theme.js.map +7 -0
  54. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-2UDYPUBJ.js +15201 -0
  55. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-2UDYPUBJ.js.map +7 -0
  56. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-6QVG4F2X.js +93 -0
  57. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-6QVG4F2X.js.map +7 -0
  58. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-BUOVMFCD.js +1004 -0
  59. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-BUOVMFCD.js.map +7 -0
  60. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-CNYJBM5F.js +21 -0
  61. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-CNYJBM5F.js.map +7 -0
  62. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-EGRHWZRV.js +1 -0
  63. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-EGRHWZRV.js.map +7 -0
  64. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-ILHRZGIS.js +46 -0
  65. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-ILHRZGIS.js.map +7 -0
  66. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JAGHY6H6.js +231 -0
  67. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JAGHY6H6.js.map +7 -0
  68. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JGVISENQ.js +292 -0
  69. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JGVISENQ.js.map +7 -0
  70. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-P5LK4A7U.js +112 -0
  71. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-P5LK4A7U.js.map +7 -0
  72. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-QPJAV452.js +13 -0
  73. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-QPJAV452.js.map +7 -0
  74. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-RYYR2YMB.js +111 -0
  75. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-RYYR2YMB.js.map +7 -0
  76. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-UM3ZGDFR.js +4480 -0
  77. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-UM3ZGDFR.js.map +7 -0
  78. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-XZTIOEPG.js +280 -0
  79. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-XZTIOEPG.js.map +7 -0
  80. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/clsx.js +10 -0
  81. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/clsx.js.map +7 -0
  82. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-react.js +1712 -0
  83. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-react.js.map +7 -0
  84. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-wheel-gestures.js +589 -0
  85. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-wheel-gestures.js.map +7 -0
  86. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/mapbox-gl.js +32835 -0
  87. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/mapbox-gl.js.map +7 -0
  88. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/package.json +3 -0
  89. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom.js +7 -0
  90. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom.js.map +7 -0
  91. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom_client.js +20217 -0
  92. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom_client.js.map +7 -0
  93. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react.js +6 -0
  94. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react.js.map +7 -0
  95. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-dev-runtime.js +278 -0
  96. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-dev-runtime.js.map +7 -0
  97. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-runtime.js +7 -0
  98. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-runtime.js.map +7 -0
  99. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/tailwind-merge.js +3095 -0
  100. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/tailwind-merge.js.map +7 -0
  101. package/template/package.json +0 -1
  102. package/bin/commands/mcp.mjs +0 -244
  103. package/template/public/favicon.ico +0 -0
package/README.md CHANGED
@@ -17,13 +17,14 @@
17
17
 
18
18
  The ChatGPT App framework.
19
19
 
20
- Quickstart, build, test, and ship your ChatGPT App locally!
20
+ Quickstart, build, test, and ship your ChatGPT Applocally!
21
21
 
22
22
  [Demo (Hosted)](https://sunpeak.ai/#simulator) ~
23
23
  [Demo (Video)](https://d10djik02wlf6x.cloudfront.net/sunpeak-demo-prod.mp4) ~
24
24
  [Discord (NEW)](https://discord.gg/FB2QNXqRnw) ~
25
25
  [Documentation](https://docs.sunpeak.ai/) ~
26
- [GitHub](https://github.com/Sunpeak-AI/sunpeak)
26
+ [GitHub](https://github.com/Sunpeak-AI/sunpeak) ~
27
+ [Resource Repository](https://app.sunpeak.ai/)
27
28
 
28
29
  <div align="center">
29
30
  <a href="https://docs.sunpeak.ai/library/chatgpt-simulator">
@@ -35,8 +36,6 @@ Quickstart, build, test, and ship your ChatGPT App locally!
35
36
 
36
37
  ## Quickstart
37
38
 
38
- ### New Projects
39
-
40
39
  Requirements: Node (20+), pnpm (10+)
41
40
 
42
41
  ```bash
@@ -48,24 +47,50 @@ To add sunpeak to an existing project, refer to the [documentation](https://docs
48
47
 
49
48
  ## Overview
50
49
 
51
- sunpeak is an npm package consisting of:
50
+ sunpeak is an npm package that helps you build ChatGPT Apps (MCP Resources) while keeping your MCP server client-agnostic. sunpeak consists of:
51
+
52
+ ### The `sunpeak` library (`./src`)
53
+
54
+ 1. Runtime APIs: Strongly typed APIs for interacting with the ChatGPT runtime, **architected to support future platforms** (Gemini, Claude, etc.).
55
+ 2. ChatGPT simulator: React component replicating ChatGPT's runtime to **test Apps locally and automatically**.
56
+ 3. MCP server: Serve Resources with mock data to the real ChatGPT with HMR (**no more cache issues or 5-click manual refreshes**).
57
+
58
+ ### The `sunpeak` framework (`./template`)
59
+
60
+ Next.js for ChatGPT Apps. This templated npm package includes:
61
+
62
+ ```bash
63
+ my-app/
64
+ ├── src/
65
+ │ └── resources/
66
+ │ └── review/ # My-app's Review UI.
67
+ │ ├── review-resource.tsx # Review UI component.
68
+ │ ├── review-resource.json # Review UI MCP metadata.
69
+ │ └── review-{scenario}-simulation.json # Mock state for testing.
70
+ └── package.json
71
+ ```
72
+
73
+ 1. Project scaffold: Complete development setup with the sunpeak library.
74
+ 2. UI components: Production-ready components following ChatGPT design guidelines and using OpenAI apps-sdk-ui React components.
75
+ 3. Convention over configuration: Create UIs (resources) by simply creating a `src/resources/NAME/NAME-resource.tsx` React file and `src/resources/NAME/NAME-resource.json` metadata file.
52
76
 
53
- 1. **The `sunpeak` library** (`./src`). An npm package for running & testing ChatGPT Apps. This standalone library contains:
54
- 1. Runtime APIs - Strongly typed, multi-platform APIs for interacting with the ChatGPT runtime, architected to support future platforms (Gemini, Claude).
55
- 2. ChatGPT simulator - React component replicating ChatGPT's runtime.
56
- 3. MCP server - Mock data MCP server for testing local UIs (resources) in the real ChatGPT.
57
- 2. **The `sunpeak` framework** (`./template`). Next.js for ChatGPT Apps. This templated npm package includes:
58
- 1. Project scaffold - Complete development setup with build, test, and mcp tooling, including the sunpeak library.
59
- 2. UI components - Production-ready components following ChatGPT design guidelines and using OpenAI apps-sdk-ui React components.
60
- 3. Convention over configuration - Create UIs (resources) by simply creating a `src/resources/NAME/NAME-resource.tsx` React file and `src/resources/NAME/NAME-resource.json` metadata file.
61
- 3. **The `sunpeak` CLI** (`./bin`). Commands for managing ChatGPT Apps. Includes a client for the [sunpeak Resource Repository](https://app.sunpeak.ai/) (ECR for ChatGPT Apps). The repository helps you & your CI/CD decouple your App from your client-agnostic MCP server:
62
- 1. Tag your app builds with version numbers and environment names (like `v1.0.0` and `prod`)
63
- 2. `push` built Apps to a central location
64
- 3. `pull` built Apps to be run in different environments
77
+ ### The `sunpeak` CLI (`./bin`)
78
+
79
+ Commands for managing ChatGPT Apps. Includes a client for the [sunpeak Resource Repository](https://app.sunpeak.ai/). The repository helps you & your CI/CD decouple your App from your client-agnostic MCP server while also providing a hosted runtime to collaborate, demo, and share your ChatGPT Apps:
80
+
81
+ <div align="center">
82
+ <a href="https://docs.sunpeak.ai/library/chatgpt-simulator">
83
+ <picture>
84
+ <img alt="ChatGPT Resource Repository" src="https://d10djik02wlf6x.cloudfront.net/blog/storybook-for-chatgpt-apps.png">
85
+ </picture>
86
+ </a>
87
+ </div>
65
88
 
66
- Note that each `sunpeak` component can be used in isolation if preferred, though the most seamless experience combines all 3.
89
+ 1. Tag your app builds with version numbers and environment names (like `v1.0.0` and `prod`)
90
+ 2. `push` built Apps to a central location
91
+ 3. `pull` built Apps to be run in different environments
67
92
 
68
- ## Example Component
93
+ ## Example Resource Component
69
94
 
70
95
  ```tsx
71
96
  import { Card } from './components';
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync } from 'fs';
3
- import { join, resolve, basename, dirname } from 'path';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ const { existsSync, readFileSync } = fs;
5
+ const { join, resolve, basename, dirname } = path;
4
6
  import { createRequire } from 'module';
5
7
  import { pathToFileURL } from 'url';
6
8
 
@@ -81,16 +83,51 @@ export async function dev(projectRoot = process.cwd(), args = []) {
81
83
  port = parseInt(args[portArgIndex + 1]);
82
84
  }
83
85
 
86
+ // Parse --no-begging flag
87
+ const noBegging = args.includes('--no-begging');
88
+
84
89
  console.log(`Starting Vite dev server on port ${port}...`);
85
90
 
86
91
  // Check if we're in the sunpeak workspace (directory is named "template")
87
92
  const isTemplate = basename(projectRoot) === 'template';
88
93
  const parentSrc = resolve(projectRoot, '../src');
89
94
 
95
+ // Import sunpeak modules (MCP server and discovery utilities)
96
+ let sunpeakMcp, sunpeak;
97
+ if (isTemplate) {
98
+ // In workspace dev mode, import from local dist folder
99
+ sunpeakMcp = await import(pathToFileURL(resolve(projectRoot, '../dist/mcp/index.js')).href);
100
+ sunpeak = await import(pathToFileURL(resolve(projectRoot, '../dist/index.js')).href);
101
+ } else {
102
+ // Import from installed sunpeak package
103
+ const sunpeakBase = require.resolve('sunpeak').replace(/dist\/index\.(c)?js$/, '');
104
+ sunpeakMcp = await import(pathToFileURL(join(sunpeakBase, 'dist/mcp/index.js')).href);
105
+ sunpeak = await import(pathToFileURL(join(sunpeakBase, 'dist/index.js')).href);
106
+ }
107
+ const { FAVICON_BUFFER: faviconBuffer, runMCPServer } = sunpeakMcp;
108
+ const { findResourceDirs, findSimulationFiles } = sunpeak;
109
+
110
+ // Vite plugin to serve the sunpeak favicon
111
+ const sunpeakFaviconPlugin = () => ({
112
+ name: 'sunpeak-favicon',
113
+ configureServer(server) {
114
+ server.middlewares.use((req, res, next) => {
115
+ if (req.url === '/favicon.ico') {
116
+ res.setHeader('Content-Type', 'image/png');
117
+ res.setHeader('Content-Length', faviconBuffer.length);
118
+ res.setHeader('Cache-Control', 'public, max-age=86400');
119
+ res.end(faviconBuffer);
120
+ return;
121
+ }
122
+ next();
123
+ });
124
+ },
125
+ });
126
+
90
127
  // Create and start Vite dev server programmatically
91
128
  const server = await createServer({
92
129
  root: projectRoot,
93
- plugins: [react(), tailwindcss()],
130
+ plugins: [react(), tailwindcss(), sunpeakFaviconPlugin()],
94
131
  resolve: {
95
132
  alias: {
96
133
  // In workspace dev mode, use local sunpeak source
@@ -109,16 +146,140 @@ export async function dev(projectRoot = process.cwd(), args = []) {
109
146
  server.printUrls();
110
147
  server.bindCLIShortcuts({ print: true });
111
148
 
112
- // Handle signals
113
- process.on('SIGINT', async () => {
114
- await server.close();
115
- process.exit(0);
116
- });
149
+ // Print star-begging message unless --no-begging is set
150
+ if (!noBegging) {
151
+ // #FFB800 in 24-bit ANSI color
152
+ console.log('\n\n\x1b[38;2;255;184;0m\u2b50\ufe0f \u2192 \u2764\ufe0f https://github.com/Sunpeak-AI/sunpeak\x1b[0m\n');
153
+ }
117
154
 
118
- process.on('SIGTERM', async () => {
119
- await server.close();
120
- process.exit(0);
121
- });
155
+ // Discover simulations using sunpeak's discovery utilities
156
+ const resourcesDir = join(projectRoot, 'src/resources');
157
+ const resourceDirs = findResourceDirs(resourcesDir, (key) => `${key}-resource.json`, fs);
158
+
159
+ const simulations = [];
160
+ for (const { key: resourceKey, dir: resourceDir, resourcePath } of resourceDirs) {
161
+ const resource = JSON.parse(readFileSync(resourcePath, 'utf-8'));
162
+ const simulationFiles = findSimulationFiles(resourceDir, resourceKey, fs);
163
+
164
+ for (const { filename, path: simPath } of simulationFiles) {
165
+ const simulationKey = filename.replace(/-simulation\.json$/, '');
166
+ const simulation = JSON.parse(readFileSync(simPath, 'utf-8'));
167
+
168
+ simulations.push({
169
+ ...simulation,
170
+ name: simulationKey,
171
+ distPath: join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),
172
+ srcPath: `/src/resources/${resourceKey}/${resourceKey}-resource.tsx`,
173
+ resource,
174
+ });
175
+ }
176
+ }
177
+
178
+ // Start MCP server with its own Vite instance
179
+ if (simulations.length > 0) {
180
+ console.log(`\nStarting MCP server with ${simulations.length} simulation(s)...`);
181
+
182
+ // Virtual entry module plugin for MCP
183
+ const sunpeakEntryPlugin = () => ({
184
+ name: 'sunpeak-entry',
185
+ resolveId(id) {
186
+ if (id.startsWith('virtual:sunpeak-entry')) {
187
+ return id;
188
+ }
189
+ },
190
+ load(id) {
191
+ if (id.startsWith('virtual:sunpeak-entry')) {
192
+ const url = new URL(id.replace('virtual:sunpeak-entry', 'http://x'));
193
+ const srcPath = url.searchParams.get('src');
194
+ const componentName = url.searchParams.get('component');
195
+
196
+ if (!srcPath || !componentName) {
197
+ return 'console.error("Missing src or component param");';
198
+ }
199
+
200
+ return `
201
+ import { createElement } from 'react';
202
+ import { createRoot } from 'react-dom/client';
203
+ import * as ResourceModule from '${srcPath}';
204
+
205
+ const Component = ResourceModule.default || ResourceModule['${componentName}'];
206
+ if (!Component) {
207
+ document.getElementById('root').innerHTML = '<pre style="color:red;padding:16px">Component not found: ${componentName}\\nExports: ' + Object.keys(ResourceModule).join(', ') + '</pre>';
208
+ } else {
209
+ createRoot(document.getElementById('root')).render(createElement(Component));
210
+ }
211
+ `;
212
+ }
213
+ },
214
+ });
215
+
216
+ // Create Vite dev server in middleware mode for MCP
217
+ // Use separate cache directory to avoid conflicts with main dev server
218
+ const mcpViteServer = await createServer({
219
+ root: projectRoot,
220
+ cacheDir: 'node_modules/.vite-mcp',
221
+ plugins: [react(), tailwindcss(), sunpeakEntryPlugin()],
222
+ resolve: {
223
+ alias: {
224
+ ...(isTemplate && {
225
+ sunpeak: parentSrc,
226
+ }),
227
+ },
228
+ },
229
+ server: {
230
+ middlewareMode: true,
231
+ allowedHosts: true,
232
+ watch: {
233
+ // Only watch files that affect the UI bundle (not JSON, tests, etc.)
234
+ // MCP resources reload on next tool call, not on file change
235
+ ignored: (filePath) => {
236
+ if (!filePath.includes('.')) return false; // Watch directories
237
+ if (/\.(tsx?|css)$/.test(filePath)) {
238
+ return /\.(test|spec)\.tsx?$/.test(filePath); // Ignore tests
239
+ }
240
+ return true; // Ignore everything else
241
+ },
242
+ },
243
+ },
244
+ optimizeDeps: {
245
+ include: ['react', 'react-dom/client'],
246
+ },
247
+ appType: 'custom',
248
+ });
249
+
250
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
251
+ runMCPServer({
252
+ name: pkg.name || 'Sunpeak',
253
+ version: pkg.version || '0.1.0',
254
+ simulations,
255
+ port: 6766,
256
+ viteServer: mcpViteServer,
257
+ });
258
+
259
+ // Handle signals - close both servers
260
+ process.on('SIGINT', async () => {
261
+ await mcpViteServer.close();
262
+ await server.close();
263
+ process.exit(0);
264
+ });
265
+
266
+ process.on('SIGTERM', async () => {
267
+ await mcpViteServer.close();
268
+ await server.close();
269
+ process.exit(0);
270
+ });
271
+ } else {
272
+ // No simulations - just handle signals for the dev server
273
+ process.on('SIGINT', async () => {
274
+ await server.close();
275
+ process.exit(0);
276
+ });
277
+
278
+ process.on('SIGTERM', async () => {
279
+ await server.close();
280
+ process.exit(0);
281
+ });
282
+ }
122
283
  }
123
284
 
124
285
  // Allow running directly
package/bin/sunpeak.js CHANGED
@@ -187,9 +187,8 @@ Done! To get started:
187
187
 
188
188
  That's it! Your project commands:
189
189
 
190
- sunpeak dev # Start development server
190
+ sunpeak dev # Start dev server + MCP endpoint
191
191
  sunpeak build # Build for production
192
- sunpeak mcp # Start MCP server
193
192
  pnpm test # Run tests
194
193
 
195
194
  See README.md for more details.
@@ -285,13 +284,6 @@ function parseResourceArgs(args) {
285
284
  }
286
285
  break;
287
286
 
288
- case 'mcp':
289
- {
290
- const { mcp } = await import(join(COMMANDS_DIR, 'mcp.mjs'));
291
- await mcp(process.cwd(), args);
292
- }
293
- break;
294
-
295
287
  case 'login':
296
288
  {
297
289
  const { login } = await import(join(COMMANDS_DIR, 'login.mjs'));
@@ -350,9 +342,9 @@ Install:
350
342
 
351
343
  Usage:
352
344
  sunpeak new [name] [resources] Create a new project
353
- sunpeak dev Start dev server
345
+ sunpeak dev Start dev server + MCP endpoint
346
+ --no-begging Suppress GitHub star message
354
347
  sunpeak build Build resources
355
- sunpeak mcp Start MCP server
356
348
  sunpeak login Log in to Sunpeak
357
349
  sunpeak logout Log out of Sunpeak
358
350
  sunpeak push Push resources to repository
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const simulatorUrl = require("../simulator-url-B6DZi3vV.cjs");
3
+ const simulatorUrl = require("../simulator-url-CYMOGoB1.cjs");
4
4
  exports.ChatGPTSimulator = simulatorUrl.ChatGPTSimulator;
5
5
  exports.IframeResource = simulatorUrl.IframeResource;
6
6
  exports.ThemeProvider = simulatorUrl.ThemeProvider;
@@ -1,4 +1,4 @@
1
- import { C, I, T, c, i, u } from "../simulator-url-izFV6mji.js";
1
+ import { C, I, T, c, i, u } from "../simulator-url-DG79-dU3.js";
2
2
  export {
3
3
  C as ChatGPTSimulator,
4
4
  I as IframeResource,
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const simulatorUrl = require("./simulator-url-B6DZi3vV.cjs");
3
+ const simulatorUrl = require("./simulator-url-CYMOGoB1.cjs");
4
4
  const React = require("react");
5
5
  function _interopNamespaceDefault(e) {
6
6
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as clsx } from "./simulator-url-izFV6mji.js";
2
- import { C, I, S, T, c, v, s, q, i, r, w, t, e, f, g, h, j, u, k, l, m, n, d, b, o, p } from "./simulator-url-izFV6mji.js";
1
+ import { a as clsx } from "./simulator-url-DG79-dU3.js";
2
+ import { C, I, S, T, c, v, s, q, i, r, w, t, e, f, g, h, j, u, k, l, m, n, d, b, o, p } from "./simulator-url-DG79-dU3.js";
3
3
  import * as React from "react";
4
4
  const MOBILE_BREAKPOINT = 768;
5
5
  function useIsMobile() {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- const server = require("../server-D_oRdZjX.cjs");
3
+ const server = require("../server-CcLDAGBE.cjs");
4
4
  const path = require("path");
5
5
  const fs = require("fs");
6
6
  const projectRoot = process.cwd();
package/dist/mcp/entry.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as runMCPServer } from "../server-BLKltt88.js";
2
+ import { r as runMCPServer } from "../server-BI9Y531R.js";
3
3
  import path from "path";
4
4
  import { readFileSync, readdirSync, existsSync } from "fs";
5
5
  const projectRoot = process.cwd();
@@ -0,0 +1,2 @@
1
+ export declare const FAVICON_BASE64 = "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";
2
+ export declare const FAVICON_BUFFER: Buffer<ArrayBuffer>;
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const server = require("../server-D_oRdZjX.cjs");
3
+ const server = require("../server-CcLDAGBE.cjs");
4
+ exports.FAVICON_BASE64 = server.FAVICON_BASE64;
5
+ exports.FAVICON_BUFFER = server.FAVICON_BUFFER;
4
6
  exports.runMCPServer = server.runMCPServer;
5
7
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -1,2 +1,3 @@
1
1
  export { runMCPServer, type MCPServerConfig } from './server.js';
2
2
  export type { SimulationWithDist } from './types.js';
3
+ export { FAVICON_BASE64, FAVICON_BUFFER } from './favicon.js';
package/dist/mcp/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import { r } from "../server-BLKltt88.js";
1
+ import { F, a, r } from "../server-BI9Y531R.js";
2
2
  export {
3
+ F as FAVICON_BASE64,
4
+ a as FAVICON_BUFFER,
3
5
  r as runMCPServer
4
6
  };
5
7
  //# sourceMappingURL=index.js.map
@@ -5,6 +5,8 @@ import path from "node:path";
5
5
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
6
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
7
7
  import { z } from "zod";
8
+ const FAVICON_BASE64 = "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";
9
+ const FAVICON_BUFFER = Buffer.from(FAVICON_BASE64, "base64");
8
10
  function $constructor(name, initializer2, params) {
9
11
  function init(inst, def) {
10
12
  var _a;
@@ -4864,7 +4866,6 @@ function getViteResourceHtml(srcPath) {
4864
4866
  <\/script>
4865
4867
  <script type="module" src="${devServerUrl}/@vite/client"><\/script>
4866
4868
  <script type="module">
4867
- // Local network access check (matching skybridge)
4868
4869
  (async () => {
4869
4870
  if (!navigator.permissions?.query) return;
4870
4871
  const protocol = window.location.protocol;
@@ -5096,6 +5097,32 @@ function runMCPServer(config2) {
5096
5097
  res.end();
5097
5098
  return;
5098
5099
  }
5100
+ if (req.method === "GET" && url.pathname === "/") {
5101
+ res.writeHead(200, {
5102
+ "Content-Type": "text/html",
5103
+ "Access-Control-Allow-Origin": "*"
5104
+ });
5105
+ res.end(`<!DOCTYPE html>
5106
+ <html>
5107
+ <head>
5108
+ <meta charset="UTF-8" />
5109
+ <link rel="icon" type="image/png" href="/favicon.ico" />
5110
+ <title>Sunpeak MCP Server</title>
5111
+ </head>
5112
+ <body><h1>Sunpeak MCP Server</h1><p>Connect via <a href="/mcp">/mcp</a></p></body>
5113
+ </html>`);
5114
+ return;
5115
+ }
5116
+ if (req.method === "GET" && url.pathname === "/favicon.ico") {
5117
+ res.writeHead(200, {
5118
+ "Content-Type": "image/png",
5119
+ "Content-Length": FAVICON_BUFFER.length,
5120
+ "Cache-Control": "public, max-age=86400",
5121
+ "Access-Control-Allow-Origin": "*"
5122
+ });
5123
+ res.end(FAVICON_BUFFER);
5124
+ return;
5125
+ }
5099
5126
  if (req.method === "GET" && url.pathname === ssePath) {
5100
5127
  console.log(`[HTTP] ${req.method} ${url.pathname}`);
5101
5128
  await handleSseRequest(res, config2, simulations, viteMode);
@@ -5127,7 +5154,6 @@ function runMCPServer(config2) {
5127
5154
  httpServer.listen(port, () => {
5128
5155
  console.log(`Sunpeak MCP server listening on http://localhost:${port}`);
5129
5156
  console.log(` SSE stream: GET http://localhost:${port}${ssePath}`);
5130
- console.log(` Message post endpoint: POST http://localhost:${port}${postPath}?sessionId=...`);
5131
5157
  if (viteMode) {
5132
5158
  console.log(` Vite HMR: enabled (source files served with hot reload)`);
5133
5159
  }
@@ -5147,6 +5173,8 @@ function runMCPServer(config2) {
5147
5173
  process.on("SIGINT", () => void shutdown());
5148
5174
  }
5149
5175
  export {
5176
+ FAVICON_BASE64 as F,
5177
+ FAVICON_BUFFER as a,
5150
5178
  runMCPServer as r
5151
5179
  };
5152
- //# sourceMappingURL=server-BLKltt88.js.map
5180
+ //# sourceMappingURL=server-BI9Y531R.js.map