sunpeak 0.17.7 → 0.18.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.
- package/README.md +52 -44
- package/bin/commands/dev.mjs +5 -6
- package/bin/commands/inspect.mjs +17 -18
- package/bin/lib/inspect/inspect-config.d.mts +2 -2
- package/bin/lib/inspect/inspect-config.mjs +2 -2
- package/bin/lib/live/chatgpt-page.mjs +2 -2
- package/bin/lib/live/host-page.mjs +3 -8
- package/bin/lib/sandbox-server.mjs +11 -11
- package/bin/sunpeak.js +3 -3
- package/dist/chatgpt/chatgpt-conversation.d.ts +1 -1
- package/dist/chatgpt/index.cjs +20 -20
- package/dist/chatgpt/index.cjs.map +1 -1
- package/dist/chatgpt/index.d.ts +10 -10
- package/dist/chatgpt/index.js +5 -5
- package/dist/chatgpt/index.js.map +1 -1
- package/dist/claude/claude-conversation.d.ts +1 -1
- package/dist/claude/index.cjs +2 -2
- package/dist/claude/index.d.ts +1 -1
- package/dist/claude/index.js +2 -2
- package/dist/host/chatgpt/index.cjs +0 -40
- package/dist/host/chatgpt/index.cjs.map +1 -1
- package/dist/host/chatgpt/index.d.ts +0 -3
- package/dist/host/chatgpt/index.js +1 -40
- package/dist/host/chatgpt/index.js.map +1 -1
- package/dist/host/index.cjs +1 -4
- package/dist/host/index.cjs.map +1 -1
- package/dist/host/index.d.ts +1 -5
- package/dist/host/index.js +2 -4
- package/dist/host/index.js.map +1 -1
- package/dist/index.cjs +9 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/{simulator → inspector}/hosts.d.ts +3 -3
- package/dist/{simulator → inspector}/iframe-resource.d.ts +3 -3
- package/dist/inspector/index.cjs +74 -0
- package/dist/{simulator → inspector}/index.cjs.map +1 -1
- package/dist/{simulator → inspector}/index.d.ts +8 -8
- package/dist/{simulator → inspector}/index.js +8 -8
- package/dist/{simulator → inspector}/index.js.map +1 -1
- package/dist/{simulator/simulator-types.d.ts → inspector/inspector-types.d.ts} +1 -1
- package/dist/{simulator/simulator-url.d.ts → inspector/inspector-url.d.ts} +15 -15
- package/dist/{simulator/simulator.d.ts → inspector/inspector.d.ts} +3 -3
- package/dist/{simulator → inspector}/mcp-app-host.d.ts +5 -5
- package/dist/{simulator → inspector}/mock-openai-runtime.d.ts +2 -2
- package/dist/{simulator → inspector}/sandbox-proxy.d.ts +1 -1
- package/dist/{simulator/use-simulator-state.d.ts → inspector/use-inspector-state.d.ts} +4 -4
- package/dist/{simulator → inspector}/use-mcp-connection.d.ts +1 -1
- package/dist/{simulator-eU6sQTje.cjs → inspector-CByJjmPD.cjs} +51 -52
- package/dist/{simulator-eU6sQTje.cjs.map → inspector-CByJjmPD.cjs.map} +1 -1
- package/dist/{simulator-0dAb16Qt.js → inspector-ClhpqKLi.js} +42 -43
- package/dist/{simulator-0dAb16Qt.js.map → inspector-ClhpqKLi.js.map} +1 -1
- package/dist/{simulator-url-3ATCsPOT.cjs → inspector-url-7qhtJwY6.cjs} +10 -10
- package/dist/{simulator-url-3ATCsPOT.cjs.map → inspector-url-7qhtJwY6.cjs.map} +1 -1
- package/dist/{simulator-url-BbuuWa7S.js → inspector-url-DuEFmxLP.js} +9 -9
- package/dist/{simulator-url-BbuuWa7S.js.map → inspector-url-DuEFmxLP.js.map} +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/types.d.ts +1 -1
- package/dist/style.css +12 -12
- package/dist/types/simulation.d.ts +1 -1
- package/package.json +7 -20
- package/template/dist/albums/albums.html +1 -1
- package/template/dist/albums/albums.json +1 -1
- package/template/dist/carousel/carousel.html +1 -1
- package/template/dist/carousel/carousel.json +1 -1
- package/template/dist/map/map.html +1 -1
- package/template/dist/map/map.json +1 -1
- package/template/dist/review/review.html +1 -1
- package/template/dist/review/review.json +1 -1
- package/template/playwright.config.ts +1 -1
- package/template/src/index-resource.tsx +1 -1
- package/template/src/styles/globals.css +2 -2
- package/template/tests/e2e/albums.spec.ts +13 -13
- package/template/tests/e2e/carousel.spec.ts +11 -11
- package/template/tests/e2e/map.spec.ts +16 -16
- package/template/tests/e2e/review.spec.ts +25 -25
- package/dist/chatgpt/globals.css +0 -2642
- package/dist/host/chatgpt/use-file-download.d.ts +0 -33
- package/dist/simulator/index.cjs +0 -74
- /package/dist/{simulator → inspector}/host-styles.d.ts +0 -0
- /package/dist/{simulator → inspector}/simple-sidebar.d.ts +0 -0
- /package/dist/{simulator → inspector}/theme-provider.d.ts +0 -0
package/README.md
CHANGED
|
@@ -16,47 +16,48 @@
|
|
|
16
16
|
[](https://www.typescriptlang.org/)
|
|
17
17
|
[](https://reactjs.org/)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Inspector, testing framework, and app framework for MCP Apps.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
[Demo (Hosted)](https://sunpeak.ai/simulator) ~
|
|
21
|
+
[Demo (Hosted)](https://sunpeak.ai/inspector) ~
|
|
24
22
|
[Demo (Video)](https://cdn.sunpeak.ai/sunpeak-demo-prod.mp4) ~
|
|
25
23
|
[Discord](https://discord.gg/FB2QNXqRnw) ~
|
|
26
24
|
[Documentation](https://sunpeak.ai/docs) ~
|
|
27
25
|
[GitHub](https://github.com/Sunpeak-AI/sunpeak)
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
<a href="https://sunpeak.ai/docs/library/simulator">
|
|
31
|
-
<picture>
|
|
32
|
-
<img alt="Simulator" src="https://cdn.sunpeak.ai/chatgpt-simulator.png">
|
|
33
|
-
</picture>
|
|
34
|
-
</a>
|
|
35
|
-
</div>
|
|
27
|
+
## sunpeak is three things
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
### 1. Inspector
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
Test any MCP server in replicated ChatGPT and Claude runtimes — no sunpeak project required.
|
|
40
32
|
|
|
41
33
|
```bash
|
|
42
|
-
|
|
43
|
-
sunpeak new
|
|
34
|
+
sunpeak inspect --server http://localhost:8000/mcp
|
|
44
35
|
```
|
|
45
36
|
|
|
46
|
-
|
|
37
|
+
<div align="center">
|
|
38
|
+
<a href="https://sunpeak.ai/docs/mcp-apps-inspector">
|
|
39
|
+
<picture>
|
|
40
|
+
<img alt="Inspector" src="https://cdn.sunpeak.ai/chatgpt-simulator.png">
|
|
41
|
+
</picture>
|
|
42
|
+
</a>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
- Multi-host inspector replicating ChatGPT and Claude runtimes
|
|
46
|
+
- Toggle themes, display modes, device types from the sidebar or URL params
|
|
47
|
+
- Call real tool handlers or use simulation fixtures for mock data
|
|
48
|
+
- Built into `sunpeak dev` for framework users
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
### 2. Testing Framework
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
E2E tests against simulated hosts and live tests against real production hosts.
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
4. MCP server: Serve Resources with mock data to hosts like ChatGPT and Claude with HMR (**no more cache issues or 5-click manual refreshes**).
|
|
54
|
+
- **Simulations**: JSON fixtures defining reproducible tool states ([example below](#simulation))
|
|
55
|
+
- **E2E tests**: Playwright + `createInspectorUrl` against the inspector ([example below](#inspector))
|
|
56
|
+
- **Live tests**: Automated browser tests against real ChatGPT via `sunpeak/test`
|
|
56
57
|
|
|
57
|
-
###
|
|
58
|
+
### 3. App Framework
|
|
58
59
|
|
|
59
|
-
Next.js for MCP Apps.
|
|
60
|
+
Next.js for MCP Apps. Convention-over-configuration project structure with the inspector and testing built in.
|
|
60
61
|
|
|
61
62
|
```bash
|
|
62
63
|
sunpeak-app/
|
|
@@ -76,26 +77,33 @@ sunpeak-app/
|
|
|
76
77
|
└── package.json
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
- **Runtime APIs**: Strongly typed React hooks (`useToolData`, `useAppState`, `useHostContext`, etc.)
|
|
81
|
+
- **Convention over configuration**: Resources, tools, and simulations are auto-discovered
|
|
82
|
+
- **Multi-platform**: Build once, deploy to ChatGPT, Claude, and future hosts
|
|
83
|
+
|
|
84
|
+
## Quickstart
|
|
85
|
+
|
|
86
|
+
Requirements: Node (20+), pnpm (10+)
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
```bash
|
|
89
|
+
pnpm add -g sunpeak
|
|
90
|
+
sunpeak new
|
|
91
|
+
```
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
## CLI
|
|
89
94
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
| Command | Description |
|
|
96
|
+
| ------------------------------------- | ------------------------------------------- |
|
|
97
|
+
| `sunpeak new [name] [resources]` | Create a new project |
|
|
98
|
+
| `sunpeak dev` | Start dev server + inspector + MCP endpoint |
|
|
99
|
+
| `sunpeak inspect --server <url\|cmd>` | Inspect any MCP server (standalone) |
|
|
100
|
+
| `sunpeak build` | Build resources + tools for production |
|
|
101
|
+
| `sunpeak start` | Start production MCP server |
|
|
102
|
+
| `sunpeak upgrade` | Upgrade sunpeak to latest version |
|
|
95
103
|
|
|
96
104
|
## Example App
|
|
97
105
|
|
|
98
|
-
Example `Resource`, `Simulation`, and testing file (using the `
|
|
106
|
+
Example `Resource`, `Simulation`, and testing file (using the `Inspector`) for an [MCP resource](https://sunpeak.ai/docs/mcp-apps/mcp/resources) called "Review".
|
|
99
107
|
|
|
100
108
|
### `Resource` Component
|
|
101
109
|
|
|
@@ -151,7 +159,7 @@ export default async function (args: Args, extra: ToolHandlerExtra) {
|
|
|
151
159
|
|
|
152
160
|
### `Simulation`
|
|
153
161
|
|
|
154
|
-
Simulation files provide fixture data for testing. Each references a tool by filename and contains the mock input/output:
|
|
162
|
+
Simulation files provide fixture data for testing UIs. Each references a tool by filename and contains the mock input/output:
|
|
155
163
|
|
|
156
164
|
```jsonc
|
|
157
165
|
// tests/simulations/review-diff.json
|
|
@@ -172,7 +180,7 @@ Simulation files provide fixture data for testing. Each references a tool by fil
|
|
|
172
180
|
}
|
|
173
181
|
```
|
|
174
182
|
|
|
175
|
-
### `
|
|
183
|
+
### `Inspector`
|
|
176
184
|
|
|
177
185
|
```bash
|
|
178
186
|
├── tests/e2e/
|
|
@@ -180,15 +188,15 @@ Simulation files provide fixture data for testing. Each references a tool by fil
|
|
|
180
188
|
└── package.json
|
|
181
189
|
```
|
|
182
190
|
|
|
183
|
-
The `
|
|
191
|
+
The `Inspector` allows you to set **host state** (like host platform, light/dark mode) via URL params, which can be rendered alongside your `Simulation`s and tested via pre-configured Playwright end-to-end tests (`.spec.ts`).
|
|
184
192
|
|
|
185
|
-
Using the `
|
|
193
|
+
Using the `Inspector` and `Simulation`s, you can test all possible App states locally and automatically across hosts (ChatGPT, Claude)!
|
|
186
194
|
|
|
187
195
|
```ts
|
|
188
196
|
// tests/e2e/review.spec.ts
|
|
189
197
|
|
|
190
198
|
import { test, expect } from '@playwright/test';
|
|
191
|
-
import {
|
|
199
|
+
import { createInspectorUrl } from 'sunpeak/inspector';
|
|
192
200
|
|
|
193
201
|
const hosts = ['chatgpt', 'claude'] as const;
|
|
194
202
|
|
|
@@ -197,7 +205,7 @@ for (const host of hosts) {
|
|
|
197
205
|
test.describe('Light Mode', () => {
|
|
198
206
|
test('should render review title with correct styles', async ({ page }) => {
|
|
199
207
|
const params = { simulation: 'review-diff', theme: 'light', host }; // Set sim & host state.
|
|
200
|
-
await page.goto(
|
|
208
|
+
await page.goto(createInspectorUrl(params));
|
|
201
209
|
|
|
202
210
|
// Resource content renders inside an iframe
|
|
203
211
|
const iframe = page.frameLocator('iframe');
|
package/bin/commands/dev.mjs
CHANGED
|
@@ -128,8 +128,8 @@ function startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBu
|
|
|
128
128
|
* Start the Vite development server.
|
|
129
129
|
*
|
|
130
130
|
* Starts the MCP server (with Vite HMR for resources) and then launches the
|
|
131
|
-
* inspector
|
|
132
|
-
*
|
|
131
|
+
* inspector pointed at it. The inspector handles the UI, tool call proxying,
|
|
132
|
+
* and resource loading — all through the MCP protocol.
|
|
133
133
|
*/
|
|
134
134
|
export async function dev(projectRoot = process.cwd(), args = []) {
|
|
135
135
|
// Check for package.json
|
|
@@ -511,8 +511,8 @@ if (import.meta.hot) {
|
|
|
511
511
|
startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBuild: isProdResources });
|
|
512
512
|
|
|
513
513
|
// Launch the inspector UI pointed at the local MCP server.
|
|
514
|
-
// This serves the
|
|
515
|
-
// In framework mode, the
|
|
514
|
+
// This serves the inspector UI via Vite, connecting to our MCP server as a client.
|
|
515
|
+
// In framework mode, the inspector shows prod-tools/prod-resources toggles instead
|
|
516
516
|
// of the server URL input.
|
|
517
517
|
const mcpUrl = `http://localhost:${mcpPort}/mcp`;
|
|
518
518
|
await inspectServer({
|
|
@@ -531,9 +531,8 @@ if (import.meta.hot) {
|
|
|
531
531
|
// The Tailwind plugin is also passed so source CSS (@import "tailwindcss") is processed.
|
|
532
532
|
...(isTemplate && {
|
|
533
533
|
resolveAlias: {
|
|
534
|
-
'sunpeak/
|
|
534
|
+
'sunpeak/inspector': resolve(parentSrc, 'inspector/index.ts'),
|
|
535
535
|
'sunpeak/style.css': resolve(parentSrc, 'style.css'),
|
|
536
|
-
'sunpeak/chatgpt/globals.css': resolve(parentSrc, 'chatgpt/globals.css'),
|
|
537
536
|
},
|
|
538
537
|
vitePlugins: [tailwindcss()],
|
|
539
538
|
viteCssConfig: lightningcssConfig,
|
package/bin/commands/inspect.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `sunpeak inspect` — Connect to an external MCP server and launch the
|
|
2
|
+
* `sunpeak inspect` — Connect to an external MCP server and launch the inspector.
|
|
3
3
|
*
|
|
4
|
-
* This command lets users test their own MCP server in the sunpeak
|
|
4
|
+
* This command lets users test their own MCP server in the sunpeak inspector
|
|
5
5
|
* without adopting the sunpeak framework conventions. It connects to the server
|
|
6
|
-
* via MCP protocol, discovers tools and resources, and serves the
|
|
6
|
+
* via MCP protocol, discovers tools and resources, and serves the inspector UI.
|
|
7
7
|
*
|
|
8
8
|
* The core logic lives in `inspectServer()`, which is also used by `sunpeak dev`
|
|
9
|
-
* to serve the
|
|
9
|
+
* to serve the inspector UI pointed at the local MCP server.
|
|
10
10
|
*
|
|
11
11
|
* Usage:
|
|
12
12
|
* sunpeak inspect --server http://localhost:8000/mcp
|
|
@@ -57,7 +57,7 @@ function parseArgs(args) {
|
|
|
57
57
|
|
|
58
58
|
function printHelp() {
|
|
59
59
|
console.log(`
|
|
60
|
-
sunpeak inspect — Test an external MCP server in the
|
|
60
|
+
sunpeak inspect — Test an external MCP server in the inspector
|
|
61
61
|
|
|
62
62
|
Usage:
|
|
63
63
|
sunpeak inspect --server <url-or-command>
|
|
@@ -66,7 +66,7 @@ Options:
|
|
|
66
66
|
--server, -s <url|cmd> MCP server URL or stdio command (required)
|
|
67
67
|
--simulations <dir> Simulation JSON directory (opt-in, no default)
|
|
68
68
|
--port, -p <number> Dev server port (default: 3000)
|
|
69
|
-
--name <string> App name in
|
|
69
|
+
--name <string> App name in inspector chrome
|
|
70
70
|
--help, -h Show this help
|
|
71
71
|
|
|
72
72
|
Examples:
|
|
@@ -210,7 +210,7 @@ function mergeSimulationFixtures(dir, simulations) {
|
|
|
210
210
|
* @param {string} appName - Display name
|
|
211
211
|
* @param {string|null} appIcon - Icon URL or emoji
|
|
212
212
|
* @param {string} sandboxUrl - Sandbox server URL
|
|
213
|
-
* @param {{ defaultProdResources?: boolean,
|
|
213
|
+
* @param {{ defaultProdResources?: boolean, hideInspectorModes?: boolean }} [modeFlags] - Mode toggles
|
|
214
214
|
*/
|
|
215
215
|
function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, sandboxUrl, modeFlags = {}) {
|
|
216
216
|
const ENTRY_ID = 'virtual:sunpeak-inspect-entry';
|
|
@@ -227,16 +227,15 @@ function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, s
|
|
|
227
227
|
return `
|
|
228
228
|
import { createElement, StrictMode } from 'react';
|
|
229
229
|
import { createRoot } from 'react-dom/client';
|
|
230
|
-
import {
|
|
230
|
+
import { Inspector } from 'sunpeak/inspector';
|
|
231
231
|
import 'sunpeak/style.css';
|
|
232
|
-
import 'sunpeak/chatgpt/globals.css';
|
|
233
232
|
|
|
234
233
|
const simulations = ${JSON.stringify(simulations)};
|
|
235
234
|
const appName = ${JSON.stringify(appName ?? 'MCP Inspector')};
|
|
236
235
|
const appIcon = ${JSON.stringify(appIcon ?? null)};
|
|
237
236
|
const sandboxUrl = ${JSON.stringify(sandboxUrl)};
|
|
238
237
|
const defaultProdResources = ${JSON.stringify(modeFlags.defaultProdResources ?? false)};
|
|
239
|
-
const
|
|
238
|
+
const hideInspectorModes = ${JSON.stringify(modeFlags.hideInspectorModes ?? false)};
|
|
240
239
|
|
|
241
240
|
const onCallTool = async (params) => {
|
|
242
241
|
const res = await fetch('/__sunpeak/call-tool', {
|
|
@@ -259,7 +258,7 @@ const onCallToolDirect = async (params) => {
|
|
|
259
258
|
const root = createRoot(document.getElementById('root'));
|
|
260
259
|
root.render(
|
|
261
260
|
createElement(StrictMode, null,
|
|
262
|
-
createElement(
|
|
261
|
+
createElement(Inspector, {
|
|
263
262
|
simulations,
|
|
264
263
|
mcpServerUrl: ${JSON.stringify(serverUrl)},
|
|
265
264
|
appName,
|
|
@@ -268,7 +267,7 @@ root.render(
|
|
|
268
267
|
onCallTool,
|
|
269
268
|
onCallToolDirect,
|
|
270
269
|
defaultProdResources,
|
|
271
|
-
|
|
270
|
+
hideInspectorModes,
|
|
272
271
|
})
|
|
273
272
|
)
|
|
274
273
|
);
|
|
@@ -492,7 +491,7 @@ function readRequestBody(req) {
|
|
|
492
491
|
|
|
493
492
|
/**
|
|
494
493
|
* Core inspect server logic. Connects to an MCP server, discovers tools/resources,
|
|
495
|
-
* merges simulation fixtures, and serves the
|
|
494
|
+
* merges simulation fixtures, and serves the inspector UI via Vite.
|
|
496
495
|
*
|
|
497
496
|
* Used by both `sunpeak inspect` (CLI) and `sunpeak dev` (programmatic).
|
|
498
497
|
*
|
|
@@ -621,7 +620,7 @@ export async function inspectServer(opts) {
|
|
|
621
620
|
</body>
|
|
622
621
|
</html>`;
|
|
623
622
|
|
|
624
|
-
const
|
|
623
|
+
const inspectorServerUrl = serverArg;
|
|
625
624
|
|
|
626
625
|
// Create the Vite server.
|
|
627
626
|
// Use the sunpeak package dir as root to avoid scanning the user's project
|
|
@@ -636,11 +635,11 @@ export async function inspectServer(opts) {
|
|
|
636
635
|
...extraVitePlugins,
|
|
637
636
|
sunpeakInspectVirtualPlugin(
|
|
638
637
|
simulations,
|
|
639
|
-
|
|
638
|
+
inspectorServerUrl,
|
|
640
639
|
serverAppName,
|
|
641
640
|
serverAppIcon,
|
|
642
641
|
sandbox.url,
|
|
643
|
-
{ defaultProdResources,
|
|
642
|
+
{ defaultProdResources, hideInspectorModes: !frameworkMode }
|
|
644
643
|
),
|
|
645
644
|
sunpeakInspectEndpointsPlugin(
|
|
646
645
|
() => mcpConnection.client,
|
|
@@ -648,9 +647,9 @@ export async function inspectServer(opts) {
|
|
|
648
647
|
{ callToolDirect: opts.callToolDirect, simulationsDir }
|
|
649
648
|
),
|
|
650
649
|
// Serve /dist/{name}/{name}.html from the project directory (for Prod Resources mode).
|
|
651
|
-
// The
|
|
650
|
+
// The Inspector polls these paths via HEAD to check if built resources exist.
|
|
652
651
|
// Only intercepts .html files under /dist/ — other /dist/ paths (like sunpeak's
|
|
653
|
-
// own dist/
|
|
652
|
+
// own dist/inspector/index.js) must fall through to Vite's module resolution.
|
|
654
653
|
...(projectRoot ? [{
|
|
655
654
|
name: 'sunpeak-dist-serve',
|
|
656
655
|
configureServer(server) {
|
|
@@ -7,7 +7,7 @@ export interface InspectConfigOptions {
|
|
|
7
7
|
simulationsDir?: string;
|
|
8
8
|
/** Host shells to test (default: ['chatgpt', 'claude']) */
|
|
9
9
|
hosts?: ('chatgpt' | 'claude')[];
|
|
10
|
-
/** App name in
|
|
10
|
+
/** App name in inspector chrome */
|
|
11
11
|
name?: string;
|
|
12
12
|
/** Additional Playwright `use` options */
|
|
13
13
|
use?: Record<string, unknown>;
|
|
@@ -15,6 +15,6 @@ export interface InspectConfigOptions {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Create a complete Playwright config for testing an external MCP server
|
|
18
|
-
* using the sunpeak
|
|
18
|
+
* using the sunpeak inspector.
|
|
19
19
|
*/
|
|
20
20
|
export function defineInspectConfig(options: InspectConfigOptions): Record<string, unknown>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Playwright config factory for inspect mode (BYOS — Bring Your Own Server).
|
|
3
3
|
*
|
|
4
4
|
* Generates a complete Playwright config that starts `sunpeak inspect` as the
|
|
5
|
-
* webServer and runs e2e tests against the
|
|
5
|
+
* webServer and runs e2e tests against the inspector. Follows the same pattern
|
|
6
6
|
* as `defineLiveConfig` for live tests.
|
|
7
7
|
*
|
|
8
8
|
* Usage in playwright.config.ts:
|
|
@@ -21,7 +21,7 @@ import { getPortSync } from '../get-port.mjs';
|
|
|
21
21
|
* @param {string} [options.testDir='tests/e2e'] - Test directory
|
|
22
22
|
* @param {string} [options.simulationsDir='tests/simulations'] - Simulation JSON directory
|
|
23
23
|
* @param {string[]} [options.hosts=['chatgpt', 'claude']] - Host shells to test
|
|
24
|
-
* @param {string} [options.name] - App name in
|
|
24
|
+
* @param {string} [options.name] - App name in inspector chrome
|
|
25
25
|
* @param {Object} [options.use] - Additional Playwright `use` options
|
|
26
26
|
* @returns {import('@playwright/test').PlaywrightTestConfig}
|
|
27
27
|
*/
|
|
@@ -11,13 +11,13 @@ import { HostPage } from './host-page.mjs';
|
|
|
11
11
|
/**
|
|
12
12
|
* All ChatGPT DOM selectors in one place for easy maintenance.
|
|
13
13
|
*
|
|
14
|
-
* Last verified: 2026-03-
|
|
14
|
+
* Last verified: 2026-03-24 via live Playwright inspection.
|
|
15
15
|
*/
|
|
16
16
|
const SELECTORS = {
|
|
17
17
|
// Chat interface
|
|
18
18
|
chatInput: '#prompt-textarea',
|
|
19
19
|
sendButton: '[data-testid="send-button"]',
|
|
20
|
-
newChatLink: '
|
|
20
|
+
newChatLink: '[data-testid="create-new-chat-button"]',
|
|
21
21
|
|
|
22
22
|
// Login detection — ChatGPT renders two profile buttons (sidebar compact + expanded); always use .first().
|
|
23
23
|
loggedInIndicator: '[data-testid="accounts-profile-button"]',
|
|
@@ -181,14 +181,9 @@ export class HostPage {
|
|
|
181
181
|
* Start a new chat conversation.
|
|
182
182
|
*/
|
|
183
183
|
async startNewChat() {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await newChatLink.click();
|
|
188
|
-
} else {
|
|
189
|
-
await this.page.goto(this.urls.base, { waitUntil: 'domcontentloaded' });
|
|
190
|
-
}
|
|
191
|
-
|
|
184
|
+
// Navigate directly rather than clicking — ChatGPT's sidebar compact
|
|
185
|
+
// icon can overlay the "New chat" link and intercept pointer events.
|
|
186
|
+
await this.page.goto(this.urls.base, { waitUntil: 'domcontentloaded' });
|
|
192
187
|
await this.page.locator(this.selectors.chatInput).waitFor({ timeout: 10_000 });
|
|
193
188
|
}
|
|
194
189
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Separate-origin sandbox server for the
|
|
2
|
+
* Separate-origin sandbox server for the inspector's double-iframe architecture.
|
|
3
3
|
*
|
|
4
4
|
* Real hosts (ChatGPT, Claude) run the sandbox proxy iframe on a separate origin
|
|
5
5
|
* (e.g., web-sandbox.oaiusercontent.com). This server replicates that by serving
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - document.referrer is empty (cross-origin navigation)
|
|
11
11
|
* - The iframe sandbox attribute behaves identically to production
|
|
12
12
|
*
|
|
13
|
-
* The server is started by `sunpeak dev` and its URL is injected into the
|
|
13
|
+
* The server is started by `sunpeak dev` and its URL is injected into the Inspector
|
|
14
14
|
* via `__SUNPEAK_SANDBOX_URL__`.
|
|
15
15
|
*
|
|
16
16
|
* NOTE: The proxy HTML and mock openai script are duplicated from sandbox-proxy.ts
|
|
@@ -287,18 +287,18 @@ iframe { border: none; width: 100%; height: 100%; display: block; }
|
|
|
287
287
|
*/
|
|
288
288
|
const MOCK_OPENAI_SCRIPT = [
|
|
289
289
|
'window.openai={',
|
|
290
|
-
'uploadFile:function(f){console.log("[
|
|
290
|
+
'uploadFile:function(f){console.log("[Inspector] uploadFile:",f.name);',
|
|
291
291
|
'return Promise.resolve({fileId:"sim_file_"+Date.now()})},',
|
|
292
|
-
'getFileDownloadUrl:function(p){console.log("[
|
|
293
|
-
'return Promise.resolve({downloadUrl:"https://
|
|
294
|
-
'requestModal:function(p){console.log("[
|
|
292
|
+
'getFileDownloadUrl:function(p){console.log("[Inspector] getFileDownloadUrl:",p.fileId);',
|
|
293
|
+
'return Promise.resolve({downloadUrl:"https://inspector.local/files/"+p.fileId})},',
|
|
294
|
+
'requestModal:function(p){console.log("[Inspector] requestModal:",JSON.stringify(p));',
|
|
295
295
|
'return Promise.resolve()},',
|
|
296
|
-
'requestCheckout:function(s){console.log("[
|
|
296
|
+
'requestCheckout:function(s){console.log("[Inspector] requestCheckout:",JSON.stringify(s));',
|
|
297
297
|
'return Promise.resolve({id:"sim_order_"+Date.now(),checkout_session_id:s.id||"sim_session",status:"completed"})},',
|
|
298
|
-
'requestClose:function(){console.log("[
|
|
299
|
-
'requestDisplayMode:function(p){console.log("[
|
|
298
|
+
'requestClose:function(){console.log("[Inspector] requestClose")},',
|
|
299
|
+
'requestDisplayMode:function(p){console.log("[Inspector] requestDisplayMode:",p.mode);',
|
|
300
300
|
'return Promise.resolve()},',
|
|
301
|
-
'sendFollowUpMessage:function(p){console.log("[
|
|
302
|
-
'openExternal:function(p){console.log("[
|
|
301
|
+
'sendFollowUpMessage:function(p){console.log("[Inspector] sendFollowUpMessage:",p.prompt)},',
|
|
302
|
+
'openExternal:function(p){console.log("[Inspector] openExternal:",p.href);window.open(p.href,"_blank")}',
|
|
303
303
|
'};',
|
|
304
304
|
].join('');
|
package/bin/sunpeak.js
CHANGED
|
@@ -95,19 +95,19 @@ function getVersion() {
|
|
|
95
95
|
{
|
|
96
96
|
const resources = discoverResources();
|
|
97
97
|
console.log(`
|
|
98
|
-
☀️ 🏔️ sunpeak -
|
|
98
|
+
☀️ 🏔️ sunpeak - Inspector, testing framework, and app framework for MCP Apps
|
|
99
99
|
|
|
100
100
|
Install:
|
|
101
101
|
pnpm add -g sunpeak
|
|
102
102
|
|
|
103
103
|
Usage:
|
|
104
104
|
sunpeak new [name] [resources] Create a new project
|
|
105
|
-
sunpeak dev Start dev server + MCP endpoint
|
|
105
|
+
sunpeak dev Start dev server + inspector + MCP endpoint
|
|
106
106
|
--no-begging Suppress GitHub star message
|
|
107
107
|
sunpeak build Build resources + tools for production
|
|
108
108
|
sunpeak start Start production MCP server
|
|
109
109
|
--port, -p Server port (default: 8000, or PORT env)
|
|
110
|
-
sunpeak inspect
|
|
110
|
+
sunpeak inspect Inspect any MCP server in the inspector
|
|
111
111
|
--server, -s <url|cmd> MCP server URL or stdio command (required)
|
|
112
112
|
--simulations <dir> Simulation JSON directory
|
|
113
113
|
sunpeak upgrade Upgrade sunpeak to latest version
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ScreenWidth } from '../
|
|
1
|
+
import { ScreenWidth } from '../inspector/inspector-types';
|
|
2
2
|
import { McpUiDisplayMode, McpUiHostContext } from '@modelcontextprotocol/ext-apps';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
type Platform = NonNullable<McpUiHostContext['platform']>;
|
package/dist/chatgpt/index.cjs
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../chunk-9hOWP6kD.cjs");
|
|
3
3
|
require("../protocol-jbxhzcnS.cjs");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const require_inspector = require("../inspector-CByJjmPD.cjs");
|
|
5
|
+
const require_inspector_url = require("../inspector-url-7qhtJwY6.cjs");
|
|
6
6
|
const require_discovery = require("../discovery-Clu4uHp1.cjs");
|
|
7
7
|
//#region src/chatgpt/index.ts
|
|
8
8
|
var chatgpt_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
9
|
-
IframeResource: () =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ThemeProvider: () =>
|
|
14
|
-
|
|
15
|
-
extractResourceCSP: () =>
|
|
9
|
+
IframeResource: () => require_inspector.IframeResource,
|
|
10
|
+
Inspector: () => require_inspector.Inspector,
|
|
11
|
+
McpAppHost: () => require_inspector.McpAppHost,
|
|
12
|
+
SCREEN_WIDTHS: () => require_inspector.SCREEN_WIDTHS,
|
|
13
|
+
ThemeProvider: () => require_inspector.ThemeProvider,
|
|
14
|
+
createInspectorUrl: () => require_inspector_url.createInspectorUrl,
|
|
15
|
+
extractResourceCSP: () => require_inspector.extractResourceCSP,
|
|
16
16
|
extractResourceKey: () => require_discovery.extractResourceKey,
|
|
17
17
|
extractSimulationKey: () => require_discovery.extractSimulationKey,
|
|
18
18
|
findResourceDirs: () => require_discovery.findResourceDirs,
|
|
19
19
|
findResourceKey: () => require_discovery.findResourceKey,
|
|
20
20
|
getComponentName: () => require_discovery.getComponentName,
|
|
21
|
-
resolveServerToolResult: () =>
|
|
21
|
+
resolveServerToolResult: () => require_inspector.resolveServerToolResult,
|
|
22
22
|
toPascalCase: () => require_discovery.toPascalCase,
|
|
23
|
-
useThemeContext: () =>
|
|
23
|
+
useThemeContext: () => require_inspector.useThemeContext
|
|
24
24
|
});
|
|
25
25
|
//#endregion
|
|
26
|
-
exports.IframeResource =
|
|
27
|
-
exports.
|
|
28
|
-
exports.
|
|
29
|
-
exports.
|
|
30
|
-
exports.ThemeProvider =
|
|
26
|
+
exports.IframeResource = require_inspector.IframeResource;
|
|
27
|
+
exports.Inspector = require_inspector.Inspector;
|
|
28
|
+
exports.McpAppHost = require_inspector.McpAppHost;
|
|
29
|
+
exports.SCREEN_WIDTHS = require_inspector.SCREEN_WIDTHS;
|
|
30
|
+
exports.ThemeProvider = require_inspector.ThemeProvider;
|
|
31
31
|
Object.defineProperty(exports, "chatgpt_exports", {
|
|
32
32
|
enumerable: true,
|
|
33
33
|
get: function() {
|
|
34
34
|
return chatgpt_exports;
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
-
exports.
|
|
38
|
-
exports.extractResourceCSP =
|
|
37
|
+
exports.createInspectorUrl = require_inspector_url.createInspectorUrl;
|
|
38
|
+
exports.extractResourceCSP = require_inspector.extractResourceCSP;
|
|
39
39
|
exports.extractResourceKey = require_discovery.extractResourceKey;
|
|
40
40
|
exports.extractSimulationKey = require_discovery.extractSimulationKey;
|
|
41
41
|
exports.findResourceDirs = require_discovery.findResourceDirs;
|
|
42
42
|
exports.findResourceKey = require_discovery.findResourceKey;
|
|
43
43
|
exports.getComponentName = require_discovery.getComponentName;
|
|
44
|
-
exports.resolveServerToolResult =
|
|
44
|
+
exports.resolveServerToolResult = require_inspector.resolveServerToolResult;
|
|
45
45
|
exports.toPascalCase = require_discovery.toPascalCase;
|
|
46
|
-
exports.useThemeContext =
|
|
46
|
+
exports.useThemeContext = require_inspector.useThemeContext;
|
|
47
47
|
|
|
48
48
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak inspector.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Inspector\nexport { Inspector } from '../inspector/inspector';\n\n// Inspector types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';\nexport { SCREEN_WIDTHS } from '../inspector/inspector-types';\n\n// Host bridge (for building custom inspectors or test harnesses)\nexport { McpAppHost } from '../inspector/mcp-app-host';\nexport type { McpAppHostOptions } from '../inspector/mcp-app-host';\n\n// Iframe rendering (used internally by inspector)\nexport { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';\nexport type { ResourceCSP } from '../inspector/iframe-resource';\n\n// Theme provider\nexport * from '../inspector/theme-provider';\n\n// URL helpers\nexport { createInspectorUrl } from '../inspector/inspector-url';\nexport type { InspectorUrlParams } from '../inspector/inspector-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}
|
package/dist/chatgpt/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { Inspector } from '../inspector/inspector';
|
|
2
2
|
export type { Simulation, ServerToolMock } from '../types/simulation';
|
|
3
3
|
export { resolveServerToolResult } from '../types/simulation';
|
|
4
|
-
export type { ScreenWidth,
|
|
5
|
-
export { SCREEN_WIDTHS } from '../
|
|
6
|
-
export { McpAppHost } from '../
|
|
7
|
-
export type { McpAppHostOptions } from '../
|
|
8
|
-
export { IframeResource, extractResourceCSP } from '../
|
|
9
|
-
export type { ResourceCSP } from '../
|
|
10
|
-
export * from '../
|
|
11
|
-
export {
|
|
12
|
-
export type {
|
|
4
|
+
export type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';
|
|
5
|
+
export { SCREEN_WIDTHS } from '../inspector/inspector-types';
|
|
6
|
+
export { McpAppHost } from '../inspector/mcp-app-host';
|
|
7
|
+
export type { McpAppHostOptions } from '../inspector/mcp-app-host';
|
|
8
|
+
export { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';
|
|
9
|
+
export type { ResourceCSP } from '../inspector/iframe-resource';
|
|
10
|
+
export * from '../inspector/theme-provider';
|
|
11
|
+
export { createInspectorUrl } from '../inspector/inspector-url';
|
|
12
|
+
export type { InspectorUrlParams } from '../inspector/inspector-url';
|
|
13
13
|
export { toPascalCase, extractResourceKey, extractSimulationKey, findResourceKey, getComponentName, findResourceDirs, } from '../lib/discovery';
|
|
14
14
|
export type { ResourceDirInfo, FsOps } from '../lib/discovery';
|
package/dist/chatgpt/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
|
|
2
2
|
import "../protocol-DJmRaBzO.js";
|
|
3
|
-
import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as
|
|
4
|
-
import { t as
|
|
3
|
+
import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Inspector, v as SCREEN_WIDTHS } from "../inspector-ClhpqKLi.js";
|
|
4
|
+
import { t as createInspectorUrl } from "../inspector-url-DuEFmxLP.js";
|
|
5
5
|
import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-Cgoegt62.js";
|
|
6
6
|
//#region src/chatgpt/index.ts
|
|
7
7
|
var chatgpt_exports = /* @__PURE__ */ __exportAll({
|
|
8
8
|
IframeResource: () => IframeResource,
|
|
9
|
+
Inspector: () => Inspector,
|
|
9
10
|
McpAppHost: () => McpAppHost,
|
|
10
11
|
SCREEN_WIDTHS: () => SCREEN_WIDTHS,
|
|
11
|
-
Simulator: () => Simulator,
|
|
12
12
|
ThemeProvider: () => ThemeProvider,
|
|
13
|
-
|
|
13
|
+
createInspectorUrl: () => createInspectorUrl,
|
|
14
14
|
extractResourceCSP: () => extractResourceCSP,
|
|
15
15
|
extractResourceKey: () => extractResourceKey,
|
|
16
16
|
extractSimulationKey: () => extractSimulationKey,
|
|
@@ -22,6 +22,6 @@ var chatgpt_exports = /* @__PURE__ */ __exportAll({
|
|
|
22
22
|
useThemeContext: () => useThemeContext
|
|
23
23
|
});
|
|
24
24
|
//#endregion
|
|
25
|
-
export { IframeResource, McpAppHost, SCREEN_WIDTHS,
|
|
25
|
+
export { IframeResource, Inspector, McpAppHost, SCREEN_WIDTHS, ThemeProvider, createInspectorUrl, extractResourceCSP, extractResourceKey, extractSimulationKey, findResourceDirs, findResourceKey, getComponentName, resolveServerToolResult, chatgpt_exports as t, toPascalCase, useThemeContext };
|
|
26
26
|
|
|
27
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak inspector.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Inspector\nexport { Inspector } from '../inspector/inspector';\n\n// Inspector types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';\nexport { SCREEN_WIDTHS } from '../inspector/inspector-types';\n\n// Host bridge (for building custom inspectors or test harnesses)\nexport { McpAppHost } from '../inspector/mcp-app-host';\nexport type { McpAppHostOptions } from '../inspector/mcp-app-host';\n\n// Iframe rendering (used internally by inspector)\nexport { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';\nexport type { ResourceCSP } from '../inspector/iframe-resource';\n\n// Theme provider\nexport * from '../inspector/theme-provider';\n\n// URL helpers\nexport { createInspectorUrl } from '../inspector/inspector-url';\nexport type { InspectorUrlParams } from '../inspector/inspector-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}
|