sunpeak 0.4.4 → 0.5.3
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.
- package/dist/chatgpt/chatgpt-simulator-types.d.ts +1 -1
- package/dist/chatgpt/chatgpt-simulator.d.ts +4 -15
- package/dist/chatgpt/index.d.ts +1 -1
- package/dist/chatgpt/mock-openai.d.ts +4 -16
- package/dist/index.cjs +69 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -40
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.cjs +76 -112
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.d.ts +2 -1
- package/dist/mcp/index.js +76 -112
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -4
- package/dist/mcp/types.d.ts +16 -62
- package/dist/providers/index.d.ts +1 -3
- package/dist/providers/openai/index.d.ts +7 -0
- package/dist/{chatgpt/openai-provider.d.ts → providers/openai/provider.d.ts} +1 -1
- package/dist/{chatgpt/openai-types.d.ts → providers/openai/types.d.ts} +3 -32
- package/dist/providers/types.d.ts +4 -5
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/provider-detection.d.ts +17 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/runtime.d.ts +34 -0
- package/dist/types/simulation.d.ts +47 -0
- package/package.json +2 -2
- package/template/README.md +6 -7
- package/template/dev/main.tsx +38 -3
- package/template/mcp/server.ts +9 -6
- package/template/nodemon.json +7 -0
- package/template/package.json +4 -2
- package/template/scripts/build-all.mjs +108 -0
- package/template/scripts/validate.mjs +16 -7
- package/template/src/components/index.ts +1 -1
- package/template/src/components/resources/AlbumsResource.tsx +13 -0
- package/template/src/components/{apps/PlacesApp.tsx → resources/CarouselResource.tsx} +11 -10
- package/template/src/components/{apps/App.tsx → resources/CounterResource.tsx} +5 -14
- package/template/src/components/resources/index.ts +3 -0
- package/template/src/index-resource.tsx +11 -0
- package/template/src/simulations/albums-simulation.ts +35 -9
- package/template/src/simulations/carousel-simulation.ts +35 -9
- package/template/src/simulations/counter-simulation.ts +41 -0
- package/template/src/simulations/index.ts +10 -10
- package/template/vite.config.build.ts +21 -15
- package/dist/chatgpt/mcp-provider.d.ts +0 -25
- package/dist/style.css +0 -4420
- package/template/src/components/apps/AlbumsApp.tsx +0 -13
- package/template/src/components/apps/active-app.ts +0 -11
- package/template/src/components/apps/index.ts +0 -3
- package/template/src/index.chatgpt.tsx +0 -9
- package/template/src/index.ts +0 -2
- package/template/src/simulations/app-configs.ts +0 -30
- package/template/src/simulations/app-simulation.ts +0 -15
- package/template/src/simulations/simulations.ts +0 -74
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
2
|
import { useWidgetProps } from "sunpeak"
|
|
3
|
-
import { Carousel
|
|
3
|
+
import { Carousel } from "../carousel/carousel"
|
|
4
|
+
import { Card } from "../card/card"
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Production-ready
|
|
7
|
+
* Production-ready Carousel Resource
|
|
7
8
|
*
|
|
8
|
-
* This
|
|
9
|
+
* This resource displays places in a carousel layout with cards.
|
|
9
10
|
* Can be dropped into any production environment without changes.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
interface CarouselCard {
|
|
13
14
|
id: string
|
|
14
15
|
name: string
|
|
15
16
|
rating: number
|
|
@@ -19,17 +20,17 @@ export interface Place {
|
|
|
19
20
|
description: string
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
places:
|
|
23
|
+
interface CarouselData extends Record<string, unknown> {
|
|
24
|
+
places: CarouselCard[]
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export const
|
|
27
|
-
const data = useWidgetProps<
|
|
27
|
+
export const CarouselResource = React.forwardRef<HTMLDivElement>((_props, ref) => {
|
|
28
|
+
const data = useWidgetProps<CarouselData>(() => ({ places: [] }))
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
31
|
<div ref={ref}>
|
|
31
32
|
<Carousel gap={16} showArrows={true} showEdgeGradients={true} cardWidth={220}>
|
|
32
|
-
{(data.places || []).map((place) => (
|
|
33
|
+
{(data.places || []).map((place: CarouselCard) => (
|
|
33
34
|
<Card
|
|
34
35
|
key={place.id}
|
|
35
36
|
image={place.image}
|
|
@@ -54,4 +55,4 @@ export const PlacesApp = React.forwardRef<HTMLDivElement>((_props, ref) => {
|
|
|
54
55
|
</div>
|
|
55
56
|
)
|
|
56
57
|
})
|
|
57
|
-
|
|
58
|
+
CarouselResource.displayName = "CarouselResource"
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import '../../styles/globals.css';
|
|
2
|
-
|
|
3
1
|
import { useWidgetState } from 'sunpeak';
|
|
4
2
|
import { Button } from '@openai/apps-sdk-ui/components/Button';
|
|
5
3
|
|
|
@@ -8,19 +6,12 @@ interface CounterState extends Record<string, unknown> {
|
|
|
8
6
|
}
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* This is a simple counter app to get you started.
|
|
14
|
-
* Try building your own app here!
|
|
9
|
+
* Production-ready Counter Resource
|
|
15
10
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* - Check out the components folder for reusable components
|
|
19
|
-
* - Use sunpeak hooks for state management and display modes
|
|
20
|
-
* - Edit this file and see your changes live
|
|
21
|
-
* - Edit ../../simulations/app-simulation.tsx to customize your simulation
|
|
11
|
+
* This resource displays a counter to demonstrate useWidgetState.
|
|
12
|
+
* Can be dropped into any production environment without changes.
|
|
22
13
|
*/
|
|
23
|
-
export function
|
|
14
|
+
export function CounterResource() {
|
|
24
15
|
const [widgetState, setWidgetState] = useWidgetState<CounterState>(() => ({
|
|
25
16
|
count: 0,
|
|
26
17
|
}));
|
|
@@ -46,7 +37,7 @@ export function App() {
|
|
|
46
37
|
Welcome to Sunpeak!
|
|
47
38
|
</h1>
|
|
48
39
|
<p className="text-secondary">
|
|
49
|
-
Build your
|
|
40
|
+
Build your MCP resource here
|
|
50
41
|
</p>
|
|
51
42
|
</div>
|
|
52
43
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import '../src/styles/globals.css';
|
|
2
|
+
// @ts-expect-error - Template file with placeholders
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
import { createRoot } from 'react-dom/client';
|
|
5
|
+
// RESOURCE_IMPORT
|
|
6
|
+
|
|
7
|
+
// Mount the resource
|
|
8
|
+
const root = document.getElementById('root');
|
|
9
|
+
if (root) {
|
|
10
|
+
// RESOURCE_MOUNT
|
|
11
|
+
}
|
|
@@ -116,14 +116,40 @@ const albumsData = {
|
|
|
116
116
|
]
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
-
export const
|
|
120
|
-
appName: 'Pizzaz',
|
|
121
|
-
value: 'albums',
|
|
122
|
-
label: 'Albums',
|
|
123
|
-
appIcon: '🍕',
|
|
119
|
+
export const albumsSimulation = {
|
|
124
120
|
userMessage: 'Pizza time',
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
|
|
122
|
+
// MCP Tool protocol - official Tool type from MCP SDK used in ListTools response
|
|
123
|
+
tool: {
|
|
124
|
+
name: 'show-albums',
|
|
125
|
+
description: 'Show photo albums',
|
|
126
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false } as const,
|
|
127
|
+
title: 'Show Albums',
|
|
128
|
+
annotations: { readOnlyHint: true },
|
|
129
|
+
_meta: {
|
|
130
|
+
'openai/outputTemplate': 'ui://AlbumsResource.tsx',
|
|
131
|
+
'openai/toolInvocation/invoking': 'Loading albums',
|
|
132
|
+
'openai/toolInvocation/invoked': 'Album loaded',
|
|
133
|
+
'openai/widgetAccessible': true,
|
|
134
|
+
'openai/resultCanProduceWidget': true,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// MCP Resource protocol - official Resource type from MCP SDK used in ListResources response
|
|
139
|
+
// resource.name is used as the simulation identifier
|
|
140
|
+
// resource.title is used as the simulation display label
|
|
141
|
+
resource: {
|
|
142
|
+
uri: 'ui://AlbumsResource.tsx',
|
|
143
|
+
name: 'albums',
|
|
144
|
+
title: 'Albums',
|
|
145
|
+
description: 'Show photo albums widget markup',
|
|
146
|
+
mimeType: 'text/html+skybridge',
|
|
147
|
+
_meta: {},
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// MCP CallTool protocol - data for CallTool response
|
|
151
|
+
toolCall: {
|
|
152
|
+
structuredContent: albumsData,
|
|
153
|
+
_meta: {},
|
|
154
|
+
},
|
|
129
155
|
} as const;
|
|
@@ -53,14 +53,40 @@ const placesData = {
|
|
|
53
53
|
]
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
export const
|
|
57
|
-
appName: 'Splorin',
|
|
58
|
-
value: 'carousel',
|
|
59
|
-
label: 'Carousel',
|
|
60
|
-
appIcon: '✈️',
|
|
56
|
+
export const carouselSimulation = {
|
|
61
57
|
userMessage: 'Show me popular places to visit in Austin Texas',
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
|
|
59
|
+
// MCP Tool protocol - official Tool type from MCP SDK used in ListTools response
|
|
60
|
+
tool: {
|
|
61
|
+
name: 'show-carousel',
|
|
62
|
+
description: 'Show popular places to visit',
|
|
63
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false } as const,
|
|
64
|
+
title: 'Show Carousel',
|
|
65
|
+
annotations: { readOnlyHint: true },
|
|
66
|
+
_meta: {
|
|
67
|
+
'openai/outputTemplate': 'ui://CarouselResource.tsx',
|
|
68
|
+
'openai/toolInvocation/invoking': 'Loading carousel',
|
|
69
|
+
'openai/toolInvocation/invoked': 'Carousel loaded',
|
|
70
|
+
'openai/widgetAccessible': true,
|
|
71
|
+
'openai/resultCanProduceWidget': true,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// MCP Resource protocol - official Resource type from MCP SDK used in ListResources response
|
|
76
|
+
// resource.name is used as the simulation identifier
|
|
77
|
+
// resource.title is used as the simulation display label
|
|
78
|
+
resource: {
|
|
79
|
+
uri: 'ui://CarouselResource.tsx',
|
|
80
|
+
name: 'carousel',
|
|
81
|
+
title: 'Carousel',
|
|
82
|
+
description: 'Show popular places to visit widget markup',
|
|
83
|
+
mimeType: 'text/html+skybridge',
|
|
84
|
+
_meta: {},
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// MCP CallTool protocol - data for CallTool response
|
|
88
|
+
toolCall: {
|
|
89
|
+
structuredContent: placesData,
|
|
90
|
+
_meta: {},
|
|
91
|
+
},
|
|
66
92
|
} as const;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-safe configuration for the counter simulation.
|
|
3
|
+
* This file contains only metadata and doesn't import React components or CSS.
|
|
4
|
+
*/
|
|
5
|
+
export const counterSimulation = {
|
|
6
|
+
userMessage: 'Help me count something',
|
|
7
|
+
|
|
8
|
+
// MCP Tool protocol - official Tool type from MCP SDK used in ListTools response
|
|
9
|
+
tool: {
|
|
10
|
+
name: 'show-counter',
|
|
11
|
+
description: 'Show a simple counter tool',
|
|
12
|
+
inputSchema: { type: 'object', properties: {}, additionalProperties: false } as const,
|
|
13
|
+
title: 'Show Counter',
|
|
14
|
+
annotations: { readOnlyHint: true },
|
|
15
|
+
_meta: {
|
|
16
|
+
'openai/outputTemplate': 'ui://CounterResource.tsx',
|
|
17
|
+
'openai/toolInvocation/invoking': 'Counting beans',
|
|
18
|
+
'openai/toolInvocation/invoked': 'Beans counted',
|
|
19
|
+
'openai/widgetAccessible': true,
|
|
20
|
+
'openai/resultCanProduceWidget': true,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// MCP Resource protocol - official Resource type from MCP SDK used in ListResources response
|
|
25
|
+
// resource.name is used as the simulation identifier
|
|
26
|
+
// resource.title is used as the simulation display label
|
|
27
|
+
resource: {
|
|
28
|
+
uri: 'ui://CounterResource.tsx',
|
|
29
|
+
name: 'counter',
|
|
30
|
+
title: 'Counter',
|
|
31
|
+
description: 'Show a simple counter tool widget markup',
|
|
32
|
+
mimeType: 'text/html+skybridge',
|
|
33
|
+
_meta: {},
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// MCP CallTool protocol - data for CallTool response
|
|
37
|
+
toolCall: {
|
|
38
|
+
structuredContent: null,
|
|
39
|
+
_meta: {},
|
|
40
|
+
},
|
|
41
|
+
} as const;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Server-safe simulation configurations
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This file contains only metadata and can be safely imported in Node.js contexts
|
|
5
5
|
* (like MCP servers) without causing issues with CSS imports or React components.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { counterSimulation } from './counter-simulation';
|
|
9
|
+
import { albumsSimulation } from './albums-simulation';
|
|
10
|
+
import { carouselSimulation } from './carousel-simulation';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export const SIMULATIONS = {
|
|
13
|
+
counter: counterSimulation,
|
|
14
|
+
albums: albumsSimulation,
|
|
15
|
+
carousel: carouselSimulation,
|
|
16
|
+
} as const;
|
|
@@ -2,30 +2,35 @@ import { defineConfig } from 'vite';
|
|
|
2
2
|
import react from '@vitejs/plugin-react';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import tailwindcss from '@tailwindcss/vite';
|
|
5
|
-
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs';
|
|
5
|
+
import { readFileSync, writeFileSync, unlinkSync, existsSync, readdirSync } from 'fs';
|
|
6
6
|
|
|
7
7
|
// Check if we're in the sunpeak workspace (directory is named "template")
|
|
8
8
|
const isTemplate = path.basename(__dirname) === 'template';
|
|
9
9
|
const parentSrc = path.resolve(__dirname, '../src');
|
|
10
10
|
|
|
11
|
-
// Plugin to inline CSS into the JS bundle
|
|
11
|
+
// Plugin to inline CSS into the JS bundle for all output files
|
|
12
12
|
function inlineCssPlugin() {
|
|
13
13
|
return {
|
|
14
14
|
name: 'inline-css',
|
|
15
15
|
closeBundle() {
|
|
16
|
-
const distDir = path.resolve(__dirname, 'dist/chatgpt');
|
|
17
|
-
const jsFile = path.join(distDir, 'index.js');
|
|
16
|
+
const distDir = path.resolve(__dirname, process.env.OUT_DIR || 'dist/chatgpt');
|
|
18
17
|
const cssFile = path.join(distDir, 'style.css');
|
|
19
18
|
|
|
20
|
-
if (existsSync(cssFile)
|
|
19
|
+
if (existsSync(cssFile)) {
|
|
21
20
|
const css = readFileSync(cssFile, 'utf-8');
|
|
22
|
-
const js = readFileSync(jsFile, 'utf-8');
|
|
23
|
-
|
|
24
|
-
// Inject CSS at the start of the JS file
|
|
25
21
|
const injectCss = `(function(){var s=document.createElement('style');s.textContent=${JSON.stringify(css)};document.head.appendChild(s);})();`;
|
|
26
|
-
writeFileSync(jsFile, injectCss + js);
|
|
27
22
|
|
|
28
|
-
//
|
|
23
|
+
// Find all .js files in the dist directory and inject CSS
|
|
24
|
+
const files = readdirSync(distDir);
|
|
25
|
+
files.forEach(file => {
|
|
26
|
+
if (file.endsWith('.js')) {
|
|
27
|
+
const jsFile = path.join(distDir, file);
|
|
28
|
+
const js = readFileSync(jsFile, 'utf-8');
|
|
29
|
+
writeFileSync(jsFile, injectCss + js);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Remove the separate CSS file after injecting into all bundles
|
|
29
34
|
unlinkSync(cssFile);
|
|
30
35
|
}
|
|
31
36
|
},
|
|
@@ -49,18 +54,19 @@ export default defineConfig({
|
|
|
49
54
|
},
|
|
50
55
|
build: {
|
|
51
56
|
target: 'es2020',
|
|
57
|
+
outDir: process.env.OUT_DIR || 'dist/chatgpt',
|
|
58
|
+
emptyOutDir: process.env.OUT_DIR ? true : false,
|
|
59
|
+
cssCodeSplit: false,
|
|
52
60
|
lib: {
|
|
53
|
-
entry: path.resolve(__dirname, 'src/index.
|
|
61
|
+
entry: path.resolve(__dirname, process.env.ENTRY_FILE || 'src/index-app.tsx'),
|
|
54
62
|
name: 'SunpeakApp',
|
|
55
63
|
formats: ['iife'],
|
|
56
|
-
fileName: () => '
|
|
64
|
+
fileName: () => process.env.OUTPUT_FILE || 'app.js',
|
|
57
65
|
},
|
|
58
|
-
outDir: 'dist/chatgpt',
|
|
59
|
-
cssCodeSplit: false,
|
|
60
66
|
rollupOptions: {
|
|
61
67
|
output: {
|
|
62
68
|
inlineDynamicImports: true,
|
|
63
|
-
assetFileNames: '
|
|
69
|
+
assetFileNames: 'style.css',
|
|
64
70
|
},
|
|
65
71
|
},
|
|
66
72
|
minify: true,
|
|
@@ -1,25 +0,0 @@
|
|
|
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;
|