sunpeak 0.14.3 → 0.15.4
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 +34 -30
- package/bin/commands/build.mjs +2 -1
- package/bin/commands/dev.mjs +72 -2
- package/dist/chatgpt/{conversation.d.ts → chatgpt-conversation.d.ts} +1 -1
- package/dist/chatgpt/chatgpt-host.d.ts +1 -0
- package/dist/chatgpt/globals.css +618 -6156
- package/dist/chatgpt/index.cjs +11 -8
- package/dist/chatgpt/index.cjs.map +1 -1
- package/dist/chatgpt/index.d.ts +10 -32
- package/dist/chatgpt/index.js +15 -12
- package/dist/chatgpt/index.js.map +1 -1
- package/dist/claude/claude-conversation.d.ts +23 -0
- package/dist/claude/claude-host.d.ts +1 -0
- package/dist/claude/index.cjs +5 -0
- package/dist/claude/index.cjs.map +1 -0
- package/dist/claude/index.d.ts +1 -0
- package/dist/claude/index.js +5 -0
- package/dist/claude/index.js.map +1 -0
- package/dist/{discovery-COZUnY6a.js → discovery-DzV3HLXs.js} +5 -5
- package/dist/{discovery-COZUnY6a.js.map → discovery-DzV3HLXs.js.map} +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/use-app-tools.d.ts +44 -0
- package/dist/hooks/use-update-model-context.d.ts +29 -0
- package/dist/index-B0dxRJvS.cjs +42 -0
- package/dist/index-B0dxRJvS.cjs.map +1 -0
- package/dist/index-Ce_5ZIdJ.js +512 -0
- package/dist/index-Ce_5ZIdJ.js.map +1 -0
- package/dist/index-Cngntkp2.cjs +527 -0
- package/dist/index-Cngntkp2.cjs.map +1 -0
- package/dist/index-CutQgPzR.js +43 -0
- package/dist/index-CutQgPzR.js.map +1 -0
- package/dist/index.cjs +1705 -1647
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2732 -2675
- package/dist/index.js.map +1 -1
- package/dist/lib/default-style-variables.d.ts +2 -0
- package/dist/lib/discovery-cli.js +1 -1
- package/dist/mcp/index.cjs +86 -27
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.d.ts +3 -1
- package/dist/mcp/index.js +85 -26
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +4 -3
- package/dist/mcp/types.d.ts +11 -0
- package/dist/platform/chatgpt/index.cjs +1 -1
- package/dist/platform/chatgpt/index.js +1 -1
- package/dist/platform/index.cjs +3 -0
- package/dist/platform/index.cjs.map +1 -1
- package/dist/platform/index.d.ts +3 -1
- package/dist/platform/index.js +3 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/{protocol-BQCnIrc9.js → protocol-DFbsCx7E.js} +29 -29
- package/dist/{protocol-BQCnIrc9.js.map → protocol-DFbsCx7E.js.map} +1 -1
- package/dist/simulator/host-styles.d.ts +5 -0
- package/dist/simulator/hosts.d.ts +73 -0
- package/dist/{chatgpt → simulator}/iframe-resource.d.ts +27 -3
- package/dist/simulator/index.cjs +39 -0
- package/dist/simulator/index.cjs.map +1 -0
- package/dist/simulator/index.d.ts +18 -0
- package/dist/simulator/index.js +39 -0
- package/dist/simulator/index.js.map +1 -0
- package/dist/{chatgpt → simulator}/mcp-app-host.d.ts +8 -1
- package/dist/simulator/mock-openai-runtime.d.ts +20 -0
- package/dist/{chatgpt → simulator}/simulator-url.d.ts +8 -1
- package/dist/simulator/simulator.d.ts +12 -0
- package/dist/{chatgpt → simulator}/theme-provider.d.ts +3 -1
- package/dist/simulator/use-simulator-state.d.ts +91 -0
- package/dist/simulator-CxrtnguM.js +8764 -0
- package/dist/simulator-CxrtnguM.js.map +1 -0
- package/dist/simulator-DcfQBRXE.cjs +8779 -0
- package/dist/simulator-DcfQBRXE.cjs.map +1 -0
- package/dist/simulator-url-CuLqtnSS.js +48 -0
- package/dist/simulator-url-CuLqtnSS.js.map +1 -0
- package/dist/simulator-url-rgg_KYOg.cjs +47 -0
- package/dist/simulator-url-rgg_KYOg.cjs.map +1 -0
- package/dist/style.css +558 -6143
- package/dist/types/runtime.d.ts +1 -1
- package/dist/{use-app-D7kRAPSG.cjs → use-app-BnoSPiUT.cjs} +2 -1
- package/dist/{use-app-D7kRAPSG.cjs.map → use-app-BnoSPiUT.cjs.map} +1 -1
- package/dist/{use-app-Dvr4LKs2.js → use-app-D_TeaMFG.js} +4 -3
- package/dist/{use-app-Dvr4LKs2.js.map → use-app-D_TeaMFG.js.map} +1 -1
- package/package.json +18 -3
- package/template/.sunpeak/dev.tsx +4 -4
- package/template/.sunpeak/resource-loader.html +1 -1
- package/template/README.md +1 -1
- package/template/node_modules/.bin/nodemon +2 -2
- package/template/node_modules/.bin/playwright +2 -2
- package/template/node_modules/.bin/sunpeak +2 -2
- package/template/node_modules/.bin/tsc +2 -2
- package/template/node_modules/.bin/tsserver +2 -2
- package/template/node_modules/.bin/tsx +2 -2
- package/template/node_modules/.bin/vite +2 -2
- package/template/src/components/avatar.tsx +4 -1
- package/template/src/components/button.tsx +17 -20
- package/template/src/resources/albums/albums-resource.tsx +2 -3
- package/template/src/resources/albums/components/album-card.tsx +4 -2
- package/template/src/resources/albums/components/film-strip.test.tsx +2 -2
- package/template/src/resources/albums/components/film-strip.tsx +2 -2
- package/template/src/resources/albums/components/fullscreen-viewer.tsx +7 -5
- package/template/src/resources/carousel/carousel-resource.tsx +2 -3
- package/template/src/resources/carousel/components/card.test.tsx +3 -2
- package/template/src/resources/carousel/components/card.tsx +8 -4
- package/template/src/resources/map/components/map-view.tsx +1 -1
- package/template/src/resources/map/components/map.tsx +1 -1
- package/template/src/resources/map/components/place-card.tsx +8 -4
- package/template/src/resources/map/components/place-carousel.tsx +1 -1
- package/template/src/resources/map/components/place-inspector.tsx +15 -7
- package/template/src/resources/map/components/place-list.tsx +7 -4
- package/template/src/resources/map/map-resource.tsx +0 -2
- package/template/src/resources/review/review-resource.tsx +61 -27
- package/template/tests/e2e/albums.spec.ts +118 -102
- package/template/tests/e2e/carousel.spec.ts +103 -100
- package/template/tests/e2e/map.spec.ts +220 -181
- package/template/tests/e2e/review.spec.ts +224 -198
- package/dist/_commonjsHelpers-Bc2YnDe1.cjs +0 -8
- package/dist/_commonjsHelpers-Bc2YnDe1.cjs.map +0 -1
- package/dist/_commonjsHelpers-DWwsNxpa.js +0 -9
- package/dist/_commonjsHelpers-DWwsNxpa.js.map +0 -1
- package/dist/index-CJ3jfcjj.js +0 -15131
- package/dist/index-CJ3jfcjj.js.map +0 -1
- package/dist/index-Cdeg96So.cjs +0 -15147
- package/dist/index-Cdeg96So.cjs.map +0 -1
- /package/dist/{chatgpt → simulator}/simple-sidebar.d.ts +0 -0
- /package/dist/{chatgpt/chatgpt-simulator-types.d.ts → simulator/simulator-types.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -23,13 +23,13 @@ Quickstart, build, test, and ship your Claude or ChatGPT App!
|
|
|
23
23
|
[Demo (Hosted)](https://sunpeak.ai/simulator) ~
|
|
24
24
|
[Demo (Video)](https://cdn.sunpeak.ai/sunpeak-demo-prod.mp4) ~
|
|
25
25
|
[Discord (NEW)](https://discord.gg/FB2QNXqRnw) ~
|
|
26
|
-
[Documentation](https://
|
|
26
|
+
[Documentation](https://sunpeak.ai/docs) ~
|
|
27
27
|
[GitHub](https://github.com/Sunpeak-AI/sunpeak)
|
|
28
28
|
|
|
29
29
|
<div align="center">
|
|
30
|
-
<a href="https://
|
|
30
|
+
<a href="https://sunpeak.ai/docs/library/simulator">
|
|
31
31
|
<picture>
|
|
32
|
-
<img alt="
|
|
32
|
+
<img alt="Simulator" src="https://cdn.sunpeak.ai/chatgpt-simulator.png">
|
|
33
33
|
</picture>
|
|
34
34
|
</a>
|
|
35
35
|
</div>
|
|
@@ -43,7 +43,7 @@ pnpm add -g sunpeak
|
|
|
43
43
|
sunpeak new
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
To add `sunpeak` to an existing project, refer to the [documentation](https://
|
|
46
|
+
To add `sunpeak` to an existing project, refer to the [documentation](https://sunpeak.ai/docs/add-to-existing-project).
|
|
47
47
|
|
|
48
48
|
## Overview
|
|
49
49
|
|
|
@@ -51,9 +51,9 @@ To add `sunpeak` to an existing project, refer to the [documentation](https://do
|
|
|
51
51
|
|
|
52
52
|
### The `sunpeak` library
|
|
53
53
|
|
|
54
|
-
1. Runtime APIs: Strongly typed React hooks for interacting with the host runtime (`useApp`, `useToolData`, `useAppState`, `useHostContext`), architected to **support generic and
|
|
55
|
-
2.
|
|
56
|
-
3. MCP server: Serve Resources with mock data to
|
|
54
|
+
1. Runtime APIs: Strongly typed React hooks for interacting with the host runtime (`useApp`, `useToolData`, `useAppState`, `useHostContext`, `useUpdateModelContext`, `useAppTools`), architected to **support generic and platform-specific features** (ChatGPT, Claude, etc.). Platform-specific hooks like `useUploadFile`, `useRequestModal`, and `useRequestCheckout` are available via `sunpeak/platform/chatgpt`, with `isChatGPT()` / `isClaude()` platform detection via `sunpeak/platform`.
|
|
55
|
+
2. Multi-host simulator: React component replicating host runtimes (ChatGPT, Claude) to **test Apps locally and automatically** via UI, props, or URL parameters.
|
|
56
|
+
3. MCP server: Serve Resources with mock data to hosts like ChatGPT and Claude with HMR (**no more cache issues or 5-click manual refreshes**).
|
|
57
57
|
|
|
58
58
|
### The `sunpeak` framework
|
|
59
59
|
|
|
@@ -72,10 +72,10 @@ my-app/
|
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
1. Project scaffold: Complete development setup with the `sunpeak` library.
|
|
75
|
-
2. UI components: Production-ready components following
|
|
75
|
+
2. UI components: Production-ready components following MCP App design guidelines.
|
|
76
76
|
3. Convention over configuration:
|
|
77
77
|
1. Create a UI by creating a `-resource.tsx` file that exports a `ResourceConfig` and a React component ([example below](#resource-component)).
|
|
78
|
-
2. Create test state (`Simulation`s) for local dev,
|
|
78
|
+
2. Create test state (`Simulation`s) for local dev, host dev, automated testing, and demos by creating a `-simulation.json` file. ([example below](#simulation))
|
|
79
79
|
|
|
80
80
|
### The `sunpeak` CLI
|
|
81
81
|
|
|
@@ -88,7 +88,7 @@ Commands for managing MCP Apps:
|
|
|
88
88
|
|
|
89
89
|
## Example App
|
|
90
90
|
|
|
91
|
-
Example `Resource`, `Simulation`, and testing file (using `
|
|
91
|
+
Example `Resource`, `Simulation`, and testing file (using the `Simulator`) for an MCP resource called "Review".
|
|
92
92
|
|
|
93
93
|
### `Resource` Component
|
|
94
94
|
|
|
@@ -110,7 +110,7 @@ import type { ResourceConfig } from 'sunpeak';
|
|
|
110
110
|
export const resource: ResourceConfig = {
|
|
111
111
|
name: 'review',
|
|
112
112
|
description: 'Visualize and review a code change',
|
|
113
|
-
_meta: { ui: { csp: { resourceDomains: ['https://cdn.
|
|
113
|
+
_meta: { ui: { csp: { resourceDomains: ['https://cdn.example.com'] } } },
|
|
114
114
|
};
|
|
115
115
|
|
|
116
116
|
export function ReviewResource() {
|
|
@@ -165,7 +165,7 @@ Testing an MCP App requires setting a lot of state: state in your **backend**, *
|
|
|
165
165
|
}
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
### `
|
|
168
|
+
### `Simulator`
|
|
169
169
|
|
|
170
170
|
```bash
|
|
171
171
|
├── tests/e2e/
|
|
@@ -173,34 +173,38 @@ Testing an MCP App requires setting a lot of state: state in your **backend**, *
|
|
|
173
173
|
└── package.json
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
The `
|
|
176
|
+
The `Simulator` 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`).
|
|
177
177
|
|
|
178
|
-
Using the `
|
|
178
|
+
Using the `Simulator` and `Simulation`s, you can test all possible App states locally and automatically across hosts (ChatGPT, Claude)!
|
|
179
179
|
|
|
180
180
|
```ts
|
|
181
181
|
// tests/e2e/review.spec.ts
|
|
182
182
|
|
|
183
183
|
import { test, expect } from '@playwright/test';
|
|
184
|
-
import { createSimulatorUrl } from 'sunpeak/
|
|
184
|
+
import { createSimulatorUrl } from 'sunpeak/simulator';
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
test.describe('Light Mode', () => {
|
|
188
|
-
test('should render review title with correct styles', async ({ page }) => {
|
|
189
|
-
const params = { simulation: 'review-diff', theme: 'light' }; // Set sim & host state.
|
|
190
|
-
await page.goto(createSimulatorUrl(params));
|
|
186
|
+
const hosts = ['chatgpt', 'claude'] as const;
|
|
191
187
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
for (const host of hosts) {
|
|
189
|
+
test.describe(`Review Resource [${host}]`, () => {
|
|
190
|
+
test.describe('Light Mode', () => {
|
|
191
|
+
test('should render review title with correct styles', async ({ page }) => {
|
|
192
|
+
const params = { simulation: 'review-diff', theme: 'light', host }; // Set sim & host state.
|
|
193
|
+
await page.goto(createSimulatorUrl(params));
|
|
196
194
|
|
|
197
|
-
|
|
195
|
+
// Resource content renders inside an iframe
|
|
196
|
+
const iframe = page.frameLocator('iframe');
|
|
197
|
+
const title = iframe.locator('h1:has-text("Refactor Authentication Module")');
|
|
198
|
+
await expect(title).toBeVisible();
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
const color = await title.evaluate((el) => window.getComputedStyle(el).color);
|
|
201
|
+
|
|
202
|
+
// Light mode should render dark text.
|
|
203
|
+
expect(color).toBe('rgb(13, 13, 13)');
|
|
204
|
+
});
|
|
201
205
|
});
|
|
202
206
|
});
|
|
203
|
-
}
|
|
207
|
+
}
|
|
204
208
|
```
|
|
205
209
|
|
|
206
210
|
## Coding Agent Skill
|
|
@@ -214,5 +218,5 @@ npx skills add Sunpeak-AI/sunpeak@create-sunpeak-app
|
|
|
214
218
|
## Resources
|
|
215
219
|
|
|
216
220
|
- [MCP Apps](https://github.com/modelcontextprotocol/ext-apps)
|
|
217
|
-
- [
|
|
218
|
-
- [
|
|
221
|
+
- [MCP Apps SDK Design Guidelines](https://developers.openai.com/apps-sdk/concepts/design-guidelines)
|
|
222
|
+
- [MCP Apps SDK Documentation - UI](https://developers.openai.com/apps-sdk/build/chatgpt-ui)
|
package/bin/commands/build.mjs
CHANGED
|
@@ -225,6 +225,7 @@ export async function build(projectRoot = process.cwd()) {
|
|
|
225
225
|
|
|
226
226
|
// Build with vite programmatically
|
|
227
227
|
await viteBuild({
|
|
228
|
+
mode: 'production',
|
|
228
229
|
root: projectRoot,
|
|
229
230
|
plugins: [react(), tailwindcss(), inlineCssPlugin(buildOutDir)],
|
|
230
231
|
define: {
|
|
@@ -261,7 +262,7 @@ export async function build(projectRoot = process.cwd()) {
|
|
|
261
262
|
},
|
|
262
263
|
});
|
|
263
264
|
} catch (error) {
|
|
264
|
-
console.error(`Failed to build ${
|
|
265
|
+
console.error(`Failed to build ${kebabName}`);
|
|
265
266
|
console.error(error);
|
|
266
267
|
process.exit(1);
|
|
267
268
|
}
|
package/bin/commands/dev.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
const { existsSync, readFileSync } = fs;
|
|
4
|
+
const { existsSync, readFileSync, watch: fsWatch } = fs;
|
|
5
5
|
const { join, resolve, basename, dirname } = path;
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import { pathToFileURL } from 'url';
|
|
8
|
+
import { spawn } from 'child_process';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Import a module from the project's node_modules using ESM resolution
|
|
@@ -54,6 +55,68 @@ async function importFromProject(require, moduleName) {
|
|
|
54
55
|
return import(pathToFileURL(entryPath).href);
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Run an initial production build and watch source files for changes.
|
|
60
|
+
* Tunnel clients (e.g. Claude via ngrok) are served the pre-built HTML since they
|
|
61
|
+
* can't reach the local Vite dev server. This keeps the prod output up to date.
|
|
62
|
+
*
|
|
63
|
+
* When a file changes during a build, the current build is killed and restarted.
|
|
64
|
+
*/
|
|
65
|
+
function startBuildWatcher(projectRoot, resourcesDir, mcpHandle) {
|
|
66
|
+
let activeChild = null;
|
|
67
|
+
const sunpeakBin = join(dirname(new URL(import.meta.url).pathname), '..', 'sunpeak.js');
|
|
68
|
+
|
|
69
|
+
const runBuild = (reason) => {
|
|
70
|
+
// Kill any in-progress build and start fresh
|
|
71
|
+
if (activeChild) {
|
|
72
|
+
activeChild.kill('SIGTERM');
|
|
73
|
+
activeChild = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`[build] ${reason}`);
|
|
77
|
+
const child = spawn(process.execPath, [sunpeakBin, 'build'], {
|
|
78
|
+
cwd: projectRoot,
|
|
79
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
80
|
+
env: { ...process.env, NODE_ENV: 'production' },
|
|
81
|
+
});
|
|
82
|
+
activeChild = child;
|
|
83
|
+
|
|
84
|
+
child.on('exit', (code) => {
|
|
85
|
+
if (child !== activeChild) return; // Superseded by a newer build
|
|
86
|
+
activeChild = null;
|
|
87
|
+
if (code === 0) {
|
|
88
|
+
// Notify non-local sessions (Claude, etc.) that resources changed
|
|
89
|
+
mcpHandle?.invalidateResources();
|
|
90
|
+
} else if (code !== null) {
|
|
91
|
+
console.error(`[build] Failed (exit ${code})`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Initial build
|
|
97
|
+
runBuild('Initial production build for tunnel clients...');
|
|
98
|
+
|
|
99
|
+
// Watch src/resources/ for changes using fs.watch (recursive supported on macOS/Windows)
|
|
100
|
+
let debounceTimer = null;
|
|
101
|
+
try {
|
|
102
|
+
fsWatch(resourcesDir, { recursive: true }, (_event, filename) => {
|
|
103
|
+
if (!filename) return;
|
|
104
|
+
// Only rebuild on source file changes
|
|
105
|
+
if (!/\.(tsx?|css)$/.test(filename)) return;
|
|
106
|
+
// Skip test files
|
|
107
|
+
if (/\.(test|spec)\.tsx?$/.test(filename)) return;
|
|
108
|
+
|
|
109
|
+
clearTimeout(debounceTimer);
|
|
110
|
+
debounceTimer = setTimeout(() => {
|
|
111
|
+
runBuild(`Rebuilding (${filename} changed)...`);
|
|
112
|
+
}, 500);
|
|
113
|
+
});
|
|
114
|
+
console.log('[build] Watching src/resources/ for changes...');
|
|
115
|
+
} catch {
|
|
116
|
+
console.warn('[build] Could not start file watcher — run "sunpeak build" manually after changes');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
57
120
|
/**
|
|
58
121
|
* Start the Vite development server
|
|
59
122
|
* Runs in the context of a user's project directory
|
|
@@ -281,7 +344,7 @@ if (import.meta.hot) {
|
|
|
281
344
|
}
|
|
282
345
|
|
|
283
346
|
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
284
|
-
runMCPServer({
|
|
347
|
+
const mcpHandle = runMCPServer({
|
|
285
348
|
name: pkg.name || 'Sunpeak',
|
|
286
349
|
version: pkg.version || '0.1.0',
|
|
287
350
|
simulations,
|
|
@@ -289,6 +352,13 @@ if (import.meta.hot) {
|
|
|
289
352
|
...(mcpViteServer && { viteServer: mcpViteServer }),
|
|
290
353
|
});
|
|
291
354
|
|
|
355
|
+
// Build production bundles and watch for changes.
|
|
356
|
+
// Tunnel clients (e.g. Claude via ngrok) get the pre-built HTML since they can't
|
|
357
|
+
// reach the local Vite dev server. The watcher rebuilds on source file changes
|
|
358
|
+
// so the prod output stays fresh without manual `sunpeak build`.
|
|
359
|
+
// On successful builds, mcpHandle.invalidateResources() notifies tunnel sessions.
|
|
360
|
+
startBuildWatcher(projectRoot, resourcesDir, mcpHandle);
|
|
361
|
+
|
|
292
362
|
// Handle signals - close both servers
|
|
293
363
|
process.on('SIGINT', async () => {
|
|
294
364
|
if (mcpViteServer) await mcpViteServer.close();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ScreenWidth } from '
|
|
1
|
+
import { ScreenWidth } from '../simulator/simulator-types';
|
|
2
2
|
import { McpUiDisplayMode, McpUiHostContext } from '@modelcontextprotocol/ext-apps';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
type Platform = NonNullable<McpUiHostContext['platform']>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|