sunpeak 0.10.6 → 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 (112) 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 +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/favicon.d.ts +2 -0
  13. package/dist/mcp/index.cjs +3 -1
  14. package/dist/mcp/index.cjs.map +1 -1
  15. package/dist/mcp/index.d.ts +1 -0
  16. package/dist/mcp/index.js +3 -1
  17. package/dist/mcp/types.d.ts +7 -0
  18. package/dist/{server-CnRhUNGQ.js → server-BI9Y531R.js} +153 -29
  19. package/dist/{server-CnRhUNGQ.js.map → server-BI9Y531R.js.map} +1 -1
  20. package/dist/{server-B-T6Y3-J.cjs → server-CcLDAGBE.cjs} +153 -29
  21. package/dist/{server-B-T6Y3-J.cjs.map → server-CcLDAGBE.cjs.map} +1 -1
  22. package/dist/{simulator-url-pSDp_VWO.cjs → simulator-url-CYMOGoB1.cjs} +28 -17
  23. package/dist/simulator-url-CYMOGoB1.cjs.map +1 -0
  24. package/dist/{simulator-url-BUKX-wRa.js → simulator-url-DG79-dU3.js} +27 -16
  25. package/dist/simulator-url-DG79-dU3.js.map +1 -0
  26. package/package.json +1 -1
  27. package/template/README.md +6 -7
  28. package/template/_gitignore +4 -0
  29. package/template/dist/albums/albums.js +4 -4
  30. package/template/dist/albums/albums.json +1 -1
  31. package/template/dist/carousel/carousel.js +3 -3
  32. package/template/dist/carousel/carousel.json +1 -1
  33. package/template/dist/map/map.js +8 -8
  34. package/template/dist/map/map.json +1 -1
  35. package/template/dist/review/review.js +3 -3
  36. package/template/dist/review/review.json +1 -1
  37. package/template/index.html +0 -1
  38. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +7 -7
  39. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +1 -1
  40. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +7 -7
  41. package/template/node_modules/.vite/deps/_metadata.json +34 -34
  42. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  43. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Avatar.js +96 -0
  44. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Avatar.js.map +7 -0
  45. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Button.js +625 -0
  46. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Button.js.map +7 -0
  47. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Checkbox.js +33 -0
  48. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Checkbox.js.map +7 -0
  49. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Icon.js +1498 -0
  50. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Icon.js.map +7 -0
  51. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Input.js +13 -0
  52. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Input.js.map +7 -0
  53. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_SegmentedControl.js +103 -0
  54. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_SegmentedControl.js.map +7 -0
  55. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Select.js +3680 -0
  56. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Select.js.map +7 -0
  57. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Textarea.js +95 -0
  58. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_components_Textarea.js.map +7 -0
  59. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_theme.js +45 -0
  60. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/@openai_apps-sdk-ui_theme.js.map +7 -0
  61. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-2UDYPUBJ.js +15201 -0
  62. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-2UDYPUBJ.js.map +7 -0
  63. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-6QVG4F2X.js +93 -0
  64. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-6QVG4F2X.js.map +7 -0
  65. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-BUOVMFCD.js +1004 -0
  66. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-BUOVMFCD.js.map +7 -0
  67. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-CNYJBM5F.js +21 -0
  68. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-CNYJBM5F.js.map +7 -0
  69. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-EGRHWZRV.js +1 -0
  70. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-EGRHWZRV.js.map +7 -0
  71. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-ILHRZGIS.js +46 -0
  72. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-ILHRZGIS.js.map +7 -0
  73. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JAGHY6H6.js +231 -0
  74. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JAGHY6H6.js.map +7 -0
  75. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JGVISENQ.js +292 -0
  76. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-JGVISENQ.js.map +7 -0
  77. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-P5LK4A7U.js +112 -0
  78. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-P5LK4A7U.js.map +7 -0
  79. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-QPJAV452.js +13 -0
  80. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-QPJAV452.js.map +7 -0
  81. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-RYYR2YMB.js +111 -0
  82. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-RYYR2YMB.js.map +7 -0
  83. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-UM3ZGDFR.js +4480 -0
  84. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-UM3ZGDFR.js.map +7 -0
  85. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-XZTIOEPG.js +280 -0
  86. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/chunk-XZTIOEPG.js.map +7 -0
  87. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/clsx.js +10 -0
  88. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/clsx.js.map +7 -0
  89. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-react.js +1712 -0
  90. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-react.js.map +7 -0
  91. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-wheel-gestures.js +589 -0
  92. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/embla-carousel-wheel-gestures.js.map +7 -0
  93. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/mapbox-gl.js +32835 -0
  94. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/mapbox-gl.js.map +7 -0
  95. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/package.json +3 -0
  96. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom.js +7 -0
  97. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom.js.map +7 -0
  98. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom_client.js +20217 -0
  99. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react-dom_client.js.map +7 -0
  100. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react.js +6 -0
  101. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react.js.map +7 -0
  102. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-dev-runtime.js +278 -0
  103. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-dev-runtime.js.map +7 -0
  104. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-runtime.js +7 -0
  105. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/react_jsx-runtime.js.map +7 -0
  106. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/tailwind-merge.js +3095 -0
  107. package/template/node_modules/.vite-mcp/deps_temp_c8c8077a/tailwind-merge.js.map +7 -0
  108. package/template/package.json +0 -1
  109. package/bin/commands/mcp.mjs +0 -77
  110. package/dist/simulator-url-BUKX-wRa.js.map +0 -1
  111. package/dist/simulator-url-pSDp_VWO.cjs.map +0 -1
  112. 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-pSDp_VWO.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-BUKX-wRa.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-pSDp_VWO.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-BUKX-wRa.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-BUKX-wRa.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-B-T6Y3-J.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();
@@ -32,6 +32,7 @@ async function startServer() {
32
32
  ...simulation,
33
33
  name: simulationKey,
34
34
  distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),
35
+ srcPath: `/src/resources/${resourceKey}/${resourceKey}-resource.tsx`,
35
36
  resource
36
37
  });
37
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entry.cjs","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by nodemon or directly to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{scenario}-simulation.json (e.g., resources/albums/albums-show-simulation.json)\n * - resources/{resource}/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport type { Resource } from '@modelcontextprotocol/sdk/types.js';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Auto-discover resources and simulations from subdirectories\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceDirs = readdirSync(resourcesDir, { withFileTypes: true }).filter((entry) =>\n entry.isDirectory()\n );\n\n const resourcesMap = new Map<string, Resource>();\n const simulations: SimulationWithDist[] = [];\n\n for (const entry of resourceDirs) {\n const resourceKey = entry.name;\n const resourceDir = path.join(resourcesDir, resourceKey);\n const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);\n\n // Skip directories without a resource file\n if (!existsSync(resourcePath)) {\n continue;\n }\n\n // Load resource\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(resourceKey, resource);\n\n // Discover simulation files in the same directory\n const dirFiles = readdirSync(resourceDir);\n for (const file of dirFiles) {\n if (file.endsWith('-simulation.json')) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = file.replace(/-simulation\\.json$/, '');\n const simulationPath = path.join(resourceDir, file);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),\n resource,\n });\n }\n }\n }\n\n runMCPServer({\n name: pkg.name || 'Sunpeak',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":["readFileSync","readdirSync","existsSync","runMCPServer"],"mappings":";;;;;AAeA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAMA,GAAAA,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,eAAe,KAAK,KAAK,aAAa,eAAe;AAC3D,QAAM,eAAeC,GAAAA,YAAY,cAAc,EAAE,eAAe,KAAA,CAAM,EAAE;AAAA,IAAO,CAAC,UAC9E,MAAM,YAAA;AAAA,EAAY;AAGpB,QAAM,mCAAmB,IAAA;AACzB,QAAM,cAAoC,CAAA;AAE1C,aAAW,SAAS,cAAc;AAChC,UAAM,cAAc,MAAM;AAC1B,UAAM,cAAc,KAAK,KAAK,cAAc,WAAW;AACvD,UAAM,eAAe,KAAK,KAAK,aAAa,GAAG,WAAW,gBAAgB;AAG1E,QAAI,CAACC,GAAAA,WAAW,YAAY,GAAG;AAC7B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,MAAMF,GAAAA,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,aAAa,QAAQ;AAGtC,UAAM,WAAWC,GAAAA,YAAY,WAAW;AACxC,eAAW,QAAQ,UAAU;AAC3B,UAAI,KAAK,SAAS,kBAAkB,GAAG;AAErC,cAAM,gBAAgB,KAAK,QAAQ,sBAAsB,EAAE;AAC3D,cAAM,iBAAiB,KAAK,KAAK,aAAa,IAAI;AAClD,cAAM,aAAa,KAAK,MAAMD,GAAAA,aAAa,gBAAgB,OAAO,CAAC;AAEnE,oBAAY,KAAK;AAAA,UACf,GAAG;AAAA,UACH,MAAM;AAAA,UACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,IAAI,WAAW,KAAK;AAAA,UACxE;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEAG,sBAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
1
+ {"version":3,"file":"entry.cjs","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by the mcp command to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{scenario}-simulation.json (e.g., resources/albums/albums-show-simulation.json)\n * - resources/{resource}/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport type { Resource } from '@modelcontextprotocol/sdk/types.js';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Auto-discover resources and simulations from subdirectories\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceDirs = readdirSync(resourcesDir, { withFileTypes: true }).filter((entry) =>\n entry.isDirectory()\n );\n\n const resourcesMap = new Map<string, Resource>();\n const simulations: SimulationWithDist[] = [];\n\n for (const entry of resourceDirs) {\n const resourceKey = entry.name;\n const resourceDir = path.join(resourcesDir, resourceKey);\n const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);\n\n // Skip directories without a resource file\n if (!existsSync(resourcePath)) {\n continue;\n }\n\n // Load resource\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(resourceKey, resource);\n\n // Discover simulation files in the same directory\n const dirFiles = readdirSync(resourceDir);\n for (const file of dirFiles) {\n if (file.endsWith('-simulation.json')) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = file.replace(/-simulation\\.json$/, '');\n const simulationPath = path.join(resourceDir, file);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),\n srcPath: `/src/resources/${resourceKey}/${resourceKey}-resource.tsx`,\n resource,\n });\n }\n }\n }\n\n runMCPServer({\n name: pkg.name || 'Sunpeak',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":["readFileSync","readdirSync","existsSync","runMCPServer"],"mappings":";;;;;AAeA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAMA,GAAAA,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,eAAe,KAAK,KAAK,aAAa,eAAe;AAC3D,QAAM,eAAeC,GAAAA,YAAY,cAAc,EAAE,eAAe,KAAA,CAAM,EAAE;AAAA,IAAO,CAAC,UAC9E,MAAM,YAAA;AAAA,EAAY;AAGpB,QAAM,mCAAmB,IAAA;AACzB,QAAM,cAAoC,CAAA;AAE1C,aAAW,SAAS,cAAc;AAChC,UAAM,cAAc,MAAM;AAC1B,UAAM,cAAc,KAAK,KAAK,cAAc,WAAW;AACvD,UAAM,eAAe,KAAK,KAAK,aAAa,GAAG,WAAW,gBAAgB;AAG1E,QAAI,CAACC,GAAAA,WAAW,YAAY,GAAG;AAC7B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,MAAMF,GAAAA,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,aAAa,QAAQ;AAGtC,UAAM,WAAWC,GAAAA,YAAY,WAAW;AACxC,eAAW,QAAQ,UAAU;AAC3B,UAAI,KAAK,SAAS,kBAAkB,GAAG;AAErC,cAAM,gBAAgB,KAAK,QAAQ,sBAAsB,EAAE;AAC3D,cAAM,iBAAiB,KAAK,KAAK,aAAa,IAAI;AAClD,cAAM,aAAa,KAAK,MAAMD,GAAAA,aAAa,gBAAgB,OAAO,CAAC;AAEnE,oBAAY,KAAK;AAAA,UACf,GAAG;AAAA,UACH,MAAM;AAAA,UACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,IAAI,WAAW,KAAK;AAAA,UACxE,SAAS,kBAAkB,WAAW,IAAI,WAAW;AAAA,UACrD;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEAG,sBAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
package/dist/mcp/entry.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as runMCPServer } from "../server-CnRhUNGQ.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();
@@ -31,6 +31,7 @@ async function startServer() {
31
31
  ...simulation,
32
32
  name: simulationKey,
33
33
  distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),
34
+ srcPath: `/src/resources/${resourceKey}/${resourceKey}-resource.tsx`,
34
35
  resource
35
36
  });
36
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entry.js","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by nodemon or directly to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{scenario}-simulation.json (e.g., resources/albums/albums-show-simulation.json)\n * - resources/{resource}/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport type { Resource } from '@modelcontextprotocol/sdk/types.js';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Auto-discover resources and simulations from subdirectories\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceDirs = readdirSync(resourcesDir, { withFileTypes: true }).filter((entry) =>\n entry.isDirectory()\n );\n\n const resourcesMap = new Map<string, Resource>();\n const simulations: SimulationWithDist[] = [];\n\n for (const entry of resourceDirs) {\n const resourceKey = entry.name;\n const resourceDir = path.join(resourcesDir, resourceKey);\n const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);\n\n // Skip directories without a resource file\n if (!existsSync(resourcePath)) {\n continue;\n }\n\n // Load resource\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(resourceKey, resource);\n\n // Discover simulation files in the same directory\n const dirFiles = readdirSync(resourceDir);\n for (const file of dirFiles) {\n if (file.endsWith('-simulation.json')) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = file.replace(/-simulation\\.json$/, '');\n const simulationPath = path.join(resourceDir, file);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),\n resource,\n });\n }\n }\n }\n\n runMCPServer({\n name: pkg.name || 'Sunpeak',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;;AAeA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,eAAe,KAAK,KAAK,aAAa,eAAe;AAC3D,QAAM,eAAe,YAAY,cAAc,EAAE,eAAe,KAAA,CAAM,EAAE;AAAA,IAAO,CAAC,UAC9E,MAAM,YAAA;AAAA,EAAY;AAGpB,QAAM,mCAAmB,IAAA;AACzB,QAAM,cAAoC,CAAA;AAE1C,aAAW,SAAS,cAAc;AAChC,UAAM,cAAc,MAAM;AAC1B,UAAM,cAAc,KAAK,KAAK,cAAc,WAAW;AACvD,UAAM,eAAe,KAAK,KAAK,aAAa,GAAG,WAAW,gBAAgB;AAG1E,QAAI,CAAC,WAAW,YAAY,GAAG;AAC7B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,aAAa,QAAQ;AAGtC,UAAM,WAAW,YAAY,WAAW;AACxC,eAAW,QAAQ,UAAU;AAC3B,UAAI,KAAK,SAAS,kBAAkB,GAAG;AAErC,cAAM,gBAAgB,KAAK,QAAQ,sBAAsB,EAAE;AAC3D,cAAM,iBAAiB,KAAK,KAAK,aAAa,IAAI;AAClD,cAAM,aAAa,KAAK,MAAM,aAAa,gBAAgB,OAAO,CAAC;AAEnE,oBAAY,KAAK;AAAA,UACf,GAAG;AAAA,UACH,MAAM;AAAA,UACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,IAAI,WAAW,KAAK;AAAA,UACxE;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,eAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
1
+ {"version":3,"file":"entry.js","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by the mcp command to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{scenario}-simulation.json (e.g., resources/albums/albums-show-simulation.json)\n * - resources/{resource}/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport type { Resource } from '@modelcontextprotocol/sdk/types.js';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Auto-discover resources and simulations from subdirectories\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceDirs = readdirSync(resourcesDir, { withFileTypes: true }).filter((entry) =>\n entry.isDirectory()\n );\n\n const resourcesMap = new Map<string, Resource>();\n const simulations: SimulationWithDist[] = [];\n\n for (const entry of resourceDirs) {\n const resourceKey = entry.name;\n const resourceDir = path.join(resourcesDir, resourceKey);\n const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);\n\n // Skip directories without a resource file\n if (!existsSync(resourcePath)) {\n continue;\n }\n\n // Load resource\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(resourceKey, resource);\n\n // Discover simulation files in the same directory\n const dirFiles = readdirSync(resourceDir);\n for (const file of dirFiles) {\n if (file.endsWith('-simulation.json')) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = file.replace(/-simulation\\.json$/, '');\n const simulationPath = path.join(resourceDir, file);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),\n srcPath: `/src/resources/${resourceKey}/${resourceKey}-resource.tsx`,\n resource,\n });\n }\n }\n }\n\n runMCPServer({\n name: pkg.name || 'Sunpeak',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;;AAeA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,eAAe,KAAK,KAAK,aAAa,eAAe;AAC3D,QAAM,eAAe,YAAY,cAAc,EAAE,eAAe,KAAA,CAAM,EAAE;AAAA,IAAO,CAAC,UAC9E,MAAM,YAAA;AAAA,EAAY;AAGpB,QAAM,mCAAmB,IAAA;AACzB,QAAM,cAAoC,CAAA;AAE1C,aAAW,SAAS,cAAc;AAChC,UAAM,cAAc,MAAM;AAC1B,UAAM,cAAc,KAAK,KAAK,cAAc,WAAW;AACvD,UAAM,eAAe,KAAK,KAAK,aAAa,GAAG,WAAW,gBAAgB;AAG1E,QAAI,CAAC,WAAW,YAAY,GAAG;AAC7B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,aAAa,QAAQ;AAGtC,UAAM,WAAW,YAAY,WAAW;AACxC,eAAW,QAAQ,UAAU;AAC3B,UAAI,KAAK,SAAS,kBAAkB,GAAG;AAErC,cAAM,gBAAgB,KAAK,QAAQ,sBAAsB,EAAE;AAC3D,cAAM,iBAAiB,KAAK,KAAK,aAAa,IAAI;AAClD,cAAM,aAAa,KAAK,MAAM,aAAa,gBAAgB,OAAO,CAAC;AAEnE,oBAAY,KAAK;AAAA,UACf,GAAG;AAAA,UACH,MAAM;AAAA,UACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,IAAI,WAAW,KAAK;AAAA,UACxE,SAAS,kBAAkB,WAAW,IAAI,WAAW;AAAA,UACrD;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,eAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
@@ -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-B-T6Y3-J.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-CnRhUNGQ.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
@@ -6,6 +6,7 @@ import { Resource, Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.
6
6
  export interface SimulationWithDist {
7
7
  name: string;
8
8
  distPath: string;
9
+ srcPath?: string;
9
10
  tool: Tool;
10
11
  resource: Resource;
11
12
  callToolResult?: CallToolResult;
@@ -19,4 +20,10 @@ export interface MCPServerConfig {
19
20
  version?: string;
20
21
  port?: number;
21
22
  simulations: SimulationWithDist[];
23
+ /**
24
+ * Vite dev server instance for HMR mode.
25
+ * When provided, resources are served as HTML that loads from Vite.
26
+ * When not provided, resources serve bundled JS (production mode).
27
+ */
28
+ viteServer?: unknown;
22
29
  }