sunpeak 0.2.6 → 0.3.2

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 (79) hide show
  1. package/README.md +32 -17
  2. package/dist/chatgpt/chatgpt-simulator-types.d.ts +8 -0
  3. package/dist/chatgpt/chatgpt-simulator.d.ts +11 -0
  4. package/dist/chatgpt/conversation.d.ts +11 -0
  5. package/dist/chatgpt/index.d.ts +3 -0
  6. package/dist/chatgpt/mcp-provider.d.ts +25 -0
  7. package/dist/chatgpt/mock-openai.d.ts +61 -0
  8. package/dist/chatgpt/openai-provider.d.ts +19 -0
  9. package/dist/chatgpt/openai-types.d.ts +81 -0
  10. package/dist/chatgpt/simple-sidebar.d.ts +22 -0
  11. package/dist/chatgpt/theme-provider.d.ts +13 -0
  12. package/dist/hooks/index.d.ts +14 -0
  13. package/dist/hooks/use-display-mode.d.ts +2 -0
  14. package/dist/hooks/use-locale.d.ts +1 -0
  15. package/dist/hooks/use-max-height.d.ts +1 -0
  16. package/dist/hooks/use-mobile.d.ts +1 -0
  17. package/dist/hooks/use-safe-area.d.ts +2 -0
  18. package/dist/hooks/use-theme.d.ts +2 -0
  19. package/dist/hooks/use-tool-input.d.ts +2 -0
  20. package/dist/hooks/use-tool-response-metadata.d.ts +2 -0
  21. package/dist/hooks/use-user-agent.d.ts +2 -0
  22. package/dist/hooks/use-view.d.ts +2 -0
  23. package/dist/hooks/use-widget-api.d.ts +8 -0
  24. package/dist/hooks/use-widget-global.d.ts +9 -0
  25. package/dist/hooks/use-widget-props.d.ts +1 -0
  26. package/dist/hooks/use-widget-state.d.ts +4 -0
  27. package/dist/index.cjs +3310 -666
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.ts +5 -366
  30. package/dist/index.js +3325 -640
  31. package/dist/index.js.map +1 -1
  32. package/dist/lib/index.d.ts +2 -0
  33. package/dist/lib/media-queries.d.ts +3 -0
  34. package/dist/lib/utils.d.ts +2 -0
  35. package/dist/mcp/index.cjs +799 -64
  36. package/dist/mcp/index.cjs.map +1 -1
  37. package/dist/mcp/index.d.ts +1 -12
  38. package/dist/mcp/index.js +786 -44
  39. package/dist/mcp/index.js.map +1 -1
  40. package/dist/mcp/server.d.ts +10 -0
  41. package/dist/mcp/types.d.ts +74 -0
  42. package/dist/providers/index.d.ts +40 -0
  43. package/dist/providers/types.d.ts +71 -0
  44. package/dist/style.css +5014 -0
  45. package/dist/test/setup.d.ts +0 -0
  46. package/dist/types/index.d.ts +2 -0
  47. package/package.json +11 -19
  48. package/template/README.md +3 -6
  49. package/template/dev/main.tsx +0 -1
  50. package/template/mcp/server.ts +1 -1
  51. package/template/package.json +4 -14
  52. package/template/src/App.tsx +7 -8
  53. package/template/src/components/index.ts +2 -2
  54. package/template/src/components/openai-card.test.tsx +73 -0
  55. package/template/src/components/openai-card.tsx +126 -0
  56. package/template/src/components/openai-carousel.test.tsx +84 -0
  57. package/template/src/components/openai-carousel.tsx +178 -0
  58. package/template/src/styles/globals.css +5 -216
  59. package/template/vite.config.build.ts +61 -0
  60. package/template/vite.config.ts +0 -2
  61. package/dist/index.d.cts +0 -366
  62. package/dist/mcp/index.d.cts +0 -12
  63. package/dist/styles/chatgpt/index.css +0 -146
  64. package/dist/styles/globals.css +0 -219
  65. package/template/components.json +0 -21
  66. package/template/dev/styles.css +0 -6
  67. package/template/postcss.config.js +0 -5
  68. package/template/src/components/shadcn/button.tsx +0 -60
  69. package/template/src/components/shadcn/card.tsx +0 -76
  70. package/template/src/components/shadcn/carousel.tsx +0 -260
  71. package/template/src/components/shadcn/index.ts +0 -5
  72. package/template/src/components/shadcn/label.tsx +0 -24
  73. package/template/src/components/shadcn/select.tsx +0 -157
  74. package/template/src/components/sunpeak-card.test.tsx +0 -76
  75. package/template/src/components/sunpeak-card.tsx +0 -171
  76. package/template/src/components/sunpeak-carousel.test.tsx +0 -42
  77. package/template/src/components/sunpeak-carousel.tsx +0 -160
  78. package/template/src/styles/chatgpt.css +0 -146
  79. package/template/tsup.config.ts +0 -50
package/README.md CHANGED
@@ -15,13 +15,15 @@
15
15
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
16
16
  [![React](https://img.shields.io/badge/React-18%20%7C%2019-blue?style=flat-square&logo=react)](https://reactjs.org/)
17
17
 
18
- The ChatGPT Apps UI SDK.
18
+ The ChatGPT Apps SDK.
19
19
 
20
- Build and test your ChatGPT App UI locally with approved React components.
20
+ Build and test your ChatGPT App UI locally with OpenAI apps-sdk-ui React components.
21
21
 
22
22
  ![ChatGPT Simulator](https://sunpeak.ai/images/chatgpt-simulator.png)
23
23
 
24
- ## Quickstart
24
+ ## Quickstart
25
+
26
+ ### New Projects
25
27
 
26
28
  Requirements: Node (20+), pnpm (10+)
27
29
 
@@ -29,25 +31,38 @@ Requirements: Node (20+), pnpm (10+)
29
31
  pnpm dlx sunpeak init
30
32
  ```
31
33
 
34
+ ### Existing Projects
35
+
36
+ Requirements: React (18+), Tailwind 4
37
+
38
+ ```bash
39
+ pnpm add sunpeak
40
+ ```
41
+
32
42
  ## Key Features
33
- - 📺 ChatGPT simulator for rapid UI component development.
34
- - 📚 React component library built on [shadcn](https://ui.shadcn.com/).
35
- - 📱 Interface for custom components that work across genAI platforms.
36
- - 🤝 Styles that fit the [OpenAI design system](https://developers.openai.com/apps-sdk/build/chatgpt-ui).
43
+ - 📺 ChatGPT simulator for local UI component development.
44
+ - 📚 Pre-built component library built on [openai/apps-sdk-ui](https://github.com/openai/apps-sdk-ui).
45
+ - 📱 Interface for cross-platforms MCP UI App development.
46
+ - 🛜 Basic MCP server to serve your UI to ChatGPT prod out-of-the-box.
37
47
  - 🧪 Testing framework that replicates advanced ChatGPT behavior locally.
38
48
 
39
49
  ## Example Component
40
50
  ```tsx
41
- import { SunpeakCard } from "sunpeak";
51
+ import '@/styles/globals.css';
52
+ import { OpenAICard } from "@/components";
42
53
 
43
54
  export default function App() {
44
55
  return (
45
- <SunpeakCard
46
- image="/photo.jpg"
47
- imageAlt="Product"
48
- header="Summer Collection"
49
- button1={{ children: "Shop Now", onClick: () => console.log("Howdy!") }}
50
- />
56
+ <OpenAICard
57
+ image="https://example.com/photo.jpg"
58
+ imageAlt="Lady Bird Lake"
59
+ header="Lady Bird Lake"
60
+ metadata="⭐ 4.5 Austin, TX"
61
+ button1={{ children: "Visit", isPrimary: true, onClick: () => {} }}
62
+ button2={{ children: "Learn More", onClick: () => {} }}
63
+ >
64
+ Scenic lake perfect for kayaking, paddleboarding, and trails.
65
+ </OpenAICard>
51
66
  );
52
67
  }
53
68
  ```
@@ -64,9 +79,9 @@ export default function App() {
64
79
  sunpeak is an npm package consisting of:
65
80
 
66
81
  1. **A CLI utility** for working with sunpeak (`./bin`).
67
- 2. **A `sunpeak` library** (`./src`). This library contains common runtime APIs and testing utilitiesincluding a ChatGPT simulatorto be used as a dependency by sunpeak projects.
68
- 3. **A templated npm package** (`./template`) that is initialized by the CLI to help developers set up sunpeak projects. These projects have the `sunpeak` dependency already wired up alongside a collection of pre-built shadcn UI components (`./template/src/components`) to copy, modify, or use as an example.
69
- 1. Developers build their final UI in the `App` component, which is then built against CSS files that codify the design systems of each of the genAI platforms (of which ChatGPT is the only one today).
82
+ 2. **A `sunpeak` library** (`./src`). This library contains common runtime APIs and testing utilities, including a ChatGPT simulator, to be used as a dependency by sunpeak projects.
83
+ 3. **A templated npm package** (`./template`) that is initialized by the CLI to help developers set up sunpeak projects. These projects have the `sunpeak` dependency already wired up alongside a collection of pre-built UI components (`./template/src/components`) to copy, modify, or use as an example.
84
+ 1. Developers build their UI in the `App` component.
70
85
 
71
86
  ## Contributing
72
87
 
@@ -0,0 +1,8 @@
1
+ import { DisplayMode, Theme } from './openai-types';
2
+ export type ScreenWidth = 'mobile-s' | 'mobile-l' | 'tablet' | 'full';
3
+ export type SimulatorConfig = {
4
+ theme: Theme;
5
+ displayMode: DisplayMode;
6
+ screenWidth: ScreenWidth;
7
+ };
8
+ export declare const SCREEN_WIDTHS: Record<ScreenWidth, number>;
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ interface ChatGPTSimulatorProps {
3
+ children: React.ReactNode;
4
+ appName?: string;
5
+ appIcon?: string;
6
+ userMessage?: string;
7
+ toolOutput?: Record<string, unknown> | null;
8
+ widgetState?: Record<string, unknown> | null;
9
+ }
10
+ export declare function ChatGPTSimulator({ children, appName, appIcon, userMessage, toolOutput, widgetState, }: ChatGPTSimulatorProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,11 @@
1
+ import { ScreenWidth } from './chatgpt-simulator-types';
2
+ import * as React from 'react';
3
+ interface ConversationProps {
4
+ children: React.ReactNode;
5
+ screenWidth: ScreenWidth;
6
+ appName?: string;
7
+ appIcon?: string;
8
+ userMessage?: string;
9
+ }
10
+ export declare function Conversation({ children, screenWidth, appName, appIcon, userMessage, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,3 @@
1
+ export { ChatGPTSimulator } from './chatgpt-simulator';
2
+ export { initMockOpenAI } from './mock-openai';
3
+ export * from './theme-provider';
@@ -0,0 +1,25 @@
1
+ import { Resource, Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import { MCPProviderImplementation, WidgetDescriptorMeta, WidgetInvocationMeta } from '../mcp/types.js';
3
+ /**
4
+ * ChatGPT MCP provider implementation.
5
+ */
6
+ export declare class ChatGPTMCPProvider implements MCPProviderImplementation {
7
+ getWidgetDescriptorMeta(): WidgetDescriptorMeta;
8
+ getWidgetInvocationMeta(): WidgetInvocationMeta;
9
+ readWidgetContent(distPath: string): string;
10
+ getWidgetMimeType(): string;
11
+ getWidgetResourceUri(): string;
12
+ createTool(config: {
13
+ name: string;
14
+ description: string;
15
+ inputSchema: Tool["inputSchema"];
16
+ }): Tool;
17
+ createResource(config: {
18
+ name: string;
19
+ description: string;
20
+ }): Resource;
21
+ }
22
+ /**
23
+ * Get the ChatGPT MCP provider instance.
24
+ */
25
+ export declare function getChatGPTMCPProvider(): MCPProviderImplementation;
@@ -0,0 +1,61 @@
1
+ import { OpenAiGlobals, OpenAiAPI, Theme, DisplayMode, View, ViewMode, UnknownObject } from '../types';
2
+ declare class MockOpenAI implements OpenAiAPI, OpenAiGlobals {
3
+ theme: Theme;
4
+ userAgent: {
5
+ device: {
6
+ type: "desktop";
7
+ };
8
+ capabilities: {
9
+ hover: boolean;
10
+ touch: boolean;
11
+ };
12
+ };
13
+ locale: string;
14
+ maxHeight: number;
15
+ displayMode: DisplayMode;
16
+ safeArea: {
17
+ insets: {
18
+ top: number;
19
+ bottom: number;
20
+ left: number;
21
+ right: number;
22
+ };
23
+ };
24
+ view: View | null;
25
+ toolInput: Record<string, unknown>;
26
+ toolOutput: Record<string, unknown> | null;
27
+ toolResponseMetadata: Record<string, unknown> | null;
28
+ widgetState: Record<string, unknown> | null;
29
+ callTool(name: string, args: Record<string, unknown>): Promise<{
30
+ result: string;
31
+ }>;
32
+ sendFollowUpMessage(args: {
33
+ prompt: string;
34
+ }): Promise<void>;
35
+ openExternal(payload: {
36
+ href: string;
37
+ }): void;
38
+ requestDisplayMode(args: {
39
+ mode: DisplayMode;
40
+ }): Promise<{
41
+ mode: DisplayMode;
42
+ }>;
43
+ requestModal(args: {
44
+ mode: ViewMode;
45
+ params?: UnknownObject;
46
+ }): Promise<void>;
47
+ notifyIntrinsicHeight(height: number): void;
48
+ setWidgetState(state: Record<string, unknown>): Promise<void>;
49
+ setTheme(theme: Theme): void;
50
+ setDisplayMode(displayMode: DisplayMode): void;
51
+ setToolOutput(toolOutput: Record<string, unknown> | null): void;
52
+ setWidgetStateExternal(widgetState: Record<string, unknown> | null): void;
53
+ emitUpdate(globals: Partial<OpenAiGlobals>): void;
54
+ }
55
+ export declare function initMockOpenAI(initialData?: {
56
+ theme?: Theme;
57
+ displayMode?: DisplayMode;
58
+ toolOutput?: Record<string, unknown> | null;
59
+ widgetState?: Record<string, unknown> | null;
60
+ }): MockOpenAI;
61
+ export type { MockOpenAI };
@@ -0,0 +1,19 @@
1
+ import { WidgetProvider, WidgetGlobals, WidgetAPI } from '../providers/types';
2
+ /**
3
+ * Check if the OpenAI provider is available.
4
+ */
5
+ export declare function isOpenAiAvailable(): boolean;
6
+ /**
7
+ * OpenAI provider implementation.
8
+ */
9
+ declare class OpenAiProvider implements WidgetProvider {
10
+ readonly id = "openai";
11
+ getGlobal<K extends keyof WidgetGlobals>(key: K): WidgetGlobals[K] | null;
12
+ subscribe(key: keyof WidgetGlobals, onChange: () => void): () => void;
13
+ getAPI(): WidgetAPI | null;
14
+ }
15
+ /**
16
+ * Get the OpenAI provider instance (singleton).
17
+ */
18
+ export declare function getOpenAiProvider(): OpenAiProvider;
19
+ export {};
@@ -0,0 +1,81 @@
1
+ export type UnknownObject = Record<string, unknown>;
2
+ export type Theme = 'light' | 'dark';
3
+ export type SafeAreaInsets = {
4
+ top: number;
5
+ bottom: number;
6
+ left: number;
7
+ right: number;
8
+ };
9
+ export type SafeArea = {
10
+ insets: SafeAreaInsets;
11
+ };
12
+ export type DeviceType = 'mobile' | 'tablet' | 'desktop' | 'unknown';
13
+ export type UserAgent = {
14
+ device: {
15
+ type: DeviceType;
16
+ };
17
+ capabilities: {
18
+ hover: boolean;
19
+ touch: boolean;
20
+ };
21
+ };
22
+ export type DisplayMode = 'pip' | 'inline' | 'fullscreen';
23
+ export type RequestDisplayMode = (args: {
24
+ mode: DisplayMode;
25
+ }) => Promise<{
26
+ mode: DisplayMode;
27
+ }>;
28
+ export type ViewMode = 'modal' | 'default';
29
+ export type View = {
30
+ mode: ViewMode;
31
+ params?: UnknownObject;
32
+ };
33
+ export type CallToolResponse = {
34
+ result: string;
35
+ };
36
+ export type CallTool = (name: string, args: Record<string, unknown>) => Promise<CallToolResponse>;
37
+ export type OpenAiGlobals<ToolInput = UnknownObject, ToolOutput = UnknownObject, ToolResponseMetadata = UnknownObject, WidgetState = UnknownObject> = {
38
+ theme: Theme;
39
+ userAgent: UserAgent;
40
+ locale: string;
41
+ maxHeight: number;
42
+ displayMode: DisplayMode;
43
+ safeArea: SafeArea;
44
+ view: View | null;
45
+ toolInput: ToolInput;
46
+ toolOutput: ToolOutput | null;
47
+ toolResponseMetadata: ToolResponseMetadata | null;
48
+ widgetState: WidgetState | null;
49
+ setWidgetState: (state: WidgetState) => Promise<void>;
50
+ };
51
+ export type RequestModal = (args: {
52
+ mode: ViewMode;
53
+ params?: UnknownObject;
54
+ }) => Promise<void>;
55
+ export type NotifyIntrinsicHeight = (height: number) => void;
56
+ export type OpenAiAPI = {
57
+ callTool: CallTool;
58
+ sendFollowUpMessage: (args: {
59
+ prompt: string;
60
+ }) => Promise<void>;
61
+ openExternal(payload: {
62
+ href: string;
63
+ }): void;
64
+ requestDisplayMode: RequestDisplayMode;
65
+ requestModal: RequestModal;
66
+ notifyIntrinsicHeight: NotifyIntrinsicHeight;
67
+ };
68
+ export declare const SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
69
+ export declare class SetGlobalsEvent extends CustomEvent<{
70
+ globals: Partial<OpenAiGlobals>;
71
+ }> {
72
+ readonly type = "openai:set_globals";
73
+ }
74
+ declare global {
75
+ interface Window {
76
+ openai: OpenAiAPI & OpenAiGlobals;
77
+ }
78
+ interface WindowEventMap {
79
+ [SET_GLOBALS_EVENT_TYPE]: SetGlobalsEvent;
80
+ }
81
+ }
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ interface SimpleSidebarProps {
3
+ children: React.ReactNode;
4
+ controls: React.ReactNode;
5
+ }
6
+ export declare function SimpleSidebar({ children, controls }: SimpleSidebarProps): import("react/jsx-runtime").JSX.Element;
7
+ interface SidebarControlProps {
8
+ label: string;
9
+ children: React.ReactNode;
10
+ }
11
+ export declare function SidebarControl({ label, children }: SidebarControlProps): import("react/jsx-runtime").JSX.Element;
12
+ interface SidebarSelectProps {
13
+ value: string;
14
+ onChange: (value: string) => void;
15
+ options: Array<{
16
+ value: string;
17
+ label: string;
18
+ }>;
19
+ placeholder?: string;
20
+ }
21
+ export declare function SidebarSelect({ value, onChange, options, placeholder }: SidebarSelectProps): import("react/jsx-runtime").JSX.Element;
22
+ export {};
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ type Theme = "light" | "dark";
3
+ type ThemeProviderProps = {
4
+ children: React.ReactNode;
5
+ defaultTheme?: Theme;
6
+ theme?: Theme;
7
+ };
8
+ type ThemeProviderState = {
9
+ theme: Theme;
10
+ };
11
+ export declare function ThemeProvider({ children, defaultTheme, theme: controlledTheme, ...props }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare const useThemeContext: () => ThemeProviderState;
13
+ export {};
@@ -0,0 +1,14 @@
1
+ export { useWidgetGlobal } from './use-widget-global';
2
+ export { useWidgetAPI } from './use-widget-api';
3
+ export { useDisplayMode } from './use-display-mode';
4
+ export { useLocale } from './use-locale';
5
+ export { useMaxHeight } from './use-max-height';
6
+ export { useIsMobile } from './use-mobile';
7
+ export { useSafeArea } from './use-safe-area';
8
+ export { useTheme } from './use-theme';
9
+ export { useToolInput } from './use-tool-input';
10
+ export { useToolResponseMetadata } from './use-tool-response-metadata';
11
+ export { useUserAgent } from './use-user-agent';
12
+ export { useView } from './use-view';
13
+ export { useWidgetProps } from './use-widget-props';
14
+ export { useWidgetState } from './use-widget-state';
@@ -0,0 +1,2 @@
1
+ import { DisplayMode } from '../types';
2
+ export declare const useDisplayMode: () => DisplayMode | null;
@@ -0,0 +1 @@
1
+ export declare const useLocale: () => string | null;
@@ -0,0 +1 @@
1
+ export declare const useMaxHeight: () => number | null;
@@ -0,0 +1 @@
1
+ export declare function useIsMobile(): boolean;
@@ -0,0 +1,2 @@
1
+ import { SafeArea } from '../types';
2
+ export declare const useSafeArea: () => SafeArea | null;
@@ -0,0 +1,2 @@
1
+ import { Theme } from '../types';
2
+ export declare const useTheme: () => Theme | null;
@@ -0,0 +1,2 @@
1
+ import { UnknownObject } from '../types';
2
+ export declare function useToolInput<T extends UnknownObject = UnknownObject>(): T | null;
@@ -0,0 +1,2 @@
1
+ import { UnknownObject } from '../types';
2
+ export declare function useToolResponseMetadata<T extends UnknownObject = UnknownObject>(): T | null;
@@ -0,0 +1,2 @@
1
+ import { UserAgent } from '../types';
2
+ export declare const useUserAgent: () => UserAgent | null;
@@ -0,0 +1,2 @@
1
+ import { View } from '../types';
2
+ export declare function useView(): View | null;
@@ -0,0 +1,8 @@
1
+ import { WidgetAPI } from '../providers';
2
+ /**
3
+ * Hook to get the widget runtime API.
4
+ * Automatically detects and uses the appropriate provider (OpenAI, etc.).
5
+ *
6
+ * @returns The API object, or null if not available.
7
+ */
8
+ export declare function useWidgetAPI(): WidgetAPI | null;
@@ -0,0 +1,9 @@
1
+ import { WidgetGlobals } from '../providers';
2
+ /**
3
+ * Hook to read and subscribe to a global property from the widget runtime.
4
+ * Automatically detects and uses the appropriate provider (OpenAI, etc.).
5
+ *
6
+ * @param key - The global property key to read.
7
+ * @returns The current value, or null if not available.
8
+ */
9
+ export declare function useWidgetGlobal<K extends keyof WidgetGlobals>(key: K): WidgetGlobals[K] | null;
@@ -0,0 +1 @@
1
+ export declare function useWidgetProps<T extends Record<string, unknown>>(defaultState?: T | (() => T)): T;
@@ -0,0 +1,4 @@
1
+ import { SetStateAction } from 'react';
2
+ import { UnknownObject } from '../types';
3
+ export declare function useWidgetState<T extends UnknownObject>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
4
+ export declare function useWidgetState<T extends UnknownObject>(defaultState?: T | (() => T | null) | null): readonly [T | null, (state: SetStateAction<T | null>) => void];