sunpeak 0.16.17 → 0.16.21
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 +2 -2
- package/bin/commands/build.mjs +1 -1
- package/bin/commands/dev.mjs +137 -19
- package/bin/commands/new.mjs +21 -2
- package/bin/commands/start.mjs +1 -1
- package/dist/chatgpt/chatgpt-conversation.d.ts +3 -1
- package/dist/chatgpt/globals.css +37 -8
- package/dist/chatgpt/index.cjs +3 -5
- package/dist/chatgpt/index.cjs.map +1 -1
- package/dist/chatgpt/index.d.ts +0 -1
- package/dist/chatgpt/index.js +3 -5
- package/dist/chatgpt/index.js.map +1 -1
- package/dist/claude/claude-conversation.d.ts +3 -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/{discovery-DvIQWTez.js → discovery-BVqD-JsT.js} +4 -2
- package/dist/{discovery-DvIQWTez.js.map → discovery-BVqD-JsT.js.map} +1 -1
- package/dist/{discovery-SviNiBkF.cjs → discovery-D1gpaVz4.cjs} +4 -2
- package/dist/{discovery-SviNiBkF.cjs.map → discovery-D1gpaVz4.cjs.map} +1 -1
- package/dist/hooks/index.d.ts +10 -1
- package/dist/hooks/safe-area.d.ts +6 -2
- package/dist/hooks/use-device-capabilities.d.ts +3 -0
- package/dist/hooks/use-platform.d.ts +3 -0
- package/dist/hooks/use-styles.d.ts +2 -0
- package/dist/hooks/use-time-zone.d.ts +1 -0
- package/dist/hooks/use-tool-info.d.ts +3 -0
- package/dist/hooks/use-user-agent.d.ts +1 -0
- package/dist/hooks/use-viewport.d.ts +3 -0
- package/dist/{platform → host}/chatgpt/index.cjs +1 -1
- package/dist/host/chatgpt/index.cjs.map +1 -0
- package/dist/{platform → host}/chatgpt/index.d.ts +2 -2
- package/dist/{platform → host}/chatgpt/index.js +1 -1
- package/dist/host/chatgpt/index.js.map +1 -0
- package/dist/{platform → host}/chatgpt/use-create-file.d.ts +2 -2
- package/dist/{platform → host}/chatgpt/use-file-download.d.ts +2 -2
- package/dist/{platform → host}/chatgpt/use-open-modal.d.ts +2 -2
- package/dist/{platform → host}/chatgpt/use-request-checkout.d.ts +2 -2
- package/dist/{platform → host}/index.cjs +5 -3
- package/dist/host/index.cjs.map +1 -0
- package/dist/{platform → host}/index.d.ts +15 -11
- package/dist/{platform → host}/index.js +5 -3
- package/dist/host/index.js.map +1 -0
- package/dist/{index-CsYoMHyn.js → index-B4aC3vjH.js} +4 -4
- package/dist/index-B4aC3vjH.js.map +1 -0
- package/dist/{index-DHcaJ5PU.cjs → index-CKabCJyV.cjs} +4 -4
- package/dist/index-CKabCJyV.cjs.map +1 -0
- package/dist/index-CX6Z4bED.js +29 -0
- package/dist/index-CX6Z4bED.js.map +1 -0
- package/dist/index-bKBBCBK6.cjs +28 -0
- package/dist/index-bKBBCBK6.cjs.map +1 -0
- package/dist/index.cjs +233 -6297
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +228 -6292
- package/dist/index.js.map +1 -1
- package/dist/lib/discovery-cli.cjs +1 -1
- package/dist/lib/discovery-cli.js +1 -1
- package/dist/mcp/index.cjs +680 -6766
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +682 -6768
- package/dist/mcp/index.js.map +1 -1
- package/dist/{protocol-CfvM5B6z.cjs → protocol-DkDHRwOW.cjs} +50 -5
- package/dist/{protocol-CfvM5B6z.cjs.map → protocol-DkDHRwOW.cjs.map} +1 -1
- package/dist/{protocol-CF-P_kw5.js → protocol-uge7qFev.js} +102 -57
- package/dist/{protocol-CF-P_kw5.js.map → protocol-uge7qFev.js.map} +1 -1
- package/dist/simulator/hosts.d.ts +2 -0
- package/dist/simulator/index.cjs +3 -3
- package/dist/simulator/index.js +3 -3
- package/dist/simulator/simple-sidebar.d.ts +18 -4
- package/dist/simulator/simulator-url.d.ts +8 -0
- package/dist/simulator/simulator.d.ts +13 -1
- package/dist/simulator/use-simulator-state.d.ts +10 -6
- package/dist/simulator-D8t-r7HH.js +3222 -0
- package/dist/simulator-D8t-r7HH.js.map +1 -0
- package/dist/simulator-FFNttkqL.cjs +3237 -0
- package/dist/simulator-FFNttkqL.cjs.map +1 -0
- package/dist/{simulator-url-rgg_KYOg.cjs → simulator-url-DcSYRl-P.cjs} +7 -1
- package/dist/simulator-url-DcSYRl-P.cjs.map +1 -0
- package/dist/{simulator-url-CuLqtnSS.js → simulator-url-j_XV3EoP.js} +7 -1
- package/dist/simulator-url-j_XV3EoP.js.map +1 -0
- package/dist/style.css +37 -8
- package/dist/use-app-C9gpzIQO.js +349 -0
- package/dist/use-app-C9gpzIQO.js.map +1 -0
- package/dist/use-app-D09O2swh.cjs +348 -0
- package/dist/use-app-D09O2swh.cjs.map +1 -0
- package/package.json +26 -14
- package/template/.sunpeak/dev.tsx +28 -2
- package/template/node_modules/.bin/vite +2 -2
- package/template/node_modules/.bin/vitest +2 -2
- package/template/package.json +5 -5
- package/template/playwright.config.ts +6 -3
- package/template/src/resources/albums/albums.test.tsx +1 -0
- package/template/src/resources/albums/albums.tsx +5 -2
- package/template/src/resources/albums/components/albums.test.tsx +22 -18
- package/template/src/resources/albums/components/albums.tsx +63 -7
- package/template/src/resources/albums/components/fullscreen-viewer.test.tsx +3 -25
- package/template/src/resources/albums/components/fullscreen-viewer.tsx +2 -3
- package/template/src/resources/carousel/carousel.test.tsx +12 -16
- package/template/src/resources/carousel/carousel.tsx +47 -5
- package/template/src/resources/map/components/map.tsx +65 -9
- package/template/src/resources/map/map.test.tsx +0 -1
- package/template/src/resources/review/review.test.tsx +25 -27
- package/template/src/resources/review/review.tsx +85 -63
- package/template/src/tools/review-diff.test.ts +73 -0
- package/template/src/tools/review-diff.ts +29 -2
- package/template/src/tools/review-post.test.ts +100 -0
- package/template/src/tools/review-post.ts +30 -2
- package/template/src/tools/review-purchase.test.ts +111 -0
- package/template/src/tools/review-purchase.ts +35 -2
- package/template/src/tools/review.test.ts +40 -0
- package/template/src/tools/review.ts +4 -1
- package/template/src/tools/show-albums.test.ts +42 -0
- package/template/src/tools/show-albums.ts +22 -2
- package/template/src/tools/show-carousel.test.ts +45 -0
- package/template/src/tools/show-carousel.ts +19 -2
- package/template/src/tools/show-map.test.ts +74 -0
- package/template/src/tools/show-map.ts +21 -2
- package/template/tests/e2e/albums.spec.ts +75 -0
- package/template/tests/e2e/carousel.spec.ts +65 -0
- package/template/tests/e2e/global-setup.ts +25 -0
- package/template/tests/e2e/map.spec.ts +60 -0
- package/template/tests/e2e/review.spec.ts +72 -11
- package/dist/chatgpt/chatgpt-simulator.d.ts +0 -10
- package/dist/index-BFD3bAHd.cjs +0 -547
- package/dist/index-BFD3bAHd.cjs.map +0 -1
- package/dist/index-CsYoMHyn.js.map +0 -1
- package/dist/index-DHcaJ5PU.cjs.map +0 -1
- package/dist/index-wUvmyoCx.js +0 -532
- package/dist/index-wUvmyoCx.js.map +0 -1
- package/dist/platform/chatgpt/index.cjs.map +0 -1
- package/dist/platform/chatgpt/index.js.map +0 -1
- package/dist/platform/index.cjs.map +0 -1
- package/dist/platform/index.js.map +0 -1
- package/dist/simulator-BEFsuj9Z.cjs +0 -8872
- package/dist/simulator-BEFsuj9Z.cjs.map +0 -1
- package/dist/simulator-Da9iAupa.js +0 -8857
- package/dist/simulator-Da9iAupa.js.map +0 -1
- package/dist/simulator-url-CuLqtnSS.js.map +0 -1
- package/dist/simulator-url-rgg_KYOg.cjs.map +0 -1
- package/dist/use-app-CaTJmpgj.cjs +0 -6449
- package/dist/use-app-CaTJmpgj.cjs.map +0 -1
- package/dist/use-app-DTTzqi-0.js +0 -6450
- package/dist/use-app-DTTzqi-0.js.map +0 -1
- /package/dist/{platform → host}/chatgpt/openai-types.d.ts +0 -0
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
Local-first MCP Apps framework.
|
|
20
20
|
|
|
21
|
-
Quickstart, build, test, and ship your Claude or ChatGPT App!
|
|
21
|
+
Quickstart, build, test, and ship your Claude Connector or ChatGPT App!
|
|
22
22
|
|
|
23
23
|
[Demo (Hosted)](https://sunpeak.ai/simulator) ~
|
|
24
24
|
[Demo (Video)](https://cdn.sunpeak.ai/sunpeak-demo-prod.mp4) ~
|
|
@@ -49,7 +49,7 @@ sunpeak new
|
|
|
49
49
|
|
|
50
50
|
### The `sunpeak` library
|
|
51
51
|
|
|
52
|
-
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.).
|
|
52
|
+
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.). Host-specific hooks like `useUploadFile`, `useRequestModal`, and `useRequestCheckout` are available via `sunpeak/host/chatgpt`, with `isChatGPT()` / `isClaude()` host detection via `sunpeak/host`.
|
|
53
53
|
2. Multi-host simulator: React component replicating host runtimes (ChatGPT, Claude) to **test Apps locally and automatically** via UI, props, or URL parameters.
|
|
54
54
|
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**).
|
|
55
55
|
|
package/bin/commands/build.mjs
CHANGED
|
@@ -355,7 +355,7 @@ ${jsContents}
|
|
|
355
355
|
|
|
356
356
|
// Find tool files
|
|
357
357
|
const toolFiles = existsSync(toolsDir)
|
|
358
|
-
? readdirSync(toolsDir).filter(f => f.endsWith('.ts'))
|
|
358
|
+
? readdirSync(toolsDir).filter(f => f.endsWith('.ts') && !f.endsWith('.test.ts'))
|
|
359
359
|
: [];
|
|
360
360
|
|
|
361
361
|
const hasServerEntry = existsSync(serverEntryPath);
|
package/bin/commands/dev.mjs
CHANGED
|
@@ -62,7 +62,7 @@ async function importFromProject(require, moduleName) {
|
|
|
62
62
|
*
|
|
63
63
|
* When a file changes during a build, the current build is killed and restarted.
|
|
64
64
|
*/
|
|
65
|
-
function startBuildWatcher(projectRoot, resourcesDir, mcpHandle) {
|
|
65
|
+
function startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBuild = false } = {}) {
|
|
66
66
|
let activeChild = null;
|
|
67
67
|
const sunpeakBin = join(dirname(new URL(import.meta.url).pathname), '..', 'sunpeak.js');
|
|
68
68
|
|
|
@@ -94,8 +94,10 @@ function startBuildWatcher(projectRoot, resourcesDir, mcpHandle) {
|
|
|
94
94
|
});
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
// Initial build
|
|
98
|
-
|
|
97
|
+
// Initial build (skip when --prod-resources already ran a synchronous build)
|
|
98
|
+
if (!skipInitialBuild) {
|
|
99
|
+
runBuild();
|
|
100
|
+
}
|
|
99
101
|
|
|
100
102
|
// Watch src/resources/ for changes using fs.watch (recursive supported on macOS/Windows)
|
|
101
103
|
let debounceTimer = null;
|
|
@@ -150,6 +152,13 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
150
152
|
// Parse --no-begging flag
|
|
151
153
|
const noBegging = args.includes('--no-begging');
|
|
152
154
|
|
|
155
|
+
// Parse --prod-tools and --prod-resources flags
|
|
156
|
+
const isProdTools = args.includes('--prod-tools');
|
|
157
|
+
const isProdResources = args.includes('--prod-resources');
|
|
158
|
+
|
|
159
|
+
if (isProdTools) console.log('Prod Tools enabled by default (toggle in simulator sidebar)');
|
|
160
|
+
if (isProdResources) console.log('Prod Resources: resources will use production-built HTML from dist/');
|
|
161
|
+
|
|
153
162
|
console.log(`Starting Vite dev server on port ${port}...`);
|
|
154
163
|
|
|
155
164
|
// Check if we're in the sunpeak workspace (directory is named "template")
|
|
@@ -197,10 +206,96 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
197
206
|
},
|
|
198
207
|
});
|
|
199
208
|
|
|
209
|
+
// Vite plugin that proxies callServerTool to real tool handlers
|
|
210
|
+
const sunpeakCallToolPlugin = () => ({
|
|
211
|
+
name: 'sunpeak-call-tool',
|
|
212
|
+
configureServer(server) {
|
|
213
|
+
server.middlewares.use('/__sunpeak/call-tool', async (req, res) => {
|
|
214
|
+
if (req.method !== 'POST') {
|
|
215
|
+
res.statusCode = 405;
|
|
216
|
+
res.end('Method not allowed');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const chunks = [];
|
|
220
|
+
for await (const chunk of req) chunks.push(chunk);
|
|
221
|
+
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
222
|
+
const { name, arguments: args } = body;
|
|
223
|
+
const toolEntry = toolPathMap.get(name);
|
|
224
|
+
if (!toolEntry) {
|
|
225
|
+
res.setHeader('Content-Type', 'application/json');
|
|
226
|
+
res.end(JSON.stringify({
|
|
227
|
+
content: [{ type: 'text', text: `[Prod Tools] Tool "${name}" not found` }],
|
|
228
|
+
isError: true,
|
|
229
|
+
}));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
// Re-load the handler module on each call so edits take effect without restart
|
|
234
|
+
const mod = await toolLoaderServer.ssrLoadModule(`./${toolEntry.relativePath}`);
|
|
235
|
+
const handler = mod.default;
|
|
236
|
+
if (typeof handler !== 'function') {
|
|
237
|
+
res.setHeader('Content-Type', 'application/json');
|
|
238
|
+
res.end(JSON.stringify({
|
|
239
|
+
content: [{ type: 'text', text: `[Prod Tools] Tool "${name}" has no default export handler` }],
|
|
240
|
+
isError: true,
|
|
241
|
+
}));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
let result = await handler(args ?? {}, {});
|
|
245
|
+
if (typeof result === 'string') {
|
|
246
|
+
result = { content: [{ type: 'text', text: result }] };
|
|
247
|
+
}
|
|
248
|
+
res.setHeader('Content-Type', 'application/json');
|
|
249
|
+
res.end(JSON.stringify(result));
|
|
250
|
+
} catch (err) {
|
|
251
|
+
res.setHeader('Content-Type', 'application/json');
|
|
252
|
+
res.end(JSON.stringify({
|
|
253
|
+
content: [{ type: 'text', text: `[Prod Tools] Tool error: ${err.message}` }],
|
|
254
|
+
isError: true,
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Vite plugin that serves production-built HTML from dist/
|
|
262
|
+
const sunpeakDistPlugin = () => ({
|
|
263
|
+
name: 'sunpeak-dist',
|
|
264
|
+
configureServer(server) {
|
|
265
|
+
server.middlewares.use('/dist', (req, res, next) => {
|
|
266
|
+
const filePath = join(projectRoot, 'dist', req.url);
|
|
267
|
+
if (filePath.endsWith('.html')) {
|
|
268
|
+
if (existsSync(filePath)) {
|
|
269
|
+
res.setHeader('Content-Type', 'text/html');
|
|
270
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
271
|
+
res.end(readFileSync(filePath));
|
|
272
|
+
} else {
|
|
273
|
+
// Return 404 instead of falling through to Vite's SPA fallback,
|
|
274
|
+
// which would serve the simulator's own index.html.
|
|
275
|
+
res.statusCode = 404;
|
|
276
|
+
res.end();
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
next();
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
200
285
|
// Create and start Vite dev server programmatically
|
|
201
286
|
const server = await createServer({
|
|
202
287
|
root: projectRoot,
|
|
203
|
-
plugins: [
|
|
288
|
+
plugins: [
|
|
289
|
+
react(),
|
|
290
|
+
tailwindcss(),
|
|
291
|
+
sunpeakFaviconPlugin(),
|
|
292
|
+
sunpeakCallToolPlugin(),
|
|
293
|
+
sunpeakDistPlugin(),
|
|
294
|
+
],
|
|
295
|
+
define: {
|
|
296
|
+
'__SUNPEAK_PROD_TOOLS__': JSON.stringify(isProdTools),
|
|
297
|
+
'__SUNPEAK_PROD_RESOURCES__': JSON.stringify(isProdResources),
|
|
298
|
+
},
|
|
204
299
|
resolve: {
|
|
205
300
|
alias: {
|
|
206
301
|
'@': path.resolve(projectRoot, 'src'),
|
|
@@ -216,6 +311,23 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
216
311
|
},
|
|
217
312
|
});
|
|
218
313
|
|
|
314
|
+
// --prod-resources: Run initial production build so dist/ is ready before server starts
|
|
315
|
+
if (isProdResources) {
|
|
316
|
+
console.log('Building production resources...');
|
|
317
|
+
const sunpeakBin = join(dirname(new URL(import.meta.url).pathname), '..', 'sunpeak.js');
|
|
318
|
+
const { execSync } = await import('child_process');
|
|
319
|
+
try {
|
|
320
|
+
execSync(`${process.execPath} ${sunpeakBin} build`, {
|
|
321
|
+
cwd: projectRoot,
|
|
322
|
+
stdio: 'inherit',
|
|
323
|
+
env: { ...process.env, NODE_ENV: 'production' },
|
|
324
|
+
});
|
|
325
|
+
} catch {
|
|
326
|
+
console.error('Build failed. Run `sunpeak build` manually to debug.');
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
219
331
|
await server.listen();
|
|
220
332
|
server.printUrls();
|
|
221
333
|
server.bindCLIShortcuts({ print: true });
|
|
@@ -270,19 +382,21 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
270
382
|
logLevel: 'silent',
|
|
271
383
|
});
|
|
272
384
|
|
|
273
|
-
//
|
|
385
|
+
// Build path map for prod-tools handler reloading (re-imports on each call for HMR).
|
|
386
|
+
// Also do an initial load to validate handlers and populate toolHandlerMap for the MCP server.
|
|
387
|
+
const toolPathMap = new Map();
|
|
274
388
|
const toolHandlerMap = new Map();
|
|
275
389
|
for (const [toolName, { tool, path: toolPath }] of toolMap) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
} catch (err) {
|
|
284
|
-
console.warn(`Warning: Could not load handler for backend-only tool "${toolName}": ${err.message}`);
|
|
390
|
+
void tool; // Used for metadata; handler loaded unconditionally
|
|
391
|
+
const relativePath = path.relative(projectRoot, toolPath);
|
|
392
|
+
toolPathMap.set(toolName, { relativePath });
|
|
393
|
+
try {
|
|
394
|
+
const mod = await toolLoaderServer.ssrLoadModule(`./${relativePath}`);
|
|
395
|
+
if (typeof mod.default === 'function') {
|
|
396
|
+
toolHandlerMap.set(toolName, { handler: mod.default });
|
|
285
397
|
}
|
|
398
|
+
} catch (err) {
|
|
399
|
+
console.warn(`Warning: Could not load handler for tool "${toolName}": ${err.message}`);
|
|
286
400
|
}
|
|
287
401
|
}
|
|
288
402
|
|
|
@@ -328,8 +442,10 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
328
442
|
srcPath,
|
|
329
443
|
resource: resourceMap.get(resourceKey),
|
|
330
444
|
} : {}),
|
|
331
|
-
// Attach real handler
|
|
332
|
-
|
|
445
|
+
// Attach real handler for tools consumed by the MCP server.
|
|
446
|
+
// Backend-only tools (no resource) always need handlers for callServerTool.
|
|
447
|
+
// UI tools only get handlers in --prod-tools mode (otherwise simulation mock data is used).
|
|
448
|
+
...((toolHandlerMap.has(toolName) && (!resourceKey || isProdTools)) ? {
|
|
333
449
|
handler: toolHandlerMap.get(toolName).handler,
|
|
334
450
|
} : {}),
|
|
335
451
|
});
|
|
@@ -422,7 +538,7 @@ if (import.meta.hot) {
|
|
|
422
538
|
},
|
|
423
539
|
server: {
|
|
424
540
|
middlewareMode: true,
|
|
425
|
-
hmr: { port: 24679 },
|
|
541
|
+
hmr: { port: Number(process.env.SUNPEAK_HMR_PORT || 24679) },
|
|
426
542
|
allowedHosts: true,
|
|
427
543
|
watch: {
|
|
428
544
|
// Only watch files that affect the UI bundle (not JSON, tests, etc.)
|
|
@@ -449,7 +565,9 @@ if (import.meta.hot) {
|
|
|
449
565
|
version: pkg.version || '0.1.0',
|
|
450
566
|
simulations,
|
|
451
567
|
port: 8000,
|
|
452
|
-
viteServer
|
|
568
|
+
// In --prod-resources mode, don't pass viteServer so the MCP server serves pre-built HTML.
|
|
569
|
+
// Otherwise, pass it so ChatGPT gets Vite HMR.
|
|
570
|
+
viteServer: isProdResources ? undefined : mcpViteServer,
|
|
453
571
|
});
|
|
454
572
|
|
|
455
573
|
// Build production bundles and watch for changes.
|
|
@@ -457,7 +575,7 @@ if (import.meta.hot) {
|
|
|
457
575
|
// reach the local Vite dev server. The watcher rebuilds on source file changes
|
|
458
576
|
// so the prod output stays fresh without manual `sunpeak build`.
|
|
459
577
|
// On successful builds, mcpHandle.invalidateResources() notifies tunnel sessions.
|
|
460
|
-
startBuildWatcher(projectRoot, resourcesDir, mcpHandle);
|
|
578
|
+
startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBuild: isProdResources });
|
|
461
579
|
|
|
462
580
|
// Handle signals - close all servers
|
|
463
581
|
process.on('SIGINT', async () => {
|
package/bin/commands/new.mjs
CHANGED
|
@@ -73,6 +73,7 @@ export const defaultDeps = {
|
|
|
73
73
|
execAsync,
|
|
74
74
|
promptName: defaultPromptName,
|
|
75
75
|
selectResources: defaultSelectResources,
|
|
76
|
+
confirm: clack.confirm,
|
|
76
77
|
intro: clack.intro,
|
|
77
78
|
outro: clack.outro,
|
|
78
79
|
spinner: clack.spinner,
|
|
@@ -191,9 +192,9 @@ export async function init(projectName, resourcesArg, deps = defaultDeps) {
|
|
|
191
192
|
return false;
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
|
-
// Skip tool files for excluded resources: src/tools/*.ts
|
|
195
|
+
// Skip tool files (and their tests) for excluded resources: src/tools/*.ts
|
|
195
196
|
if (src.includes('/src/tools/') && name.endsWith('.ts')) {
|
|
196
|
-
const baseName = name.replace(/\.ts$/, '');
|
|
197
|
+
const baseName = name.replace(/\.(test\.)?ts$/, '');
|
|
197
198
|
if (baseName === resource || baseName.startsWith(resource + '-') || baseName.endsWith('-' + resource)) {
|
|
198
199
|
return false;
|
|
199
200
|
}
|
|
@@ -266,6 +267,24 @@ export async function init(projectName, resourcesArg, deps = defaultDeps) {
|
|
|
266
267
|
s.stop(`Install failed. You can try running "${pm} install" manually.`);
|
|
267
268
|
}
|
|
268
269
|
|
|
270
|
+
// Offer to install the sunpeak skill (only in interactive mode)
|
|
271
|
+
if (resourcesArg === undefined) {
|
|
272
|
+
const installSkill = await d.confirm({
|
|
273
|
+
message: 'Install the sunpeak skill? (helps your coding agent build your app)',
|
|
274
|
+
initialValue: true,
|
|
275
|
+
});
|
|
276
|
+
if (!clack.isCancel(installSkill) && installSkill) {
|
|
277
|
+
try {
|
|
278
|
+
d.execSync('npx skills add Sunpeak-AI/sunpeak@create-sunpeak-app', {
|
|
279
|
+
cwd: targetDir,
|
|
280
|
+
stdio: 'inherit',
|
|
281
|
+
});
|
|
282
|
+
} catch {
|
|
283
|
+
d.console.log('Skill install skipped. You can install later with: npx skills add Sunpeak-AI/sunpeak@create-sunpeak-app');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
269
288
|
const runCmd = pm === 'npm' ? 'npm run' : pm;
|
|
270
289
|
|
|
271
290
|
d.outro(`Done! To get started:
|
package/bin/commands/start.mjs
CHANGED
|
@@ -114,7 +114,7 @@ export async function start(projectRoot = process.cwd(), args = []) {
|
|
|
114
114
|
const tools = [];
|
|
115
115
|
|
|
116
116
|
if (existsSync(toolsDir)) {
|
|
117
|
-
const toolFiles = readdirSync(toolsDir).filter(f => f.endsWith('.js'));
|
|
117
|
+
const toolFiles = readdirSync(toolsDir).filter(f => f.endsWith('.js') && !f.endsWith('.test.js'));
|
|
118
118
|
|
|
119
119
|
for (const file of toolFiles) {
|
|
120
120
|
const toolName = file.replace(/\.js$/, '');
|
|
@@ -17,6 +17,8 @@ interface ConversationProps {
|
|
|
17
17
|
* border from flashing at a stale height before the iframe resizes.
|
|
18
18
|
*/
|
|
19
19
|
isTransitioning?: boolean;
|
|
20
|
+
/** Optional action element rendered in the conversation header (e.g., Run button) */
|
|
21
|
+
headerAction?: React.ReactNode;
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* Conversation layout that renders children (iframe) at a stable tree position.
|
|
@@ -31,5 +33,5 @@ interface ConversationProps {
|
|
|
31
33
|
* - **fullscreen**: content wrapper becomes `position: fixed` covering the viewport;
|
|
32
34
|
* fullscreen chrome (header/footer) rendered as a separate fixed overlay
|
|
33
35
|
*/
|
|
34
|
-
export declare function Conversation({ children, screenWidth, displayMode, platform, onRequestDisplayMode, appName, appIcon, userMessage, isTransitioning, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
export declare function Conversation({ children, screenWidth, displayMode, platform, onRequestDisplayMode, appName, appIcon, userMessage, isTransitioning, headerAction, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
|
|
35
37
|
export {};
|
package/dist/chatgpt/globals.css
CHANGED
|
@@ -618,6 +618,10 @@
|
|
|
618
618
|
left: 340px;
|
|
619
619
|
}
|
|
620
620
|
|
|
621
|
+
.-z-10 {
|
|
622
|
+
z-index: calc(10 * -1);
|
|
623
|
+
}
|
|
624
|
+
|
|
621
625
|
.z-10 {
|
|
622
626
|
z-index: 10;
|
|
623
627
|
}
|
|
@@ -642,6 +646,18 @@
|
|
|
642
646
|
z-index: 51;
|
|
643
647
|
}
|
|
644
648
|
|
|
649
|
+
.z-\[200\] {
|
|
650
|
+
z-index: 200;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.col-span-3 {
|
|
654
|
+
grid-column: span 3 / span 3;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.col-span-4 {
|
|
658
|
+
grid-column: span 4 / span 4;
|
|
659
|
+
}
|
|
660
|
+
|
|
645
661
|
.container {
|
|
646
662
|
width: 100%;
|
|
647
663
|
}
|
|
@@ -1034,10 +1050,18 @@
|
|
|
1034
1050
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
1035
1051
|
}
|
|
1036
1052
|
|
|
1053
|
+
.grid-cols-7 {
|
|
1054
|
+
grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1037
1057
|
.grid-cols-\[1fr_auto_1fr\] {
|
|
1038
1058
|
grid-template-columns: 1fr auto 1fr;
|
|
1039
1059
|
}
|
|
1040
1060
|
|
|
1061
|
+
.grid-cols-\[2fr_1fr\] {
|
|
1062
|
+
grid-template-columns: 2fr 1fr;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1041
1065
|
.flex-col {
|
|
1042
1066
|
flex-direction: column;
|
|
1043
1067
|
}
|
|
@@ -1460,6 +1484,10 @@
|
|
|
1460
1484
|
padding: calc(var(--spacing) * 5);
|
|
1461
1485
|
}
|
|
1462
1486
|
|
|
1487
|
+
.p-8 {
|
|
1488
|
+
padding: calc(var(--spacing) * 8);
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1463
1491
|
.p-\[1px\] {
|
|
1464
1492
|
padding: 1px;
|
|
1465
1493
|
}
|
|
@@ -1520,10 +1548,6 @@
|
|
|
1520
1548
|
padding-block: calc(var(--spacing) * 4);
|
|
1521
1549
|
}
|
|
1522
1550
|
|
|
1523
|
-
.py-8 {
|
|
1524
|
-
padding-block: calc(var(--spacing) * 8);
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
1551
|
.pt-0 {
|
|
1528
1552
|
padding-top: calc(var(--spacing) * 0);
|
|
1529
1553
|
}
|
|
@@ -1552,10 +1576,6 @@
|
|
|
1552
1576
|
padding-bottom: calc(var(--spacing) * 10);
|
|
1553
1577
|
}
|
|
1554
1578
|
|
|
1555
|
-
.pl-4 {
|
|
1556
|
-
padding-left: calc(var(--spacing) * 4);
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
1579
|
.text-center {
|
|
1560
1580
|
text-align: center;
|
|
1561
1581
|
}
|
|
@@ -1710,6 +1730,10 @@
|
|
|
1710
1730
|
text-transform: uppercase;
|
|
1711
1731
|
}
|
|
1712
1732
|
|
|
1733
|
+
.no-underline {
|
|
1734
|
+
text-decoration-line: none;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1713
1737
|
.antialiased {
|
|
1714
1738
|
-webkit-font-smoothing: antialiased;
|
|
1715
1739
|
-moz-osx-font-smoothing: grayscale;
|
|
@@ -1774,6 +1798,11 @@
|
|
|
1774
1798
|
outline-width: 1px;
|
|
1775
1799
|
}
|
|
1776
1800
|
|
|
1801
|
+
.blur {
|
|
1802
|
+
--tw-blur: blur(8px);
|
|
1803
|
+
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1777
1806
|
.filter {
|
|
1778
1807
|
filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
|
|
1779
1808
|
}
|
package/dist/chatgpt/index.cjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const simulator = require("../simulator-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const discovery = require("../discovery-SviNiBkF.cjs");
|
|
3
|
+
const simulator = require("../simulator-FFNttkqL.cjs");
|
|
4
|
+
const simulatorUrl = require("../simulator-url-DcSYRl-P.cjs");
|
|
5
|
+
const discovery = require("../discovery-D1gpaVz4.cjs");
|
|
7
6
|
exports.IframeResource = simulator.IframeResource;
|
|
8
7
|
exports.McpAppHost = simulator.McpAppHost;
|
|
9
8
|
exports.SCREEN_WIDTHS = simulator.SCREEN_WIDTHS;
|
|
@@ -12,7 +11,6 @@ exports.ThemeProvider = simulator.ThemeProvider;
|
|
|
12
11
|
exports.extractResourceCSP = simulator.extractResourceCSP;
|
|
13
12
|
exports.resolveServerToolResult = simulator.resolveServerToolResult;
|
|
14
13
|
exports.useThemeContext = simulator.useThemeContext;
|
|
15
|
-
exports.ChatGPTSimulator = chatgpt_index.ChatGPTSimulator;
|
|
16
14
|
exports.createSimulatorUrl = simulatorUrl.createSimulatorUrl;
|
|
17
15
|
exports.buildDevSimulations = discovery.buildDevSimulations;
|
|
18
16
|
exports.buildResourceMap = discovery.buildResourceMap;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/chatgpt/index.d.ts
CHANGED
package/dist/chatgpt/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { I, M, a, S, T, j, m, n } from "../simulator-
|
|
2
|
-
import {
|
|
3
|
-
import { c } from "../
|
|
4
|
-
import { b, a as a2, c as c2, d, e, f, g, h, i, t } from "../discovery-DvIQWTez.js";
|
|
1
|
+
import { I, M, a, S, T, j, m, n } from "../simulator-D8t-r7HH.js";
|
|
2
|
+
import { c } from "../simulator-url-j_XV3EoP.js";
|
|
3
|
+
import { b, a as a2, c as c2, d, e, f, g, h, i, t } from "../discovery-BVqD-JsT.js";
|
|
5
4
|
export {
|
|
6
|
-
C as ChatGPTSimulator,
|
|
7
5
|
I as IframeResource,
|
|
8
6
|
M as McpAppHost,
|
|
9
7
|
a as SCREEN_WIDTHS,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -12,6 +12,8 @@ interface ClaudeConversationProps {
|
|
|
12
12
|
appIcon?: string;
|
|
13
13
|
userMessage?: string;
|
|
14
14
|
isTransitioning?: boolean;
|
|
15
|
+
/** Optional action element rendered in the conversation header (e.g., Run button) */
|
|
16
|
+
headerAction?: React.ReactNode;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Claude conversation shell — mimics Claude's chat UI chrome.
|
|
@@ -19,5 +21,5 @@ interface ClaudeConversationProps {
|
|
|
19
21
|
* All three display modes (inline, pip, fullscreen) share the same React tree
|
|
20
22
|
* shape so that the iframe never unmounts when switching modes.
|
|
21
23
|
*/
|
|
22
|
-
export declare function ClaudeConversation({ children, screenWidth, displayMode, platform, onRequestDisplayMode, appName, appIcon, userMessage, isTransitioning, }: ClaudeConversationProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare function ClaudeConversation({ children, screenWidth, displayMode, platform, onRequestDisplayMode, appName, appIcon, userMessage, isTransitioning, headerAction, }: ClaudeConversationProps): import("react/jsx-runtime").JSX.Element;
|
|
23
25
|
export {};
|
package/dist/claude/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const simulator = require("../simulator-
|
|
4
|
-
exports.
|
|
3
|
+
const simulator = require("../simulator-FFNttkqL.cjs");
|
|
4
|
+
exports.Simulator = simulator.Simulator;
|
|
5
5
|
//# sourceMappingURL=index.cjs.map
|
package/dist/claude/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Simulator
|
|
1
|
+
export { Simulator } from '../simulator/simulator';
|
package/dist/claude/index.js
CHANGED
|
@@ -190,7 +190,9 @@ function findToolFiles(toolsDir, fs) {
|
|
|
190
190
|
return [];
|
|
191
191
|
}
|
|
192
192
|
const entries = fs.readdirSync(toolsDir, { withFileTypes: true });
|
|
193
|
-
return entries.filter(
|
|
193
|
+
return entries.filter(
|
|
194
|
+
(entry) => !entry.isDirectory() && entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")
|
|
195
|
+
).map((entry) => ({
|
|
194
196
|
name: entry.name.replace(/\.ts$/, ""),
|
|
195
197
|
path: `${toolsDir}/${entry.name}`
|
|
196
198
|
}));
|
|
@@ -219,4 +221,4 @@ export {
|
|
|
219
221
|
findToolFiles as k,
|
|
220
222
|
toPascalCase as t
|
|
221
223
|
};
|
|
222
|
-
//# sourceMappingURL=discovery-
|
|
224
|
+
//# sourceMappingURL=discovery-BVqD-JsT.js.map
|