sunpeak 0.6.1 → 0.6.5

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 (59) hide show
  1. package/bin/sunpeak.js +133 -6
  2. package/dist/chatgpt/conversation.d.ts +2 -1
  3. package/dist/index.cjs +24 -4
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +24 -4
  6. package/dist/index.js.map +1 -1
  7. package/dist/mcp/entry.cjs +2 -2
  8. package/dist/mcp/entry.cjs.map +1 -1
  9. package/dist/mcp/entry.js +2 -2
  10. package/dist/mcp/entry.js.map +1 -1
  11. package/dist/mcp/index.cjs +1 -1
  12. package/dist/mcp/index.js +1 -1
  13. package/dist/{server-DpriZ4jT.cjs → server-CQGbJWbk.cjs} +17 -8
  14. package/dist/{server-DpriZ4jT.cjs.map → server-CQGbJWbk.cjs.map} +1 -1
  15. package/dist/{server-SBlanUcf.js → server-DGCvp1RA.js} +17 -8
  16. package/dist/{server-SBlanUcf.js.map → server-DGCvp1RA.js.map} +1 -1
  17. package/dist/style.css +444 -0
  18. package/package.json +1 -1
  19. package/template/.sunpeak/dev.tsx +1 -1
  20. package/template/dist/chatgpt/albums.js +2 -2
  21. package/template/dist/chatgpt/carousel.js +1 -1
  22. package/template/dist/chatgpt/counter.js +1 -1
  23. package/template/dist/chatgpt/pizzaz.js +3034 -0
  24. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Avatar.js +97 -0
  25. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Avatar.js.map +7 -0
  26. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +3 -3
  27. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +1 -1
  28. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +16 -16
  29. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Textarea.js +3 -3
  30. package/template/node_modules/.vite/deps/_metadata.json +45 -33
  31. package/template/node_modules/.vite/deps/{chunk-DQAZDQU3.js → chunk-LR7NKCX5.js} +8 -8
  32. package/template/node_modules/.vite/deps/mapbox-gl.js +32835 -0
  33. package/template/node_modules/.vite/deps/mapbox-gl.js.map +7 -0
  34. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  35. package/template/package.json +1 -0
  36. package/template/src/components/album/album-carousel.test.tsx +84 -0
  37. package/template/src/components/album/album-carousel.tsx +168 -0
  38. package/template/src/components/album/albums.test.tsx +2 -2
  39. package/template/src/components/album/albums.tsx +3 -3
  40. package/template/src/components/album/index.ts +1 -0
  41. package/template/src/components/carousel/index.ts +1 -0
  42. package/template/src/components/index.ts +1 -1
  43. package/template/src/components/pizzaz/index.ts +6 -0
  44. package/template/src/components/pizzaz/map-view.tsx +212 -0
  45. package/template/src/components/pizzaz/pizzaz.tsx +145 -0
  46. package/template/src/components/pizzaz/place-card.tsx +55 -0
  47. package/template/src/components/pizzaz/place-carousel.tsx +45 -0
  48. package/template/src/components/pizzaz/place-inspector.tsx +132 -0
  49. package/template/src/components/pizzaz/place-list.tsx +90 -0
  50. package/template/src/resources/carousel-resource.test.tsx +1 -4
  51. package/template/src/resources/carousel-resource.tsx +1 -2
  52. package/template/src/resources/index.ts +1 -0
  53. package/template/src/resources/pizzaz-resource.tsx +32 -0
  54. package/template/src/simulations/index.ts +2 -0
  55. package/template/src/simulations/pizzaz-simulation.ts +177 -0
  56. package/template/src/components/card/index.ts +0 -1
  57. /package/template/node_modules/.vite/deps/{chunk-DQAZDQU3.js.map → chunk-LR7NKCX5.js.map} +0 -0
  58. /package/template/src/components/{card → carousel}/card.test.tsx +0 -0
  59. /package/template/src/components/{card → carousel}/card.tsx +0 -0
package/bin/sunpeak.js CHANGED
@@ -27,7 +27,82 @@ function checkPackageJson() {
27
27
  }
28
28
  }
29
29
 
30
- async function init(projectName) {
30
+ function parseResourcesInput(input) {
31
+ const VALID_RESOURCES = ['albums', 'carousel', 'counter', 'pizzaz'];
32
+
33
+ // If no input, return all resources
34
+ if (!input || input.trim() === '') {
35
+ return VALID_RESOURCES;
36
+ }
37
+
38
+ // Split by comma or space and trim
39
+ const tokens = input
40
+ .toLowerCase()
41
+ .split(/[,\s]+/)
42
+ .map((s) => s.trim())
43
+ .filter((s) => s.length > 0);
44
+
45
+ // Validate tokens
46
+ const invalid = tokens.filter((t) => !VALID_RESOURCES.includes(t));
47
+ if (invalid.length > 0) {
48
+ console.error(`Error: Invalid resource(s): ${invalid.join(', ')}`);
49
+ console.error(`Valid resources are: ${VALID_RESOURCES.join(', ')}`);
50
+ process.exit(1);
51
+ }
52
+
53
+ // Remove duplicates
54
+ return [...new Set(tokens)];
55
+ }
56
+
57
+ function updateIndexFiles(targetDir, selectedResources) {
58
+ // Map resource names to their component/export names
59
+ const resourceMap = {
60
+ albums: { component: 'album', resourceClass: 'AlbumsResource', simulation: 'albums' },
61
+ carousel: { component: 'carousel', resourceClass: 'CarouselResource', simulation: 'carousel' },
62
+ counter: { component: null, resourceClass: 'CounterResource', simulation: 'counter' },
63
+ pizzaz: { component: 'pizzaz', resourceClass: 'PizzazResource', simulation: 'pizzaz' },
64
+ };
65
+
66
+ // Update components/index.ts
67
+ const componentsIndexPath = join(targetDir, 'src', 'components', 'index.ts');
68
+ const componentExports = selectedResources
69
+ .map((r) => resourceMap[r].component)
70
+ .filter((comp) => comp !== null) // Filter out null components
71
+ .filter((v, i, a) => a.indexOf(v) === i) // Remove duplicates
72
+ .map((comp) => `export * from './${comp}';`)
73
+ .join('\n');
74
+ writeFileSync(componentsIndexPath, componentExports + '\n');
75
+
76
+ // Update resources/index.ts
77
+ const resourcesIndexPath = join(targetDir, 'src', 'resources', 'index.ts');
78
+ const resourceExports = selectedResources
79
+ .map((r) => `export { ${resourceMap[r].resourceClass} } from './${r}-resource';`)
80
+ .join('\n');
81
+ writeFileSync(resourcesIndexPath, resourceExports + '\n');
82
+
83
+ // Update simulations/index.ts
84
+ const simulationsIndexPath = join(targetDir, 'src', 'simulations', 'index.ts');
85
+ const simulationImports = selectedResources
86
+ .map((r) => `import { ${r}Simulation } from './${r}-simulation.js';`)
87
+ .join('\n');
88
+ const simulationExports = selectedResources.map((r) => ` ${r}: ${r}Simulation,`).join('\n');
89
+ const simulationsContent = `/**
90
+ * Server-safe simulation configurations
91
+ *
92
+ * This file contains only metadata and can be safely imported in Node.js contexts
93
+ * (like MCP servers) without causing issues with CSS imports or React components.
94
+ */
95
+
96
+ ${simulationImports}
97
+
98
+ export const SIMULATIONS = {
99
+ ${simulationExports}
100
+ } as const;
101
+ `;
102
+ writeFileSync(simulationsIndexPath, simulationsContent);
103
+ }
104
+
105
+ async function init(projectName, resourcesArg) {
31
106
  if (!projectName) {
32
107
  projectName = await prompt('☀️ 🏔️ Project name [my-app]: ');
33
108
  if (!projectName) {
@@ -40,6 +115,18 @@ async function init(projectName) {
40
115
  process.exit(1);
41
116
  }
42
117
 
118
+ // Use resources from args or ask for them
119
+ let resourcesInput;
120
+ if (resourcesArg) {
121
+ resourcesInput = resourcesArg;
122
+ console.log(`☀️ 🏔️ Resources: ${resourcesArg}`);
123
+ } else {
124
+ resourcesInput = await prompt(
125
+ '☀️ 🏔️ Resources (UIs) to include [albums, carousel, counter, pizzaz]: '
126
+ );
127
+ }
128
+ const selectedResources = parseResourcesInput(resourcesInput);
129
+
43
130
  const targetDir = join(process.cwd(), projectName);
44
131
 
45
132
  if (existsSync(targetDir)) {
@@ -53,11 +140,45 @@ async function init(projectName) {
53
140
 
54
141
  mkdirSync(targetDir, { recursive: true });
55
142
 
143
+ // Map resource names to their component directory names
144
+ const resourceComponentMap = {
145
+ albums: 'album',
146
+ carousel: 'carousel',
147
+ counter: null, // Counter doesn't have a component directory
148
+ pizzaz: 'pizzaz',
149
+ };
150
+
56
151
  cpSync(templateDir, targetDir, {
57
152
  recursive: true,
58
153
  filter: (src) => {
59
154
  const name = basename(src);
60
- return name !== 'node_modules' && name !== 'pnpm-lock.yaml';
155
+
156
+ // Skip node_modules and lock file
157
+ if (name === 'node_modules' || name === 'pnpm-lock.yaml') {
158
+ return false;
159
+ }
160
+
161
+ // Filter resource files based on selection
162
+ const VALID_RESOURCES = ['albums', 'carousel', 'counter', 'pizzaz'];
163
+ const excludedResources = VALID_RESOURCES.filter((r) => !selectedResources.includes(r));
164
+
165
+ for (const resource of excludedResources) {
166
+ // Skip resource files
167
+ if (name === `${resource}-resource.tsx` || name === `${resource}-resource.test.tsx`) {
168
+ return false;
169
+ }
170
+ // Skip simulation files
171
+ if (name === `${resource}-simulation.ts`) {
172
+ return false;
173
+ }
174
+ // Skip component directories (map resource name to component dir name)
175
+ const componentDirName = resourceComponentMap[resource];
176
+ if (componentDirName && src.includes('/components/') && name === componentDirName) {
177
+ return false;
178
+ }
179
+ }
180
+
181
+ return true;
61
182
  },
62
183
  });
63
184
 
@@ -88,6 +209,9 @@ async function init(projectName) {
88
209
 
89
210
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
90
211
 
212
+ // Update index.ts files based on selected resources
213
+ updateIndexFiles(targetDir, selectedResources);
214
+
91
215
  console.log(`
92
216
  Done! To get started:
93
217
 
@@ -119,7 +243,7 @@ const [, , command, ...args] = process.argv;
119
243
 
120
244
  switch (command) {
121
245
  case 'new':
122
- await init(args[0]);
246
+ await init(args[0], args[1]);
123
247
  break;
124
248
 
125
249
  case 'dev':
@@ -149,8 +273,11 @@ const [, , command, ...args] = process.argv;
149
273
  ☀️ 🏔️ sunpeak - The MCP App framework
150
274
 
151
275
  Usage:
152
- npx sunpeak new [name] Create a new project (no install needed)
153
- pnpm dlx sunpeak new Alternative with pnpm
276
+ npx sunpeak new [name] [resources] Create a new project (no install needed)
277
+ pnpm dlx sunpeak new Alternative with pnpm
278
+
279
+ Resources: albums, carousel, counter, pizzaz (comma/space separated)
280
+ Example: npx sunpeak new my-app "albums,carousel"
154
281
 
155
282
  Inside your project, use npm scripts:
156
283
  pnpm dev Start development server
@@ -159,7 +286,7 @@ Inside your project, use npm scripts:
159
286
  pnpm test Run tests
160
287
 
161
288
  Direct CLI commands (when sunpeak is installed):
162
- sunpeak new [name] Create a new project
289
+ sunpeak new [name] [resources] Create a new project
163
290
  sunpeak dev Start dev server
164
291
  sunpeak build Build resources
165
292
  sunpeak mcp Start MCP server
@@ -6,6 +6,7 @@ interface ConversationProps {
6
6
  appName?: string;
7
7
  appIcon?: string;
8
8
  userMessage?: string;
9
+ resourceMeta?: Record<string, unknown>;
9
10
  }
10
- export declare function Conversation({ children, screenWidth, appName, appIcon, userMessage, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function Conversation({ children, screenWidth, appName, appIcon, userMessage, resourceMeta, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
11
12
  export {};
package/dist/index.cjs CHANGED
@@ -7572,9 +7572,10 @@ const SCREEN_WIDTHS = {
7572
7572
  function Conversation({
7573
7573
  children,
7574
7574
  screenWidth,
7575
- appName = "Sunpeak App",
7575
+ appName = "Sunpeak",
7576
7576
  appIcon,
7577
- userMessage = "What have you got for me today?"
7577
+ userMessage = "What have you got for me today?",
7578
+ resourceMeta
7578
7579
  }) {
7579
7580
  const displayMode = useDisplayMode() ?? "inline";
7580
7581
  const api = useWidgetAPI();
@@ -7608,7 +7609,25 @@ function Conversation({
7608
7609
  }
7609
7610
  ) }),
7610
7611
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-primary flex items-center justify-center text-base", children: appName }),
7611
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end" })
7612
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
7613
+ Button,
7614
+ {
7615
+ variant: "outline",
7616
+ color: "primary",
7617
+ className: "bg-token-bg-primary",
7618
+ onClick: () => {
7619
+ const widgetDomain = resourceMeta == null ? void 0 : resourceMeta["openai/widgetDomain"];
7620
+ if ((api == null ? void 0 : api.openExternal) && widgetDomain) {
7621
+ api.openExternal({ href: widgetDomain });
7622
+ }
7623
+ },
7624
+ children: [
7625
+ appIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "me-2 h-4 w-4 flex items-center justify-center", children: appIcon }),
7626
+ "Open in ",
7627
+ appName
7628
+ ]
7629
+ }
7630
+ ) })
7612
7631
  ] }),
7613
7632
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative overflow-hidden flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full max-w-full overflow-auto", children }) }),
7614
7633
  /* @__PURE__ */ jsxRuntime.jsx("footer", { className: "bg-surface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[48rem] mx-auto px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -7917,7 +7936,7 @@ const DEFAULT_DISPLAY_MODE = "inline";
7917
7936
  function ChatGPTSimulator({
7918
7937
  children,
7919
7938
  simulations = [],
7920
- appName = "Sunpeak App",
7939
+ appName = "Sunpeak",
7921
7940
  appIcon
7922
7941
  }) {
7923
7942
  const [screenWidth, setScreenWidth] = React__namespace.useState("full");
@@ -8411,6 +8430,7 @@ function ChatGPTSimulator({
8411
8430
  appName,
8412
8431
  appIcon,
8413
8432
  userMessage,
8433
+ resourceMeta: selectedSim == null ? void 0 : selectedSim.resource._meta,
8414
8434
  children: content
8415
8435
  },
8416
8436
  selectedKey