sunpeak 0.16.2 → 0.16.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 +3 -1
- package/bin/commands/build.mjs +1 -0
- package/bin/commands/dev.mjs +65 -166
- package/bin/sunpeak.js +0 -1
- package/dist/chatgpt/globals.css +0 -8
- package/dist/mcp/index.cjs +7258 -7254
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +7259 -7255
- package/dist/mcp/index.js.map +1 -1
- package/dist/style.css +0 -8
- package/package.json +1 -1
- package/template/package.json +0 -3
- package/template/src/components/avatar.tsx +1 -1
- package/template/src/resources/albums/components/album-card.tsx +2 -2
- package/template/src/resources/albums/components/album-carousel.tsx +3 -3
- package/template/src/resources/albums/components/film-strip.tsx +2 -2
- package/template/src/resources/albums/components/fullscreen-viewer.tsx +1 -1
- package/template/src/resources/carousel/components/card.tsx +2 -2
- package/template/src/resources/carousel/components/carousel.tsx +3 -3
- package/template/src/resources/map/components/map-view.tsx +1 -1
- package/template/src/resources/map/components/map.tsx +3 -3
- package/template/src/resources/map/components/place-card.tsx +2 -2
- package/template/src/resources/map/components/place-carousel.tsx +1 -1
- package/template/src/resources/map/components/place-inspector.tsx +4 -4
- package/template/src/resources/map/components/place-list.tsx +2 -2
- package/template/src/resources/review/review.tsx +59 -29
- package/template/src/tools/review-diff.ts +3 -1
- package/template/src/tools/review-post.ts +3 -1
- package/template/src/tools/review-purchase.ts +3 -1
- package/template/src/tools/show-albums.ts +3 -1
- package/template/src/tools/show-carousel.ts +3 -1
- package/template/src/tools/show-map.ts +3 -1
- package/template/tsconfig.json +7 -2
- package/template/vitest.config.ts +1 -0
- package/template/node_modules/.bin/nodemon +0 -21
- package/template/node_modules/.bin/tsx +0 -21
package/README.md
CHANGED
|
@@ -141,7 +141,9 @@ export const schema = {
|
|
|
141
141
|
title: z.string().describe('Title describing the changes'),
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
type Args = z.infer<z.ZodObject<typeof schema>>;
|
|
145
|
+
|
|
146
|
+
export default async function (args: Args, extra: ToolHandlerExtra) {
|
|
145
147
|
return { structuredContent: { title: args.title, sections: [] } };
|
|
146
148
|
}
|
|
147
149
|
```
|
package/bin/commands/build.mjs
CHANGED
|
@@ -241,6 +241,7 @@ export async function build(projectRoot = process.cwd()) {
|
|
|
241
241
|
resolve: {
|
|
242
242
|
conditions: ['style', 'import', 'module', 'browser', 'default'],
|
|
243
243
|
alias: {
|
|
244
|
+
'@': path.resolve(projectRoot, 'src'),
|
|
244
245
|
// In workspace dev mode, use local sunpeak source
|
|
245
246
|
...(isTemplate && {
|
|
246
247
|
sunpeak: parentSrc,
|
package/bin/commands/dev.mjs
CHANGED
|
@@ -149,9 +149,6 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
149
149
|
// Parse --no-begging flag
|
|
150
150
|
const noBegging = args.includes('--no-begging');
|
|
151
151
|
|
|
152
|
-
// Parse --prod-mcp flag (serve production build files over MCP instead of Vite HMR)
|
|
153
|
-
const prodMcp = args.includes('--prod-mcp');
|
|
154
|
-
|
|
155
152
|
console.log(`Starting Vite dev server on port ${port}...`);
|
|
156
153
|
|
|
157
154
|
// Check if we're in the sunpeak workspace (directory is named "template")
|
|
@@ -178,7 +175,7 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
178
175
|
sunpeakMcp = await import(pathToFileURL(join(sunpeakBase, 'dist/mcp/index.js')).href);
|
|
179
176
|
sunpeakDiscovery = await import(pathToFileURL(join(sunpeakBase, 'dist/lib/discovery-cli.js')).href);
|
|
180
177
|
}
|
|
181
|
-
const { FAVICON_BUFFER: faviconBuffer, runMCPServer
|
|
178
|
+
const { FAVICON_BUFFER: faviconBuffer, runMCPServer } = sunpeakMcp;
|
|
182
179
|
const { findResourceDirs, findSimulationFilesFlat, findToolFiles, extractResourceExport, extractToolExport } = sunpeakDiscovery;
|
|
183
180
|
|
|
184
181
|
// Vite plugin to serve the sunpeak favicon
|
|
@@ -204,6 +201,7 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
204
201
|
plugins: [react(), tailwindcss(), sunpeakFaviconPlugin()],
|
|
205
202
|
resolve: {
|
|
206
203
|
alias: {
|
|
204
|
+
'@': path.resolve(projectRoot, 'src'),
|
|
207
205
|
// In workspace dev mode, use local sunpeak source
|
|
208
206
|
...(isTemplate && {
|
|
209
207
|
sunpeak: parentSrc,
|
|
@@ -296,33 +294,29 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
296
294
|
});
|
|
297
295
|
}
|
|
298
296
|
|
|
299
|
-
// Start MCP server with its own Vite instance
|
|
297
|
+
// Start MCP server with its own Vite instance for HMR
|
|
300
298
|
if (simulations.length > 0) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
299
|
+
console.log(`\nStarting MCP server with ${simulations.length} simulation(s) (Vite HMR)...`);
|
|
300
|
+
|
|
301
|
+
// Virtual entry module plugin for MCP
|
|
302
|
+
const sunpeakEntryPlugin = () => ({
|
|
303
|
+
name: 'sunpeak-entry',
|
|
304
|
+
resolveId(id) {
|
|
305
|
+
if (id.startsWith('virtual:sunpeak-entry')) {
|
|
306
|
+
return id;
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
load(id) {
|
|
310
|
+
if (id.startsWith('virtual:sunpeak-entry')) {
|
|
311
|
+
const url = new URL(id.replace('virtual:sunpeak-entry', 'http://x'));
|
|
312
|
+
const srcPath = url.searchParams.get('src');
|
|
313
|
+
const componentName = url.searchParams.get('component');
|
|
314
|
+
|
|
315
|
+
if (!srcPath || !componentName) {
|
|
316
|
+
return 'console.error("Missing src or component param");';
|
|
313
317
|
}
|
|
314
|
-
},
|
|
315
|
-
load(id) {
|
|
316
|
-
if (id.startsWith('virtual:sunpeak-entry')) {
|
|
317
|
-
const url = new URL(id.replace('virtual:sunpeak-entry', 'http://x'));
|
|
318
|
-
const srcPath = url.searchParams.get('src');
|
|
319
|
-
const componentName = url.searchParams.get('component');
|
|
320
|
-
|
|
321
|
-
if (!srcPath || !componentName) {
|
|
322
|
-
return 'console.error("Missing src or component param");';
|
|
323
|
-
}
|
|
324
318
|
|
|
325
|
-
|
|
319
|
+
return `
|
|
326
320
|
import { createElement } from 'react';
|
|
327
321
|
import { createRoot } from 'react-dom/client';
|
|
328
322
|
import { AppProvider } from 'sunpeak';
|
|
@@ -349,149 +343,54 @@ if (import.meta.hot) {
|
|
|
349
343
|
import.meta.hot.accept();
|
|
350
344
|
}
|
|
351
345
|
`;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
});
|
|
355
349
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
},
|
|
350
|
+
// Create Vite dev server in middleware mode for MCP
|
|
351
|
+
// Use separate cache directory to avoid conflicts with main dev server
|
|
352
|
+
const mcpViteServer = await createServer({
|
|
353
|
+
root: projectRoot,
|
|
354
|
+
cacheDir: 'node_modules/.vite-mcp',
|
|
355
|
+
plugins: [react(), tailwindcss(), sunpeakEntryPlugin()],
|
|
356
|
+
resolve: {
|
|
357
|
+
alias: {
|
|
358
|
+
'@': path.resolve(projectRoot, 'src'),
|
|
359
|
+
...(isTemplate && {
|
|
360
|
+
sunpeak: parentSrc,
|
|
361
|
+
}),
|
|
368
362
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
363
|
+
},
|
|
364
|
+
server: {
|
|
365
|
+
middlewareMode: true,
|
|
366
|
+
allowedHosts: true,
|
|
367
|
+
watch: {
|
|
368
|
+
// Only watch files that affect the UI bundle (not JSON, tests, etc.)
|
|
369
|
+
// MCP resources reload on next tool call, not on file change
|
|
370
|
+
ignored: (filePath) => {
|
|
371
|
+
if (!filePath.includes('.')) return false; // Watch directories
|
|
372
|
+
if (/\.(tsx?|css)$/.test(filePath)) {
|
|
373
|
+
return /\.(test|spec)\.tsx?$/.test(filePath); // Ignore tests
|
|
374
|
+
}
|
|
375
|
+
return true; // Ignore everything else
|
|
382
376
|
},
|
|
383
377
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
378
|
+
},
|
|
379
|
+
optimizeDeps: {
|
|
380
|
+
include: ['react', 'react-dom/client'],
|
|
381
|
+
},
|
|
382
|
+
appType: 'custom',
|
|
383
|
+
});
|
|
390
384
|
|
|
391
385
|
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
392
386
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
server: { middlewareMode: true },
|
|
401
|
-
appType: 'custom',
|
|
402
|
-
logLevel: 'silent',
|
|
403
|
-
resolve: {
|
|
404
|
-
alias: {
|
|
405
|
-
...(isTemplate && { sunpeak: parentSrc }),
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
const prodTools = [];
|
|
411
|
-
for (const { name: toolName, path: toolPath } of toolFiles) {
|
|
412
|
-
try {
|
|
413
|
-
const relativePath = './' + toolPath.replace(projectRoot + '/', '').replace(projectRoot + '\\', '');
|
|
414
|
-
const mod = await ssrLoader.ssrLoadModule(relativePath);
|
|
415
|
-
if (mod.tool && mod.default) {
|
|
416
|
-
prodTools.push({
|
|
417
|
-
name: toolName,
|
|
418
|
-
tool: mod.tool,
|
|
419
|
-
schema: mod.schema,
|
|
420
|
-
handler: mod.default,
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
} catch (err) {
|
|
424
|
-
console.warn(`Warning: Could not load tool handler ${toolName}: ${err.message}`);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Load server entry if present
|
|
429
|
-
const serverEntryPath = join(projectRoot, 'src/server.ts');
|
|
430
|
-
let auth = undefined;
|
|
431
|
-
let serverConfig = {};
|
|
432
|
-
if (existsSync(serverEntryPath)) {
|
|
433
|
-
try {
|
|
434
|
-
const serverMod = await ssrLoader.ssrLoadModule('./src/server.ts');
|
|
435
|
-
if (typeof serverMod.auth === 'function') {
|
|
436
|
-
auth = serverMod.auth;
|
|
437
|
-
console.log('Loaded auth from src/server.ts');
|
|
438
|
-
}
|
|
439
|
-
if (serverMod.server) serverConfig = serverMod.server;
|
|
440
|
-
} catch (err) {
|
|
441
|
-
console.warn(`Warning: Could not load server entry: ${err.message}`);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
await ssrLoader.close();
|
|
446
|
-
|
|
447
|
-
// Build production resources from dist/
|
|
448
|
-
const prodResources = [];
|
|
449
|
-
for (const { key } of resourceDirs) {
|
|
450
|
-
const meta = resourceMap.get(key);
|
|
451
|
-
if (!meta) continue;
|
|
452
|
-
const htmlPath = join(projectRoot, `dist/${key}/${key}.html`);
|
|
453
|
-
const jsonPath = join(projectRoot, `dist/${key}/${key}.json`);
|
|
454
|
-
if (!existsSync(htmlPath)) continue;
|
|
455
|
-
|
|
456
|
-
const html = readFileSync(htmlPath, 'utf-8');
|
|
457
|
-
let uri = `ui://${meta.name ?? key}`;
|
|
458
|
-
let _meta = meta._meta;
|
|
459
|
-
|
|
460
|
-
// Use URI from build JSON if available (has cache-bust timestamp)
|
|
461
|
-
if (existsSync(jsonPath)) {
|
|
462
|
-
try {
|
|
463
|
-
const buildMeta = JSON.parse(readFileSync(jsonPath, 'utf-8'));
|
|
464
|
-
if (buildMeta.uri) uri = buildMeta.uri;
|
|
465
|
-
} catch {}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
prodResources.push({
|
|
469
|
-
name: meta.name ?? key,
|
|
470
|
-
uri,
|
|
471
|
-
html,
|
|
472
|
-
description: meta.description,
|
|
473
|
-
_meta,
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const name = serverConfig.name ?? pkg.name ?? 'Sunpeak';
|
|
478
|
-
const version = serverConfig.version ?? pkg.version ?? '0.1.0';
|
|
479
|
-
|
|
480
|
-
console.log(`Starting production MCP server with ${prodTools.length} tool(s)...`);
|
|
481
|
-
startProductionHttpServer(
|
|
482
|
-
{ name, version, tools: prodTools, resources: prodResources, auth },
|
|
483
|
-
8000
|
|
484
|
-
);
|
|
485
|
-
} else {
|
|
486
|
-
// Default: simulation-based MCP server with fixture data
|
|
487
|
-
mcpHandle = runMCPServer({
|
|
488
|
-
name: pkg.name || 'Sunpeak',
|
|
489
|
-
version: pkg.version || '0.1.0',
|
|
490
|
-
simulations,
|
|
491
|
-
port: 8000,
|
|
492
|
-
...(mcpViteServer && { viteServer: mcpViteServer }),
|
|
493
|
-
});
|
|
494
|
-
}
|
|
387
|
+
const mcpHandle = runMCPServer({
|
|
388
|
+
name: pkg.name || 'Sunpeak',
|
|
389
|
+
version: pkg.version || '0.1.0',
|
|
390
|
+
simulations,
|
|
391
|
+
port: 8000,
|
|
392
|
+
viteServer: mcpViteServer,
|
|
393
|
+
});
|
|
495
394
|
|
|
496
395
|
// Build production bundles and watch for changes.
|
|
497
396
|
// Tunnel clients (e.g. Claude via ngrok) get the pre-built HTML since they can't
|
|
@@ -502,13 +401,13 @@ if (import.meta.hot) {
|
|
|
502
401
|
|
|
503
402
|
// Handle signals - close both servers
|
|
504
403
|
process.on('SIGINT', async () => {
|
|
505
|
-
|
|
404
|
+
await mcpViteServer.close();
|
|
506
405
|
await server.close();
|
|
507
406
|
process.exit(0);
|
|
508
407
|
});
|
|
509
408
|
|
|
510
409
|
process.on('SIGTERM', async () => {
|
|
511
|
-
|
|
410
|
+
await mcpViteServer.close();
|
|
512
411
|
await server.close();
|
|
513
412
|
process.exit(0);
|
|
514
413
|
});
|
package/bin/sunpeak.js
CHANGED
|
@@ -97,7 +97,6 @@ Usage:
|
|
|
97
97
|
sunpeak new [name] [resources] Create a new project
|
|
98
98
|
sunpeak dev Start dev server + MCP endpoint
|
|
99
99
|
--no-begging Suppress GitHub star message
|
|
100
|
-
--prod-mcp Use real tool handlers (not fixtures)
|
|
101
100
|
sunpeak build Build resources + tools for production
|
|
102
101
|
sunpeak start Start production MCP server
|
|
103
102
|
--port, -p Server port (default: 8000, or PORT env)
|
package/dist/chatgpt/globals.css
CHANGED
|
@@ -1368,10 +1368,6 @@
|
|
|
1368
1368
|
background-color: #0000;
|
|
1369
1369
|
}
|
|
1370
1370
|
|
|
1371
|
-
.bg-white {
|
|
1372
|
-
background-color: var(--color-white);
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
1371
|
.bg-gradient-to-l {
|
|
1376
1372
|
--tw-gradient-position: to left in oklab;
|
|
1377
1373
|
background-image: linear-gradient(var(--tw-gradient-stops));
|
|
@@ -1672,10 +1668,6 @@
|
|
|
1672
1668
|
white-space: pre-wrap;
|
|
1673
1669
|
}
|
|
1674
1670
|
|
|
1675
|
-
.text-\[\#000000\] {
|
|
1676
|
-
color: #000;
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
1671
|
.text-\[var\(--color-text-danger\)\] {
|
|
1680
1672
|
color: var(--color-text-danger);
|
|
1681
1673
|
}
|