sunpeak 0.9.10 → 0.10.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 (95) hide show
  1. package/bin/commands/build.mjs +56 -30
  2. package/bin/commands/deploy.mjs +17 -17
  3. package/bin/commands/push.mjs +115 -64
  4. package/bin/lib/patterns.mjs +40 -0
  5. package/bin/sunpeak.js +50 -106
  6. package/dist/chatgpt/index.cjs +1 -1
  7. package/dist/chatgpt/index.js +1 -1
  8. package/dist/index.cjs +150 -12
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.js +167 -29
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/discovery.d.ts +76 -13
  13. package/dist/mcp/entry.cjs +24 -27
  14. package/dist/mcp/entry.cjs.map +1 -1
  15. package/dist/mcp/entry.js +25 -28
  16. package/dist/mcp/entry.js.map +1 -1
  17. package/dist/{simulator-url-wBi-pko3.js → simulator-url-BZBcq5tc.js} +9 -16
  18. package/dist/{simulator-url-wBi-pko3.js.map → simulator-url-BZBcq5tc.js.map} +1 -1
  19. package/dist/{simulator-url-oevkxbU4.cjs → simulator-url-D4tFBjeu.cjs} +10 -17
  20. package/dist/{simulator-url-oevkxbU4.cjs.map → simulator-url-D4tFBjeu.cjs.map} +1 -1
  21. package/package.json +1 -1
  22. package/template/.sunpeak/dev.tsx +5 -5
  23. package/template/README.md +54 -50
  24. package/template/dist/{albums.json → albums/albums.json} +1 -1
  25. package/template/dist/{carousel.json → carousel/carousel.json} +1 -1
  26. package/template/dist/{map.json → map/map.json} +1 -1
  27. package/template/dist/{review.json → review/review.json} +1 -1
  28. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +4 -4
  29. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +6 -6
  30. package/template/node_modules/.vite/deps/_metadata.json +25 -25
  31. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  32. package/template/src/resources/{albums-resource.test.tsx → albums/albums-resource.test.tsx} +1 -1
  33. package/template/src/resources/{albums-resource.tsx → albums/albums-resource.tsx} +1 -1
  34. package/template/src/resources/albums/albums-show-simulation.json +131 -0
  35. package/template/src/{components/album → resources/albums/components}/album-card.tsx +1 -1
  36. package/template/src/{components/album → resources/albums/components}/album-carousel.tsx +1 -1
  37. package/template/src/{components/album → resources/albums/components}/film-strip.tsx +1 -1
  38. package/template/src/{components/album → resources/albums/components}/fullscreen-viewer.tsx +1 -1
  39. package/template/src/resources/{carousel-resource.test.tsx → carousel/carousel-resource.test.tsx} +1 -1
  40. package/template/src/resources/{carousel-resource.tsx → carousel/carousel-resource.tsx} +1 -1
  41. package/template/src/resources/carousel/carousel-show-simulation.json +68 -0
  42. package/template/src/{components/carousel → resources/carousel/components}/card.tsx +1 -1
  43. package/template/src/{components/carousel → resources/carousel/components}/carousel.tsx +1 -1
  44. package/template/src/resources/index.ts +5 -5
  45. package/template/src/{components/map → resources/map/components}/map-view.tsx +1 -1
  46. package/template/src/{components/map → resources/map/components}/map.tsx +1 -1
  47. package/template/src/{components/map → resources/map/components}/place-card.tsx +1 -1
  48. package/template/src/{components/map → resources/map/components}/place-carousel.tsx +1 -1
  49. package/template/src/{components/map → resources/map/components}/place-inspector.tsx +1 -1
  50. package/template/src/{components/map → resources/map/components}/place-list.tsx +1 -1
  51. package/template/src/resources/{map-resource.test.tsx → map/map-resource.test.tsx} +1 -1
  52. package/template/src/resources/{map-resource.tsx → map/map-resource.tsx} +1 -1
  53. package/template/src/resources/map/map-show-simulation.json +123 -0
  54. package/template/src/resources/review/review-diff-simulation.json +80 -0
  55. package/template/src/resources/review/review-post-simulation.json +56 -0
  56. package/template/src/resources/review/review-purchase-simulation.json +88 -0
  57. package/dist/discovery-a4WId9PC.cjs +0 -125
  58. package/dist/discovery-a4WId9PC.cjs.map +0 -1
  59. package/dist/discovery-ft3cd2dW.js +0 -126
  60. package/dist/discovery-ft3cd2dW.js.map +0 -1
  61. package/template/src/components/index.ts +0 -3
  62. package/template/src/simulations/index.ts +0 -16
  63. /package/template/{src/simulations → dist/albums}/albums-show-simulation.json +0 -0
  64. /package/template/dist/{albums.js → albums/albums.js} +0 -0
  65. /package/template/{src/simulations → dist/carousel}/carousel-show-simulation.json +0 -0
  66. /package/template/dist/{carousel.js → carousel/carousel.js} +0 -0
  67. /package/template/{src/simulations → dist/map}/map-show-simulation.json +0 -0
  68. /package/template/dist/{map.js → map/map.js} +0 -0
  69. /package/template/{src/simulations → dist/review}/review-diff-simulation.json +0 -0
  70. /package/template/{src/simulations → dist/review}/review-post-simulation.json +0 -0
  71. /package/template/{src/simulations → dist/review}/review-purchase-simulation.json +0 -0
  72. /package/template/dist/{review.js → review/review.js} +0 -0
  73. /package/template/src/resources/{albums-resource.json → albums/albums-resource.json} +0 -0
  74. /package/template/src/{components/album → resources/albums/components}/album-card.test.tsx +0 -0
  75. /package/template/src/{components/album → resources/albums/components}/album-carousel.test.tsx +0 -0
  76. /package/template/src/{components/album → resources/albums/components}/albums.test.tsx +0 -0
  77. /package/template/src/{components/album → resources/albums/components}/albums.tsx +0 -0
  78. /package/template/src/{components/album → resources/albums/components}/film-strip.test.tsx +0 -0
  79. /package/template/src/{components/album → resources/albums/components}/fullscreen-viewer.test.tsx +0 -0
  80. /package/template/src/{components/album → resources/albums/components}/index.ts +0 -0
  81. /package/template/src/resources/{carousel-resource.json → carousel/carousel-resource.json} +0 -0
  82. /package/template/src/{components/carousel → resources/carousel/components}/card.test.tsx +0 -0
  83. /package/template/src/{components/carousel → resources/carousel/components}/carousel.test.tsx +0 -0
  84. /package/template/src/{components/carousel → resources/carousel/components}/index.ts +0 -0
  85. /package/template/src/{components/map → resources/map/components}/index.ts +0 -0
  86. /package/template/src/{components/map → resources/map/components}/map-view.test.tsx +0 -0
  87. /package/template/src/{components/map → resources/map/components}/place-card.test.tsx +0 -0
  88. /package/template/src/{components/map → resources/map/components}/place-carousel.test.tsx +0 -0
  89. /package/template/src/{components/map → resources/map/components}/place-inspector.test.tsx +0 -0
  90. /package/template/src/{components/map → resources/map/components}/place-list.test.tsx +0 -0
  91. /package/template/src/{components/map → resources/map/components}/types.ts +0 -0
  92. /package/template/src/resources/{map-resource.json → map/map-resource.json} +0 -0
  93. /package/template/src/resources/{review-resource.json → review/review-resource.json} +0 -0
  94. /package/template/src/resources/{review-resource.test.tsx → review/review-resource.test.tsx} +0 -0
  95. /package/template/src/resources/{review-resource.tsx → review/review-resource.tsx} +0 -0
@@ -35,25 +35,16 @@ type GlobModules = Record<string, unknown>;
35
35
  * Extracts components and exports them with PascalCase names.
36
36
  *
37
37
  * @example
38
- * const modules = import.meta.glob('./*-resource.tsx', { eager: true });
38
+ * const modules = import.meta.glob('./**\/*-resource.tsx', { eager: true });
39
39
  * export default createResourceExports(modules);
40
40
  */
41
41
  export declare function createResourceExports(modules: GlobModules): Record<string, React.ComponentType>;
42
- /**
43
- * Process simulation modules from import.meta.glob() result.
44
- * Builds a map of simulation key -> simulation data.
45
- *
46
- * @example
47
- * const modules = import.meta.glob('./*-simulation.json', { eager: true });
48
- * export const SIMULATIONS = createSimulationIndex(modules);
49
- */
50
- export declare function createSimulationIndex(modules: GlobModules): Record<string, unknown>;
51
42
  /**
52
43
  * Build a resource metadata map from import.meta.glob() result.
53
44
  * Used for connecting simulations to their resource definitions.
54
45
  *
55
46
  * @example
56
- * const modules = import.meta.glob('../src/resources/*-resource.json', { eager: true });
47
+ * const modules = import.meta.glob('../src/resources/**\/*-resource.json', { eager: true });
57
48
  * const resourcesMap = buildResourceMap(modules);
58
49
  */
59
50
  export declare function buildResourceMap<T>(modules: GlobModules): Map<string, T>;
@@ -101,10 +92,82 @@ export interface BuildDevSimulationsOptions {
101
92
  *
102
93
  * @example
103
94
  * const simulations = buildDevSimulations({
104
- * simulationModules: import.meta.glob('../src/simulations/*-simulation.json', { eager: true }),
105
- * resourceModules: import.meta.glob('../src/resources/*-resource.json', { eager: true }),
95
+ * simulationModules: import.meta.glob('../src/resources/**\/*-simulation.json', { eager: true }),
96
+ * resourceModules: import.meta.glob('../src/resources/**\/*-resource.json', { eager: true }),
106
97
  * resourceComponents: resourceComponents,
107
98
  * });
108
99
  */
109
100
  export declare function buildDevSimulations(options: BuildDevSimulationsOptions): Record<string, Simulation>;
101
+ /**
102
+ * Information about a discovered resource directory
103
+ */
104
+ export interface ResourceDirInfo {
105
+ /** Resource key (directory name), e.g., 'albums', 'carousel' */
106
+ key: string;
107
+ /** Full path to the resource directory */
108
+ dir: string;
109
+ /** Full path to the main resource file (tsx or json depending on context) */
110
+ resourcePath: string;
111
+ }
112
+ /**
113
+ * File system operations interface for dependency injection in tests
114
+ */
115
+ export interface FsOps {
116
+ readdirSync: (path: string, options: {
117
+ withFileTypes: true;
118
+ }) => Array<{
119
+ name: string;
120
+ isDirectory: () => boolean;
121
+ }>;
122
+ existsSync: (path: string) => boolean;
123
+ }
124
+ /**
125
+ * Find all resource directories in a base directory.
126
+ * Each valid resource directory contains a file matching the expected pattern.
127
+ *
128
+ * @param baseDir - Base directory to scan (e.g., 'src/resources' or 'dist')
129
+ * @param filePattern - Function to generate expected filename from resource key
130
+ * @param fs - File system operations (for testing)
131
+ *
132
+ * @example
133
+ * // Find source resources (tsx files)
134
+ * const resources = findResourceDirs('src/resources', key => `${key}-resource.tsx`);
135
+ *
136
+ * @example
137
+ * // Find built resources (js files)
138
+ * const resources = findResourceDirs('dist', key => `${key}.js`);
139
+ */
140
+ export declare function findResourceDirs(baseDir: string, filePattern: (key: string) => string, fs: FsOps): ResourceDirInfo[];
141
+ /**
142
+ * Check if a filename is a simulation file for a given resource.
143
+ * Matches pattern: {resourceKey}-*-simulation.json
144
+ *
145
+ * @example
146
+ * isSimulationFile('albums-show-simulation.json', 'albums') // true
147
+ * isSimulationFile('albums-show-simulation.json', 'carousel') // false
148
+ * isSimulationFile('albums-resource.json', 'albums') // false
149
+ */
150
+ export declare function isSimulationFile(filename: string, resourceKey: string): boolean;
151
+ /**
152
+ * Extract the simulation name from a simulation filename.
153
+ * Given "{resourceKey}-{name}-simulation.json", returns "{name}".
154
+ *
155
+ * @example
156
+ * extractSimulationName('albums-show-simulation.json', 'albums') // 'show'
157
+ * extractSimulationName('carousel-hero-simulation.json', 'carousel') // 'hero'
158
+ */
159
+ export declare function extractSimulationName(filename: string, resourceKey: string): string;
160
+ /**
161
+ * Find all simulation files in a resource directory.
162
+ *
163
+ * @param resourceDir - Path to the resource directory
164
+ * @param resourceKey - Resource key (e.g., 'albums')
165
+ * @param fs - File system operations (for testing)
166
+ * @returns Array of { filename, name } objects
167
+ */
168
+ export declare function findSimulationFiles(resourceDir: string, resourceKey: string, fs: Pick<FsOps, 'readdirSync' | 'existsSync'>): Array<{
169
+ filename: string;
170
+ name: string;
171
+ path: string;
172
+ }>;
110
173
  export {};
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  const server = require("../server-CSybLAYo.cjs");
4
- const discovery = require("../discovery-a4WId9PC.cjs");
5
4
  const path = require("path");
6
5
  const fs = require("fs");
7
6
  const projectRoot = process.cwd();
@@ -9,36 +8,34 @@ async function startServer() {
9
8
  const pkgPath = path.join(projectRoot, "package.json");
10
9
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
11
10
  const resourcesDir = path.join(projectRoot, "src/resources");
12
- const resourceFiles = fs.readdirSync(resourcesDir).filter((f) => f.endsWith("-resource.json"));
11
+ const resourceDirs = fs.readdirSync(resourcesDir, { withFileTypes: true }).filter(
12
+ (entry) => entry.isDirectory()
13
+ );
13
14
  const resourcesMap = /* @__PURE__ */ new Map();
14
- for (const filename of resourceFiles) {
15
- const key = filename.replace(/-resource\.json$/, "");
16
- const resourcePath = path.join(resourcesDir, filename);
17
- const resource = JSON.parse(fs.readFileSync(resourcePath, "utf-8"));
18
- resourcesMap.set(key, resource);
19
- }
20
- const resourceKeys = Array.from(resourcesMap.keys());
21
- const simulationsDir = path.join(projectRoot, "src/simulations");
22
- const simulationFiles = fs.readdirSync(simulationsDir).filter((f) => f.endsWith("-simulation.json"));
23
15
  const simulations = [];
24
- for (const filename of simulationFiles) {
25
- const simulationKey = filename.replace(/-simulation\.json$/, "");
26
- const simulationPath = path.join(simulationsDir, filename);
27
- const simulation = JSON.parse(fs.readFileSync(simulationPath, "utf-8"));
28
- const resourceKey = discovery.findResourceKey(simulationKey, resourceKeys);
29
- if (!resourceKey) {
30
- console.warn(
31
- `No matching resource found for simulation "${simulationKey}". Expected a resource file like src/resources/${simulationKey.split("-")[0]}-resource.json`
32
- );
16
+ for (const entry of resourceDirs) {
17
+ const resourceKey = entry.name;
18
+ const resourceDir = path.join(resourcesDir, resourceKey);
19
+ const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);
20
+ if (!fs.existsSync(resourcePath)) {
33
21
  continue;
34
22
  }
35
- const resource = resourcesMap.get(resourceKey);
36
- simulations.push({
37
- ...simulation,
38
- name: simulationKey,
39
- distPath: path.join(projectRoot, `dist/${resourceKey}.js`),
40
- resource
41
- });
23
+ const resource = JSON.parse(fs.readFileSync(resourcePath, "utf-8"));
24
+ resourcesMap.set(resourceKey, resource);
25
+ const dirFiles = fs.readdirSync(resourceDir);
26
+ for (const file of dirFiles) {
27
+ if (file.endsWith("-simulation.json")) {
28
+ const simulationKey = file.replace(/-simulation\.json$/, "");
29
+ const simulationPath = path.join(resourceDir, file);
30
+ const simulation = JSON.parse(fs.readFileSync(simulationPath, "utf-8"));
31
+ simulations.push({
32
+ ...simulation,
33
+ name: simulationKey,
34
+ distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),
35
+ resource
36
+ });
37
+ }
38
+ }
42
39
  }
43
40
  server.runMCPServer({
44
41
  name: pkg.name || "Sunpeak",
@@ -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 * - simulations/{resource}-{tool}-simulation.json (e.g., albums-show-simulation.json)\n * - resources/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport { findResourceKey } from '../lib/discovery.js';\nimport path from 'path';\nimport { 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 resource files first (to build lookup map)\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceFiles = readdirSync(resourcesDir).filter((f) => f.endsWith('-resource.json'));\n\n const resourcesMap = new Map<string, Resource>();\n for (const filename of resourceFiles) {\n // Extract key from filename: 'review-resource.json' -> 'review'\n const key = filename.replace(/-resource\\.json$/, '');\n const resourcePath = path.join(resourcesDir, filename);\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(key, resource);\n }\n\n const resourceKeys = Array.from(resourcesMap.keys());\n\n // Auto-discover simulation files\n const simulationsDir = path.join(projectRoot, 'src/simulations');\n const simulationFiles = readdirSync(simulationsDir).filter((f) => f.endsWith('-simulation.json'));\n\n // Build simulations array from discovered files\n const simulations: SimulationWithDist[] = [];\n\n for (const filename of simulationFiles) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = filename.replace(/-simulation\\.json$/, '');\n\n // Load simulation data\n const simulationPath = path.join(simulationsDir, filename);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n // Find matching resource by best prefix match\n const resourceKey = findResourceKey(simulationKey, resourceKeys);\n if (!resourceKey) {\n console.warn(\n `No matching resource found for simulation \"${simulationKey}\". ` +\n `Expected a resource file like src/resources/${simulationKey.split('-')[0]}-resource.json`\n );\n continue;\n }\n\n const resource = resourcesMap.get(resourceKey)!;\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}.js`),\n resource,\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","findResourceKey","runMCPServer"],"mappings":";;;;;;AAgBA,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,gBAAgBC,eAAY,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,gBAAgB,CAAC;AAE1F,QAAM,mCAAmB,IAAA;AACzB,aAAW,YAAY,eAAe;AAEpC,UAAM,MAAM,SAAS,QAAQ,oBAAoB,EAAE;AACnD,UAAM,eAAe,KAAK,KAAK,cAAc,QAAQ;AACrD,UAAM,WAAW,KAAK,MAAMD,GAAAA,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,KAAK,QAAQ;AAAA,EAChC;AAEA,QAAM,eAAe,MAAM,KAAK,aAAa,MAAM;AAGnD,QAAM,iBAAiB,KAAK,KAAK,aAAa,iBAAiB;AAC/D,QAAM,kBAAkBC,eAAY,cAAc,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,kBAAkB,CAAC;AAGhG,QAAM,cAAoC,CAAA;AAE1C,aAAW,YAAY,iBAAiB;AAEtC,UAAM,gBAAgB,SAAS,QAAQ,sBAAsB,EAAE;AAG/D,UAAM,iBAAiB,KAAK,KAAK,gBAAgB,QAAQ;AACzD,UAAM,aAAa,KAAK,MAAMD,GAAAA,aAAa,gBAAgB,OAAO,CAAC;AAGnE,UAAM,cAAcE,UAAAA,gBAAgB,eAAe,YAAY;AAC/D,QAAI,CAAC,aAAa;AAChB,cAAQ;AAAA,QACN,8CAA8C,aAAa,kDACV,cAAc,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,MAAA;AAE9E;AAAA,IACF;AAEA,UAAM,WAAW,aAAa,IAAI,WAAW;AAE7C,gBAAY,KAAK;AAAA,MACf,GAAG;AAAA,MACH,MAAM;AAAA,MACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,KAAK;AAAA,MACzD;AAAA,IAAA,CACD;AAAA,EACH;AAEAC,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 nodemon or directly to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{tool}-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;"}
package/dist/mcp/entry.js CHANGED
@@ -1,43 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import { r as runMCPServer } from "../server-310A1k9o.js";
3
- import { f as findResourceKey } from "../discovery-ft3cd2dW.js";
4
3
  import path from "path";
5
- import { readFileSync, readdirSync } from "fs";
4
+ import { readFileSync, readdirSync, existsSync } from "fs";
6
5
  const projectRoot = process.cwd();
7
6
  async function startServer() {
8
7
  const pkgPath = path.join(projectRoot, "package.json");
9
8
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
10
9
  const resourcesDir = path.join(projectRoot, "src/resources");
11
- const resourceFiles = readdirSync(resourcesDir).filter((f) => f.endsWith("-resource.json"));
10
+ const resourceDirs = readdirSync(resourcesDir, { withFileTypes: true }).filter(
11
+ (entry) => entry.isDirectory()
12
+ );
12
13
  const resourcesMap = /* @__PURE__ */ new Map();
13
- for (const filename of resourceFiles) {
14
- const key = filename.replace(/-resource\.json$/, "");
15
- const resourcePath = path.join(resourcesDir, filename);
16
- const resource = JSON.parse(readFileSync(resourcePath, "utf-8"));
17
- resourcesMap.set(key, resource);
18
- }
19
- const resourceKeys = Array.from(resourcesMap.keys());
20
- const simulationsDir = path.join(projectRoot, "src/simulations");
21
- const simulationFiles = readdirSync(simulationsDir).filter((f) => f.endsWith("-simulation.json"));
22
14
  const simulations = [];
23
- for (const filename of simulationFiles) {
24
- const simulationKey = filename.replace(/-simulation\.json$/, "");
25
- const simulationPath = path.join(simulationsDir, filename);
26
- const simulation = JSON.parse(readFileSync(simulationPath, "utf-8"));
27
- const resourceKey = findResourceKey(simulationKey, resourceKeys);
28
- if (!resourceKey) {
29
- console.warn(
30
- `No matching resource found for simulation "${simulationKey}". Expected a resource file like src/resources/${simulationKey.split("-")[0]}-resource.json`
31
- );
15
+ for (const entry of resourceDirs) {
16
+ const resourceKey = entry.name;
17
+ const resourceDir = path.join(resourcesDir, resourceKey);
18
+ const resourcePath = path.join(resourceDir, `${resourceKey}-resource.json`);
19
+ if (!existsSync(resourcePath)) {
32
20
  continue;
33
21
  }
34
- const resource = resourcesMap.get(resourceKey);
35
- simulations.push({
36
- ...simulation,
37
- name: simulationKey,
38
- distPath: path.join(projectRoot, `dist/${resourceKey}.js`),
39
- resource
40
- });
22
+ const resource = JSON.parse(readFileSync(resourcePath, "utf-8"));
23
+ resourcesMap.set(resourceKey, resource);
24
+ const dirFiles = readdirSync(resourceDir);
25
+ for (const file of dirFiles) {
26
+ if (file.endsWith("-simulation.json")) {
27
+ const simulationKey = file.replace(/-simulation\.json$/, "");
28
+ const simulationPath = path.join(resourceDir, file);
29
+ const simulation = JSON.parse(readFileSync(simulationPath, "utf-8"));
30
+ simulations.push({
31
+ ...simulation,
32
+ name: simulationKey,
33
+ distPath: path.join(projectRoot, `dist/${resourceKey}/${resourceKey}.js`),
34
+ resource
35
+ });
36
+ }
37
+ }
41
38
  }
42
39
  runMCPServer({
43
40
  name: pkg.name || "Sunpeak",
@@ -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 * - simulations/{resource}-{tool}-simulation.json (e.g., albums-show-simulation.json)\n * - resources/{resource}-resource.json\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport { findResourceKey } from '../lib/discovery.js';\nimport path from 'path';\nimport { 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 resource files first (to build lookup map)\n const resourcesDir = path.join(projectRoot, 'src/resources');\n const resourceFiles = readdirSync(resourcesDir).filter((f) => f.endsWith('-resource.json'));\n\n const resourcesMap = new Map<string, Resource>();\n for (const filename of resourceFiles) {\n // Extract key from filename: 'review-resource.json' -> 'review'\n const key = filename.replace(/-resource\\.json$/, '');\n const resourcePath = path.join(resourcesDir, filename);\n const resource = JSON.parse(readFileSync(resourcePath, 'utf-8')) as Resource;\n resourcesMap.set(key, resource);\n }\n\n const resourceKeys = Array.from(resourcesMap.keys());\n\n // Auto-discover simulation files\n const simulationsDir = path.join(projectRoot, 'src/simulations');\n const simulationFiles = readdirSync(simulationsDir).filter((f) => f.endsWith('-simulation.json'));\n\n // Build simulations array from discovered files\n const simulations: SimulationWithDist[] = [];\n\n for (const filename of simulationFiles) {\n // Extract simulation key from filename: 'albums-show-simulation.json' -> 'albums-show'\n const simulationKey = filename.replace(/-simulation\\.json$/, '');\n\n // Load simulation data\n const simulationPath = path.join(simulationsDir, filename);\n const simulation = JSON.parse(readFileSync(simulationPath, 'utf-8'));\n\n // Find matching resource by best prefix match\n const resourceKey = findResourceKey(simulationKey, resourceKeys);\n if (!resourceKey) {\n console.warn(\n `No matching resource found for simulation \"${simulationKey}\". ` +\n `Expected a resource file like src/resources/${simulationKey.split('-')[0]}-resource.json`\n );\n continue;\n }\n\n const resource = resourcesMap.get(resourceKey)!;\n\n simulations.push({\n ...simulation,\n name: simulationKey,\n distPath: path.join(projectRoot, `dist/${resourceKey}.js`),\n resource,\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":";;;;;AAgBA,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,gBAAgB,YAAY,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,gBAAgB,CAAC;AAE1F,QAAM,mCAAmB,IAAA;AACzB,aAAW,YAAY,eAAe;AAEpC,UAAM,MAAM,SAAS,QAAQ,oBAAoB,EAAE;AACnD,UAAM,eAAe,KAAK,KAAK,cAAc,QAAQ;AACrD,UAAM,WAAW,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAC/D,iBAAa,IAAI,KAAK,QAAQ;AAAA,EAChC;AAEA,QAAM,eAAe,MAAM,KAAK,aAAa,MAAM;AAGnD,QAAM,iBAAiB,KAAK,KAAK,aAAa,iBAAiB;AAC/D,QAAM,kBAAkB,YAAY,cAAc,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,kBAAkB,CAAC;AAGhG,QAAM,cAAoC,CAAA;AAE1C,aAAW,YAAY,iBAAiB;AAEtC,UAAM,gBAAgB,SAAS,QAAQ,sBAAsB,EAAE;AAG/D,UAAM,iBAAiB,KAAK,KAAK,gBAAgB,QAAQ;AACzD,UAAM,aAAa,KAAK,MAAM,aAAa,gBAAgB,OAAO,CAAC;AAGnE,UAAM,cAAc,gBAAgB,eAAe,YAAY;AAC/D,QAAI,CAAC,aAAa;AAChB,cAAQ;AAAA,QACN,8CAA8C,aAAa,kDACV,cAAc,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,MAAA;AAE9E;AAAA,IACF;AAEA,UAAM,WAAW,aAAa,IAAI,WAAW;AAE7C,gBAAY,KAAK;AAAA,MACf,GAAG;AAAA,MACH,MAAM;AAAA,MACN,UAAU,KAAK,KAAK,aAAa,QAAQ,WAAW,KAAK;AAAA,MACzD;AAAA,IAAA,CACD;AAAA,EACH;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 nodemon or directly to start the MCP server\n *\n * Auto-discovers simulations and resources by file naming convention:\n * - resources/{resource}/{resource}-{tool}-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;"}
@@ -7609,14 +7609,14 @@ const SCREEN_WIDTHS = {
7609
7609
  full: 1024
7610
7610
  };
7611
7611
  const ALLOWED_SCRIPT_ORIGINS = [
7612
- "https://sandbox.sunpeakai.com",
7612
+ "https://sunpeak-prod-app-storage.s3.us-east-2.amazonaws.com",
7613
7613
  "http://localhost",
7614
7614
  "https://localhost",
7615
7615
  "http://127.0.0.1",
7616
7616
  "https://127.0.0.1"
7617
7617
  ];
7618
7618
  const ALLOWED_PARENT_ORIGINS = [
7619
- "https://app.sunpeak.ai",
7619
+ "https://sandbox.sunpeakai.com",
7620
7620
  "http://localhost",
7621
7621
  "https://localhost",
7622
7622
  "http://127.0.0.1",
@@ -8149,31 +8149,24 @@ function IframeResource({ scriptSrc, className, style, csp }) {
8149
8149
  sendUpdate("openai:update");
8150
8150
  }, [sendUpdate]);
8151
8151
  const isValidScriptSrc = useMemo(() => isAllowedScriptSrc(scriptSrc), [scriptSrc]);
8152
- const blobUrl = useMemo(() => {
8152
+ const htmlContent = useMemo(() => {
8153
8153
  if (!isValidScriptSrc) {
8154
8154
  console.error("[IframeResource] Script source not allowed:", scriptSrc);
8155
- const errorHtml = `<!DOCTYPE html><html><body><h1>Error</h1><p>Script source not allowed.</p></body></html>`;
8156
- const blob2 = new Blob([errorHtml], { type: "text/html" });
8157
- return URL.createObjectURL(blob2);
8155
+ return `<!DOCTYPE html><html><body><h1>Error</h1><p>Script source not allowed.</p></body></html>`;
8158
8156
  }
8159
8157
  const absoluteScriptSrc = scriptSrc.startsWith("/") ? `${window.location.origin}${scriptSrc}` : scriptSrc;
8160
8158
  const cspPolicy = generateCSP(csp, absoluteScriptSrc);
8161
8159
  const bridgeScript = generateBridgeScript(ALLOWED_PARENT_ORIGINS);
8162
- const html = injectBridgeScript(
8160
+ return injectBridgeScript(
8163
8161
  generateScriptHtml(absoluteScriptSrc, theme ?? "dark", cspPolicy),
8164
8162
  bridgeScript
8165
8163
  );
8166
- const blob = new Blob([html], { type: "text/html" });
8167
- return URL.createObjectURL(blob);
8168
8164
  }, [scriptSrc, theme, isValidScriptSrc, csp]);
8169
- useEffect(() => {
8170
- return () => URL.revokeObjectURL(blobUrl);
8171
- }, [blobUrl]);
8172
8165
  return /* @__PURE__ */ jsx(
8173
8166
  "iframe",
8174
8167
  {
8175
8168
  ref: iframeRef,
8176
- src: blobUrl,
8169
+ srcDoc: htmlContent,
8177
8170
  className,
8178
8171
  style: {
8179
8172
  border: "none",
@@ -8185,8 +8178,8 @@ function IframeResource({ scriptSrc, className, style, csp }) {
8185
8178
  ...style
8186
8179
  },
8187
8180
  title: "Resource Preview",
8188
- sandbox: "allow-scripts",
8189
- allow: "accelerometer 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; publickey-credentials-get 'none'; usb 'none'; xr-spatial-tracking 'none'"
8181
+ sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox",
8182
+ allow: "local-network-access *; microphone *; midi *; accelerometer 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; payment 'none'; publickey-credentials-get 'none'; usb 'none'; xr-spatial-tracking 'none'"
8190
8183
  }
8191
8184
  );
8192
8185
  }
@@ -9186,4 +9179,4 @@ export {
9186
9179
  getAPI as v,
9187
9180
  resetProviderCache as w
9188
9181
  };
9189
- //# sourceMappingURL=simulator-url-wBi-pko3.js.map
9182
+ //# sourceMappingURL=simulator-url-BZBcq5tc.js.map