sunpeak 0.16.3 → 0.16.5

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.
Files changed (35) hide show
  1. package/README.md +3 -1
  2. package/bin/commands/build.mjs +1 -0
  3. package/bin/commands/dev.mjs +2 -0
  4. package/dist/chatgpt/globals.css +0 -8
  5. package/dist/mcp/index.cjs +61 -48
  6. package/dist/mcp/index.cjs.map +1 -1
  7. package/dist/mcp/index.js +61 -48
  8. package/dist/mcp/index.js.map +1 -1
  9. package/dist/style.css +0 -8
  10. package/package.json +1 -1
  11. package/template/package.json +0 -3
  12. package/template/src/components/avatar.tsx +1 -1
  13. package/template/src/resources/albums/components/album-card.tsx +2 -2
  14. package/template/src/resources/albums/components/album-carousel.tsx +3 -3
  15. package/template/src/resources/albums/components/film-strip.tsx +2 -2
  16. package/template/src/resources/albums/components/fullscreen-viewer.tsx +1 -1
  17. package/template/src/resources/carousel/components/card.tsx +2 -2
  18. package/template/src/resources/carousel/components/carousel.tsx +3 -3
  19. package/template/src/resources/map/components/map-view.tsx +1 -1
  20. package/template/src/resources/map/components/map.tsx +3 -3
  21. package/template/src/resources/map/components/place-card.tsx +2 -2
  22. package/template/src/resources/map/components/place-carousel.tsx +1 -1
  23. package/template/src/resources/map/components/place-inspector.tsx +4 -4
  24. package/template/src/resources/map/components/place-list.tsx +2 -2
  25. package/template/src/resources/review/review.tsx +59 -29
  26. package/template/src/tools/review-diff.ts +3 -1
  27. package/template/src/tools/review-post.ts +3 -1
  28. package/template/src/tools/review-purchase.ts +3 -1
  29. package/template/src/tools/show-albums.ts +3 -1
  30. package/template/src/tools/show-carousel.ts +3 -1
  31. package/template/src/tools/show-map.ts +3 -1
  32. package/template/tsconfig.json +7 -2
  33. package/template/vitest.config.ts +1 -0
  34. package/template/node_modules/.bin/nodemon +0 -21
  35. 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
- export default async function (args: Record<string, unknown>, extra: ToolHandlerExtra) {
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
  ```
@@ -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,
@@ -201,6 +201,7 @@ export async function dev(projectRoot = process.cwd(), args = []) {
201
201
  plugins: [react(), tailwindcss(), sunpeakFaviconPlugin()],
202
202
  resolve: {
203
203
  alias: {
204
+ '@': path.resolve(projectRoot, 'src'),
204
205
  // In workspace dev mode, use local sunpeak source
205
206
  ...(isTemplate && {
206
207
  sunpeak: parentSrc,
@@ -354,6 +355,7 @@ if (import.meta.hot) {
354
355
  plugins: [react(), tailwindcss(), sunpeakEntryPlugin()],
355
356
  resolve: {
356
357
  alias: {
358
+ '@': path.resolve(projectRoot, 'src'),
357
359
  ...(isTemplate && {
358
360
  sunpeak: parentSrc,
359
361
  }),
@@ -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
  }
@@ -15520,27 +15520,30 @@ function createAppServer(config, simulations, viteMode) {
15520
15520
  },
15521
15521
  { capabilities: { resources: {}, tools: {} } }
15522
15522
  );
15523
- const registeredResources = /* @__PURE__ */ new Set();
15523
+ const registeredUriSet = /* @__PURE__ */ new Set();
15524
+ const resourceHandles = /* @__PURE__ */ new Map();
15525
+ const toolHandles = [];
15524
15526
  for (const simulation of simulations) {
15525
15527
  const resource = simulation.resource;
15526
15528
  const tool = simulation.tool;
15527
15529
  const toolResult = simulation.toolResult ?? { structuredContent: null };
15528
15530
  const uri2 = resource.uri ?? `ui://${resource.name}`;
15531
+ const resourceName = resource.name;
15529
15532
  const resourceMeta = resource._meta ?? {};
15530
15533
  const toolMeta = tool._meta ?? {};
15531
- if (!registeredResources.has(uri2)) {
15532
- registeredResources.add(uri2);
15534
+ if (!registeredUriSet.has(uri2)) {
15535
+ registeredUriSet.add(uri2);
15533
15536
  const listMeta = viteMode ? injectViteCSP(resourceMeta) : resourceMeta;
15534
15537
  console.log(`[MCP] RegisterResource: ${uri2}`);
15535
- ak(
15536
- mcpServer,
15537
- resource.name,
15538
+ const handle = mcpServer.registerResource(
15539
+ resourceName,
15538
15540
  uri2,
15539
15541
  {
15542
+ mimeType: EI,
15540
15543
  description: resource.description,
15541
15544
  _meta: listMeta
15542
15545
  },
15543
- async (_uri, extra) => {
15546
+ async (readUri, extra) => {
15544
15547
  const prodBuild = needsProdBuild(
15545
15548
  extra?.requestInfo?.headers ?? {}
15546
15549
  );
@@ -15549,17 +15552,18 @@ function createAppServer(config, simulations, viteMode) {
15549
15552
  try {
15550
15553
  content = getResourceHtml(simulation, viteMode, prodBuild);
15551
15554
  } catch (error) {
15552
- console.error(`[MCP] ReadResource error for ${uri2}:`, error);
15555
+ console.error(`[MCP] ReadResource error for ${readUri.href}:`, error);
15553
15556
  throw error;
15554
15557
  }
15555
15558
  const sizeKB = (content.length / 1024).toFixed(1);
15556
15559
  console.log(
15557
- `[MCP] ReadResource: ${uri2} → ${sizeKB}KB${prodBuild ? " (prod build)" : " (vite)"}`
15560
+ `[MCP] ReadResource: ${readUri.href} → ${sizeKB}KB${prodBuild ? " (prod build)" : " (vite)"}`
15558
15561
  );
15559
15562
  return {
15560
15563
  contents: [
15561
15564
  {
15562
- uri: uri2,
15565
+ // Use readUri (not closure variable) so the response URI matches after updates
15566
+ uri: readUri.href,
15563
15567
  mimeType: EI,
15564
15568
  text: content,
15565
15569
  _meta: readMeta
@@ -15568,20 +15572,22 @@ function createAppServer(config, simulations, viteMode) {
15568
15572
  };
15569
15573
  }
15570
15574
  );
15575
+ resourceHandles.set(resourceName, handle);
15571
15576
  }
15572
- hk(
15577
+ const fullToolMeta = {
15578
+ ...toolMeta,
15579
+ ui: {
15580
+ resourceUri: uri2,
15581
+ // Preserve tool visibility from simulation metadata if declared
15582
+ ...toolMeta.ui?.visibility ? { visibility: toolMeta.ui.visibility } : {}
15583
+ }
15584
+ };
15585
+ const toolHandle = hk(
15573
15586
  mcpServer,
15574
15587
  tool.name,
15575
15588
  {
15576
15589
  description: tool.description,
15577
- _meta: {
15578
- ...toolMeta,
15579
- ui: {
15580
- resourceUri: uri2,
15581
- // Preserve tool visibility from simulation metadata if declared
15582
- ...toolMeta.ui?.visibility ? { visibility: toolMeta.ui.visibility } : {}
15583
- }
15584
- }
15590
+ _meta: fullToolMeta
15585
15591
  },
15586
15592
  async (extra) => {
15587
15593
  const args = extra.request?.params?.arguments ?? {};
@@ -15602,12 +15608,13 @@ function createAppServer(config, simulations, viteMode) {
15602
15608
  };
15603
15609
  }
15604
15610
  );
15611
+ toolHandles.push({ handle: toolHandle, resourceName, toolMeta: fullToolMeta });
15605
15612
  }
15606
- const registeredUris = Array.from(registeredResources).join(", ");
15613
+ const registeredUris = Array.from(registeredUriSet).join(", ");
15607
15614
  console.log(
15608
15615
  `[MCP] Registered ${simulations.length} tool(s) and resource(s)${viteMode ? " (vite mode)" : ""}: ${registeredUris}`
15609
15616
  );
15610
- return mcpServer;
15617
+ return { server: mcpServer, resourceHandles, toolHandles };
15611
15618
  }
15612
15619
  const SESSION_IDLE_TIMEOUT_MS$1 = 5 * 60 * 1e3;
15613
15620
  function isLocalConnection(req) {
@@ -15626,10 +15633,8 @@ const cleanupInterval = setInterval(() => {
15626
15633
  const now = Date.now();
15627
15634
  for (const [id2, session] of sessions) {
15628
15635
  if (now - session.lastActivity > SESSION_IDLE_TIMEOUT_MS$1) {
15629
- sessions.delete(id2);
15630
- session.transport.close?.();
15631
- session.server.close();
15632
- console.log(`[MCP] Session expired: ${id2.substring(0, 8)}... (${sessions.size} active)`);
15636
+ console.log(`[MCP] Session expired: ${id2.substring(0, 8)}...`);
15637
+ void session.server.close();
15633
15638
  }
15634
15639
  }
15635
15640
  }, 6e4);
@@ -15676,11 +15681,18 @@ async function handleMcpRequest(req, res, config, simulations, viteMode) {
15676
15681
  }
15677
15682
  if (req.method === "POST") {
15678
15683
  const isLocal = isLocalConnection(req);
15679
- const server = createAppServer(config, simulations, viteMode);
15684
+ const { server, resourceHandles, toolHandles } = createAppServer(config, simulations, viteMode);
15680
15685
  const transport = new StreamableHTTPServerTransport({
15681
15686
  sessionIdGenerator: () => node_crypto.randomUUID(),
15682
15687
  onsessioninitialized: (id2) => {
15683
- sessions.set(id2, { server, transport, isLocal, lastActivity: Date.now() });
15688
+ sessions.set(id2, {
15689
+ server,
15690
+ transport,
15691
+ isLocal,
15692
+ lastActivity: Date.now(),
15693
+ resourceHandles,
15694
+ toolHandles
15695
+ });
15684
15696
  const origin = isLocal ? "local" : "tunnel";
15685
15697
  console.log(
15686
15698
  `[MCP] Session started: ${id2.substring(0, 8)}... (${origin}, ${sessions.size} active)`
@@ -15695,13 +15707,12 @@ async function handleMcpRequest(req, res, config, simulations, viteMode) {
15695
15707
  const id2 = transport.sessionId;
15696
15708
  console.error(`[MCP] Transport error${id2 ? ` (${id2.substring(0, 8)}...)` : ""}:`, error);
15697
15709
  };
15698
- transport.onclose = async () => {
15710
+ transport.onclose = () => {
15699
15711
  const id2 = transport.sessionId;
15700
15712
  if (id2 && sessions.has(id2)) {
15701
15713
  sessions.delete(id2);
15702
15714
  console.log(`[MCP] Session closed: ${id2.substring(0, 8)}... (${sessions.size} active)`);
15703
15715
  }
15704
- await server.close();
15705
15716
  };
15706
15717
  await server.connect(transport);
15707
15718
  await transport.handleRequest(req, res, parsedBody);
@@ -15796,16 +15807,24 @@ function runMCPServer(config) {
15796
15807
  process.on("SIGINT", () => void shutdown());
15797
15808
  return {
15798
15809
  invalidateResources() {
15799
- let notified = 0;
15810
+ if (sessions.size === 0) return;
15811
+ const timestamp = Date.now();
15800
15812
  for (const [, session] of sessions) {
15801
- if (!session.isLocal) {
15802
- session.server.sendResourceListChanged();
15803
- notified++;
15813
+ for (const [name, handle] of session.resourceHandles) {
15814
+ handle.update({ uri: `ui://${name}-${timestamp}` });
15815
+ }
15816
+ for (const { handle, resourceName, toolMeta } of session.toolHandles) {
15817
+ const newUri = `ui://${resourceName}-${timestamp}`;
15818
+ handle.update({
15819
+ _meta: {
15820
+ ...toolMeta,
15821
+ ui: { ...toolMeta.ui, resourceUri: newUri },
15822
+ "ui/resourceUri": newUri
15823
+ }
15824
+ });
15804
15825
  }
15805
15826
  }
15806
- if (notified > 0) {
15807
- console.log(`[MCP] Notified ${notified} session(s) of resource changes`);
15808
- }
15827
+ console.log(`[MCP] Cache-busted ${sessions.size} session(s) with timestamp ${timestamp}`);
15809
15828
  }
15810
15829
  };
15811
15830
  }
@@ -15916,10 +15935,8 @@ function createMcpHandler(config) {
15916
15935
  const now = Date.now();
15917
15936
  for (const [id2, session] of sessions2) {
15918
15937
  if (now - session.lastActivity > SESSION_IDLE_TIMEOUT_MS) {
15919
- sessions2.delete(id2);
15920
- session.transport.close?.();
15921
- session.server.close();
15922
- console.log(`[MCP] Session expired: ${id2.substring(0, 8)}... (${sessions2.size} active)`);
15938
+ console.log(`[MCP] Session expired: ${id2.substring(0, 8)}...`);
15939
+ void session.server.close();
15923
15940
  }
15924
15941
  }
15925
15942
  }, 6e4);
@@ -15997,13 +16014,12 @@ function createMcpHandler(config) {
15997
16014
  const id2 = transport.sessionId;
15998
16015
  console.error(`[MCP] Transport error${id2 ? ` (${id2.substring(0, 8)}...)` : ""}:`, error);
15999
16016
  };
16000
- transport.onclose = async () => {
16017
+ transport.onclose = () => {
16001
16018
  const id2 = transport.sessionId;
16002
16019
  if (id2 && sessions2.has(id2)) {
16003
16020
  sessions2.delete(id2);
16004
16021
  console.log(`[MCP] Session closed: ${id2.substring(0, 8)}... (${sessions2.size} active)`);
16005
16022
  }
16006
- await server.close();
16007
16023
  };
16008
16024
  await server.connect(transport);
16009
16025
  await transport.handleRequest(req, res, parsedBody);
@@ -16019,10 +16035,8 @@ function createHandler(config) {
16019
16035
  const now = Date.now();
16020
16036
  for (const [id2, session] of sessions2) {
16021
16037
  if (now - session.lastActivity > SESSION_IDLE_TIMEOUT_MS) {
16022
- sessions2.delete(id2);
16023
- session.transport.close?.();
16024
- session.server.close();
16025
- console.log(`[MCP] Session expired: ${id2.substring(0, 8)}... (${sessions2.size} active)`);
16038
+ console.log(`[MCP] Session expired: ${id2.substring(0, 8)}...`);
16039
+ void session.server.close();
16026
16040
  }
16027
16041
  }
16028
16042
  }, 6e4);
@@ -16077,12 +16091,11 @@ function createHandler(config) {
16077
16091
  transport.onerror = (error) => {
16078
16092
  console.error("[MCP] Transport error:", error);
16079
16093
  };
16080
- transport.onclose = async () => {
16094
+ transport.onclose = () => {
16081
16095
  const id2 = transport.sessionId;
16082
16096
  if (id2 && sessions2.has(id2)) {
16083
16097
  sessions2.delete(id2);
16084
16098
  }
16085
- await server.close();
16086
16099
  };
16087
16100
  await server.connect(transport);
16088
16101
  const response = await transport.handleRequest(req, { parsedBody, authInfo });