sunpeak 0.16.2 → 0.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/commands/dev.mjs +63 -166
- package/bin/sunpeak.js +0 -1
- package/dist/mcp/index.cjs +7255 -7242
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +7256 -7243
- package/dist/mcp/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
@@ -296,33 +293,29 @@ export async function dev(projectRoot = process.cwd(), args = []) {
|
|
|
296
293
|
});
|
|
297
294
|
}
|
|
298
295
|
|
|
299
|
-
// Start MCP server with its own Vite instance
|
|
296
|
+
// Start MCP server with its own Vite instance for HMR
|
|
300
297
|
if (simulations.length > 0) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
298
|
+
console.log(`\nStarting MCP server with ${simulations.length} simulation(s) (Vite HMR)...`);
|
|
299
|
+
|
|
300
|
+
// Virtual entry module plugin for MCP
|
|
301
|
+
const sunpeakEntryPlugin = () => ({
|
|
302
|
+
name: 'sunpeak-entry',
|
|
303
|
+
resolveId(id) {
|
|
304
|
+
if (id.startsWith('virtual:sunpeak-entry')) {
|
|
305
|
+
return id;
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
load(id) {
|
|
309
|
+
if (id.startsWith('virtual:sunpeak-entry')) {
|
|
310
|
+
const url = new URL(id.replace('virtual:sunpeak-entry', 'http://x'));
|
|
311
|
+
const srcPath = url.searchParams.get('src');
|
|
312
|
+
const componentName = url.searchParams.get('component');
|
|
313
|
+
|
|
314
|
+
if (!srcPath || !componentName) {
|
|
315
|
+
return 'console.error("Missing src or component param");';
|
|
313
316
|
}
|
|
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
317
|
|
|
325
|
-
|
|
318
|
+
return `
|
|
326
319
|
import { createElement } from 'react';
|
|
327
320
|
import { createRoot } from 'react-dom/client';
|
|
328
321
|
import { AppProvider } from 'sunpeak';
|
|
@@ -349,149 +342,53 @@ if (import.meta.hot) {
|
|
|
349
342
|
import.meta.hot.accept();
|
|
350
343
|
}
|
|
351
344
|
`;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
});
|
|
355
348
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
},
|
|
349
|
+
// Create Vite dev server in middleware mode for MCP
|
|
350
|
+
// Use separate cache directory to avoid conflicts with main dev server
|
|
351
|
+
const mcpViteServer = await createServer({
|
|
352
|
+
root: projectRoot,
|
|
353
|
+
cacheDir: 'node_modules/.vite-mcp',
|
|
354
|
+
plugins: [react(), tailwindcss(), sunpeakEntryPlugin()],
|
|
355
|
+
resolve: {
|
|
356
|
+
alias: {
|
|
357
|
+
...(isTemplate && {
|
|
358
|
+
sunpeak: parentSrc,
|
|
359
|
+
}),
|
|
368
360
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
361
|
+
},
|
|
362
|
+
server: {
|
|
363
|
+
middlewareMode: true,
|
|
364
|
+
allowedHosts: true,
|
|
365
|
+
watch: {
|
|
366
|
+
// Only watch files that affect the UI bundle (not JSON, tests, etc.)
|
|
367
|
+
// MCP resources reload on next tool call, not on file change
|
|
368
|
+
ignored: (filePath) => {
|
|
369
|
+
if (!filePath.includes('.')) return false; // Watch directories
|
|
370
|
+
if (/\.(tsx?|css)$/.test(filePath)) {
|
|
371
|
+
return /\.(test|spec)\.tsx?$/.test(filePath); // Ignore tests
|
|
372
|
+
}
|
|
373
|
+
return true; // Ignore everything else
|
|
382
374
|
},
|
|
383
375
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
376
|
+
},
|
|
377
|
+
optimizeDeps: {
|
|
378
|
+
include: ['react', 'react-dom/client'],
|
|
379
|
+
},
|
|
380
|
+
appType: 'custom',
|
|
381
|
+
});
|
|
390
382
|
|
|
391
383
|
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
392
384
|
|
|
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
|
-
}
|
|
385
|
+
const mcpHandle = runMCPServer({
|
|
386
|
+
name: pkg.name || 'Sunpeak',
|
|
387
|
+
version: pkg.version || '0.1.0',
|
|
388
|
+
simulations,
|
|
389
|
+
port: 8000,
|
|
390
|
+
viteServer: mcpViteServer,
|
|
391
|
+
});
|
|
495
392
|
|
|
496
393
|
// Build production bundles and watch for changes.
|
|
497
394
|
// Tunnel clients (e.g. Claude via ngrok) get the pre-built HTML since they can't
|
|
@@ -502,13 +399,13 @@ if (import.meta.hot) {
|
|
|
502
399
|
|
|
503
400
|
// Handle signals - close both servers
|
|
504
401
|
process.on('SIGINT', async () => {
|
|
505
|
-
|
|
402
|
+
await mcpViteServer.close();
|
|
506
403
|
await server.close();
|
|
507
404
|
process.exit(0);
|
|
508
405
|
});
|
|
509
406
|
|
|
510
407
|
process.on('SIGTERM', async () => {
|
|
511
|
-
|
|
408
|
+
await mcpViteServer.close();
|
|
512
409
|
await server.close();
|
|
513
410
|
process.exit(0);
|
|
514
411
|
});
|
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)
|