sunpeak 0.5.19 → 0.5.22

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 (54) hide show
  1. package/README.md +10 -1
  2. package/{cli → bin/commands}/build.mjs +1 -10
  3. package/bin/commands/dev.mjs +79 -0
  4. package/bin/commands/mcp.mjs +75 -0
  5. package/bin/sunpeak.js +30 -65
  6. package/bin/utils.mjs +12 -0
  7. package/dist/dev/entry.d.ts +0 -0
  8. package/dist/mcp/entry.cjs +29 -0
  9. package/dist/mcp/entry.cjs.map +1 -0
  10. package/dist/mcp/entry.d.ts +2 -0
  11. package/dist/mcp/entry.js +28 -0
  12. package/dist/mcp/entry.js.map +1 -0
  13. package/dist/mcp/index.cjs +2 -920
  14. package/dist/mcp/index.cjs.map +1 -1
  15. package/dist/mcp/index.js +2 -920
  16. package/dist/mcp/index.js.map +1 -1
  17. package/dist/server-DpriZ4jT.cjs +922 -0
  18. package/dist/server-DpriZ4jT.cjs.map +1 -0
  19. package/dist/server-SBlanUcf.js +923 -0
  20. package/dist/server-SBlanUcf.js.map +1 -0
  21. package/package.json +3 -2
  22. package/template/.sunpeak/dev.tsx +5 -0
  23. package/template/README.md +17 -27
  24. package/template/index.html +2 -2
  25. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +3 -3
  26. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +1 -1
  27. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +16 -16
  28. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Textarea.js +3 -3
  29. package/template/node_modules/.vite/deps/_metadata.json +34 -34
  30. package/template/node_modules/.vite/deps/{chunk-675LFNY2.js → chunk-EVJ3DVH5.js} +8 -8
  31. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  32. package/template/nodemon.json +1 -1
  33. package/template/package.json +3 -16
  34. package/template/src/components/album/albums.tsx +2 -2
  35. package/template/src/dev/entry.tsx +0 -0
  36. package/template/src/mcp/entry.ts +0 -0
  37. package/template/src/simulations/index.ts +3 -3
  38. package/cli/validate.mjs +0 -245
  39. package/template/_prettierignore +0 -4
  40. package/template/_prettierrc +0 -9
  41. package/template/dev/main.tsx +0 -43
  42. package/template/eslint.config.cjs +0 -49
  43. package/template/mcp/server.ts +0 -19
  44. package/template/node_modules/.bin/eslint +0 -21
  45. package/template/node_modules/.bin/eslint-config-prettier +0 -21
  46. package/template/node_modules/.bin/prettier +0 -21
  47. package/template/node_modules/.bin/ts-node +0 -21
  48. package/template/node_modules/.bin/ts-node-cwd +0 -21
  49. package/template/node_modules/.bin/ts-node-esm +0 -21
  50. package/template/node_modules/.bin/ts-node-script +0 -21
  51. package/template/node_modules/.bin/ts-node-transpile-only +0 -21
  52. package/template/node_modules/.bin/ts-script +0 -21
  53. /package/template/node_modules/.vite/deps/{chunk-675LFNY2.js.map → chunk-EVJ3DVH5.js.map} +0 -0
  54. /package/template/{assets → public}/favicon.ico +0 -0
package/README.md CHANGED
@@ -36,7 +36,16 @@ Quickstart, build, and test your ChatGPT App locally with OpenAI apps-sdk-ui Rea
36
36
  Requirements: Node (20+), pnpm (10+)
37
37
 
38
38
  ```bash
39
- pnpm dlx sunpeak new
39
+ # Create a new project (no install needed)
40
+ npx sunpeak new my-app
41
+
42
+ # Or with pnpm
43
+ pnpm dlx sunpeak new my-app
44
+
45
+ # Start developing
46
+ cd my-app
47
+ pnpm install
48
+ pnpm dev
40
49
  ```
41
50
 
42
51
  To add sunpeak to an existing project, refer to the [documentation](https://docs.sunpeak.ai/add-to-existing-project).
@@ -2,16 +2,7 @@
2
2
  import { execSync } from 'child_process';
3
3
  import { existsSync, rmSync, readdirSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
4
4
  import path from 'path';
5
-
6
- /**
7
- * Detect package manager for the project
8
- */
9
- function detectPackageManager(projectRoot) {
10
- if (existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
11
- if (existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
12
- if (existsSync(path.join(projectRoot, 'package-lock.json'))) return 'npm';
13
- return 'pnpm'; // default
14
- }
5
+ import { detectPackageManager } from '../utils.mjs';
15
6
 
16
7
  /**
17
8
  * Build all resources for a Sunpeak project
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import { existsSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { detectPackageManager } from '../utils.mjs';
6
+
7
+ /**
8
+ * Start the Vite development server
9
+ * Runs in the context of a user's project directory
10
+ */
11
+ export async function dev(projectRoot = process.cwd(), args = []) {
12
+ const pm = detectPackageManager(projectRoot);
13
+
14
+ // Check for package.json
15
+ const pkgJsonPath = join(projectRoot, 'package.json');
16
+ if (!existsSync(pkgJsonPath)) {
17
+ console.error('Error: No package.json found in current directory');
18
+ console.error('Make sure you are in a Sunpeak project directory');
19
+ process.exit(1);
20
+ }
21
+
22
+ // Parse port from args or use default
23
+ let port = process.env.PORT || '6767';
24
+ const portArgIndex = args.findIndex(arg => arg === '--port' || arg === '-p');
25
+ if (portArgIndex !== -1 && args[portArgIndex + 1]) {
26
+ port = args[portArgIndex + 1];
27
+ }
28
+
29
+ // Build vite command
30
+ const viteCommand = pm === 'npm' ? 'npx' : pm;
31
+ const viteArgs = pm === 'npm' ? ['vite'] : ['exec', 'vite'];
32
+
33
+ // Add port
34
+ viteArgs.push('--port', port);
35
+
36
+ // Add any additional args (filtering out port if already handled)
37
+ const additionalArgs = portArgIndex !== -1
38
+ ? [...args.slice(0, portArgIndex), ...args.slice(portArgIndex + 2)]
39
+ : args;
40
+ viteArgs.push(...additionalArgs);
41
+
42
+ console.log(`Starting Vite dev server on port ${port}...`);
43
+
44
+ // Spawn vite process
45
+ const child = spawn(viteCommand, viteArgs, {
46
+ cwd: projectRoot,
47
+ stdio: 'inherit',
48
+ env: {
49
+ ...process.env,
50
+ PORT: port,
51
+ FORCE_COLOR: '1',
52
+ },
53
+ });
54
+
55
+ // Forward signals
56
+ process.on('SIGINT', () => {
57
+ child.kill('SIGINT');
58
+ process.exit(0);
59
+ });
60
+
61
+ process.on('SIGTERM', () => {
62
+ child.kill('SIGTERM');
63
+ process.exit(0);
64
+ });
65
+
66
+ // Handle child exit
67
+ child.on('exit', (code) => {
68
+ process.exit(code || 0);
69
+ });
70
+ }
71
+
72
+ // Allow running directly
73
+ if (import.meta.url === `file://${process.argv[1]}`) {
74
+ const args = process.argv.slice(2);
75
+ dev(process.cwd(), args).catch(error => {
76
+ console.error('Error:', error.message);
77
+ process.exit(1);
78
+ });
79
+ }
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import { existsSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { detectPackageManager } from '../utils.mjs';
6
+
7
+ /**
8
+ * Start the MCP server with auto-reload
9
+ * Runs in the context of a user's project directory
10
+ */
11
+ export async function mcp(projectRoot = process.cwd(), args = []) {
12
+ const pm = detectPackageManager(projectRoot);
13
+
14
+ // Check for package.json
15
+ const pkgJsonPath = join(projectRoot, 'package.json');
16
+ if (!existsSync(pkgJsonPath)) {
17
+ console.error('Error: No package.json found in current directory');
18
+ console.error('Make sure you are in a Sunpeak project directory');
19
+ process.exit(1);
20
+ }
21
+
22
+ // Check for nodemon config
23
+ const nodemonConfigPath = join(projectRoot, 'nodemon.json');
24
+ if (!existsSync(nodemonConfigPath)) {
25
+ console.error('Error: nodemon.json not found');
26
+ console.error('Expected location: ' + nodemonConfigPath);
27
+ console.error('\nThe MCP server requires nodemon.json for auto-reload configuration.');
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log('Starting MCP server with auto-reload...');
32
+ console.log('Watching src/ for changes...\n');
33
+
34
+ // Build nodemon command
35
+ const nodemonCommand = pm === 'npm' ? 'npx' : pm;
36
+ const nodemonArgs = pm === 'npm' ? ['nodemon'] : ['exec', 'nodemon'];
37
+
38
+ // Add any additional args
39
+ nodemonArgs.push(...args);
40
+
41
+ // Spawn nodemon process
42
+ const child = spawn(nodemonCommand, nodemonArgs, {
43
+ cwd: projectRoot,
44
+ stdio: 'inherit',
45
+ env: {
46
+ ...process.env,
47
+ FORCE_COLOR: '1',
48
+ },
49
+ });
50
+
51
+ // Forward signals
52
+ process.on('SIGINT', () => {
53
+ child.kill('SIGINT');
54
+ process.exit(0);
55
+ });
56
+
57
+ process.on('SIGTERM', () => {
58
+ child.kill('SIGTERM');
59
+ process.exit(0);
60
+ });
61
+
62
+ // Handle child exit
63
+ child.on('exit', (code) => {
64
+ process.exit(code || 0);
65
+ });
66
+ }
67
+
68
+ // Allow running directly
69
+ if (import.meta.url === `file://${process.argv[1]}`) {
70
+ const args = process.argv.slice(2);
71
+ mcp(process.cwd(), args).catch(error => {
72
+ console.error('Error:', error.message);
73
+ process.exit(1);
74
+ });
75
+ }
package/bin/sunpeak.js CHANGED
@@ -4,10 +4,9 @@ import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync, renameSync
4
4
  import { join, dirname, basename } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { createInterface } from 'readline';
7
- import { spawn } from 'child_process';
8
7
 
9
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
- const CLI_DIR = join(__dirname, '..', 'cli');
9
+ const COMMANDS_DIR = join(__dirname, 'commands');
11
10
 
12
11
  function prompt(question) {
13
12
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -19,19 +18,6 @@ function prompt(question) {
19
18
  });
20
19
  }
21
20
 
22
- function runCommand(command, args = [], options = {}) {
23
- const child = spawn(command, args, {
24
- cwd: process.cwd(),
25
- stdio: 'inherit',
26
- env: { ...process.env, FORCE_COLOR: '1' },
27
- ...options,
28
- });
29
-
30
- child.on('exit', (code) => {
31
- process.exit(code || 0);
32
- });
33
- }
34
-
35
21
  function checkPackageJson() {
36
22
  const pkgPath = join(process.cwd(), 'package.json');
37
23
  if (!existsSync(pkgPath)) {
@@ -107,7 +93,14 @@ Done! To get started:
107
93
 
108
94
  cd ${projectName}
109
95
  pnpm install
110
- sunpeak dev
96
+ pnpm dev
97
+
98
+ That's it! Your project commands:
99
+
100
+ pnpm dev # Start development server
101
+ pnpm build # Build for production
102
+ pnpm mcp # Start MCP server
103
+ pnpm test # Run tests
111
104
 
112
105
  See README.md for more details.
113
106
  `);
@@ -130,45 +123,23 @@ const [, , command, ...args] = process.argv;
130
123
  break;
131
124
 
132
125
  case 'dev':
133
- runCommand('pnpm', ['dev', ...args]);
126
+ {
127
+ const { dev } = await import(join(COMMANDS_DIR, 'dev.mjs'));
128
+ await dev(process.cwd(), args);
129
+ }
134
130
  break;
135
131
 
136
132
  case 'build':
137
133
  {
138
- const { build } = await import(join(CLI_DIR, 'build.mjs'));
134
+ const { build } = await import(join(COMMANDS_DIR, 'build.mjs'));
139
135
  await build(process.cwd());
140
136
  }
141
137
  break;
142
138
 
143
139
  case 'mcp':
144
- case 'mcp:serve':
145
- if (command === 'mcp:serve' || args[0] === 'serve' || args[0] === ':serve') {
146
- runCommand('pnpm', ['mcp:serve', ...(command === 'mcp:serve' ? args : args.slice(1))]);
147
- } else {
148
- runCommand('pnpm', ['mcp', ...args]);
149
- }
150
- break;
151
-
152
- case 'lint':
153
- runCommand('pnpm', ['lint', ...args]);
154
- break;
155
-
156
- case 'typecheck':
157
- runCommand('pnpm', ['typecheck', ...args]);
158
- break;
159
-
160
- case 'test':
161
- runCommand('pnpm', ['test', ...args]);
162
- break;
163
-
164
- case 'format':
165
- runCommand('pnpm', ['format', ...args]);
166
- break;
167
-
168
- case 'validate':
169
140
  {
170
- const { validate } = await import(join(CLI_DIR, 'validate.mjs'));
171
- await validate(process.cwd());
141
+ const { mcp } = await import(join(COMMANDS_DIR, 'mcp.mjs'));
142
+ await mcp(process.cwd(), args);
172
143
  }
173
144
  break;
174
145
 
@@ -178,26 +149,20 @@ const [, , command, ...args] = process.argv;
178
149
  ☀️ 🏔️ sunpeak - The MCP App SDK
179
150
 
180
151
  Usage:
181
- sunpeak <command> [options]
182
-
183
- Commands:
184
- new [name] Create a new project from template
185
- dev Start the development server
186
- build Build all resources for production
187
- mcp Run the MCP server with nodemon
188
- mcp:serve Run the MCP server directly
189
- lint Run ESLint to check code quality
190
- typecheck Run TypeScript type checking
191
- test Run tests with Vitest
192
- format Format code with Prettier
193
- validate Run full validation suite
194
- help Show this help message
195
-
196
- Examples:
197
- sunpeak new my-app
198
- sunpeak dev
199
- sunpeak build
200
- sunpeak mcp
152
+ npx sunpeak new [name] Create a new project (no install needed)
153
+ pnpm dlx sunpeak new Alternative with pnpm
154
+
155
+ Inside your project, use npm scripts:
156
+ pnpm dev Start development server
157
+ pnpm build Build for production
158
+ pnpm mcp Start MCP server
159
+ pnpm test Run tests
160
+
161
+ Direct CLI commands (when sunpeak is installed):
162
+ sunpeak new [name] Create a new project
163
+ sunpeak dev Start dev server
164
+ sunpeak build Build resources
165
+ sunpeak mcp Start MCP server
201
166
 
202
167
  For more information, visit: https://sunpeak.ai/
203
168
  `);
package/bin/utils.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+
4
+ /**
5
+ * Detect package manager for the project
6
+ */
7
+ export function detectPackageManager(projectRoot) {
8
+ if (existsSync(join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
9
+ if (existsSync(join(projectRoot, 'yarn.lock'))) return 'yarn';
10
+ if (existsSync(join(projectRoot, 'package-lock.json'))) return 'npm';
11
+ return 'pnpm'; // default
12
+ }
File without changes
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ const server = require("../server-DpriZ4jT.cjs");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+ const projectRoot = process.cwd();
7
+ async function startServer() {
8
+ const pkgPath = path.join(projectRoot, "package.json");
9
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
10
+ const simulationsPath = path.join(projectRoot, "src/simulations/index.ts");
11
+ const { SIMULATIONS } = await import(simulationsPath);
12
+ const simulations = Object.entries(
13
+ SIMULATIONS
14
+ ).map(([simulationKey, simulation]) => ({
15
+ ...simulation,
16
+ distPath: path.join(projectRoot, `dist/chatgpt/${simulationKey}.js`)
17
+ }));
18
+ server.runMCPServer({
19
+ name: pkg.name || "Sunpeak App",
20
+ version: pkg.version || "0.1.0",
21
+ simulations,
22
+ port: 6766
23
+ });
24
+ }
25
+ startServer().catch((error) => {
26
+ console.error("Failed to start MCP server:", error);
27
+ process.exit(1);
28
+ });
29
+ //# sourceMappingURL=entry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.cjs","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by nodemon or directly to start the MCP server\n * It automatically discovers the user's project and simulations\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { readFileSync } from 'fs';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Dynamically import user's simulations\n const simulationsPath = path.join(projectRoot, 'src/simulations/index.ts');\n const { SIMULATIONS } = await import(simulationsPath);\n\n // Add distPath to each simulation for the MCP server\n const simulations = Object.entries(\n SIMULATIONS as Record<string, Omit<SimulationWithDist, 'distPath'>>\n ).map(([simulationKey, simulation]) => ({\n ...simulation,\n distPath: path.join(projectRoot, `dist/chatgpt/${simulationKey}.js`),\n }));\n\n runMCPServer({\n name: pkg.name || 'Sunpeak App',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":["readFileSync","runMCPServer"],"mappings":";;;;;AAWA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAMA,GAAAA,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,kBAAkB,KAAK,KAAK,aAAa,0BAA0B;AACzE,QAAM,EAAE,YAAA,IAAgB,MAAM,OAAO;AAGrC,QAAM,cAAc,OAAO;AAAA,IACzB;AAAA,EAAA,EACA,IAAI,CAAC,CAAC,eAAe,UAAU,OAAO;AAAA,IACtC,GAAG;AAAA,IACH,UAAU,KAAK,KAAK,aAAa,gBAAgB,aAAa,KAAK;AAAA,EAAA,EACnE;AAEFC,sBAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { r as runMCPServer } from "../server-SBlanUcf.js";
3
+ import path from "path";
4
+ import { readFileSync } from "fs";
5
+ const projectRoot = process.cwd();
6
+ async function startServer() {
7
+ const pkgPath = path.join(projectRoot, "package.json");
8
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
9
+ const simulationsPath = path.join(projectRoot, "src/simulations/index.ts");
10
+ const { SIMULATIONS } = await import(simulationsPath);
11
+ const simulations = Object.entries(
12
+ SIMULATIONS
13
+ ).map(([simulationKey, simulation]) => ({
14
+ ...simulation,
15
+ distPath: path.join(projectRoot, `dist/chatgpt/${simulationKey}.js`)
16
+ }));
17
+ runMCPServer({
18
+ name: pkg.name || "Sunpeak App",
19
+ version: pkg.version || "0.1.0",
20
+ simulations,
21
+ port: 6766
22
+ });
23
+ }
24
+ startServer().catch((error) => {
25
+ console.error("Failed to start MCP server:", error);
26
+ process.exit(1);
27
+ });
28
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sources":["../../src/mcp/entry.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Internal MCP server entry point\n * This is run by nodemon or directly to start the MCP server\n * It automatically discovers the user's project and simulations\n */\nimport { runMCPServer, type SimulationWithDist } from './index.js';\nimport path from 'path';\nimport { readFileSync } from 'fs';\n\n// Determine project root (where this is being run from)\nconst projectRoot = process.cwd();\n\nasync function startServer() {\n // Read package.json for app metadata\n const pkgPath = path.join(projectRoot, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n // Dynamically import user's simulations\n const simulationsPath = path.join(projectRoot, 'src/simulations/index.ts');\n const { SIMULATIONS } = await import(simulationsPath);\n\n // Add distPath to each simulation for the MCP server\n const simulations = Object.entries(\n SIMULATIONS as Record<string, Omit<SimulationWithDist, 'distPath'>>\n ).map(([simulationKey, simulation]) => ({\n ...simulation,\n distPath: path.join(projectRoot, `dist/chatgpt/${simulationKey}.js`),\n }));\n\n runMCPServer({\n name: pkg.name || 'Sunpeak App',\n version: pkg.version || '0.1.0',\n simulations,\n port: 6766,\n });\n}\n\nstartServer().catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;;AAWA,MAAM,cAAc,QAAQ,IAAA;AAE5B,eAAe,cAAc;AAE3B,QAAM,UAAU,KAAK,KAAK,aAAa,cAAc;AACrD,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAGrD,QAAM,kBAAkB,KAAK,KAAK,aAAa,0BAA0B;AACzE,QAAM,EAAE,YAAA,IAAgB,MAAM,OAAO;AAGrC,QAAM,cAAc,OAAO;AAAA,IACzB;AAAA,EAAA,EACA,IAAI,CAAC,CAAC,eAAe,UAAU,OAAO;AAAA,IACtC,GAAG;AAAA,IACH,UAAU,KAAK,KAAK,aAAa,gBAAgB,aAAa,KAAK;AAAA,EAAA,EACnE;AAEF,eAAa;AAAA,IACX,MAAM,IAAI,QAAQ;AAAA,IAClB,SAAS,IAAI,WAAW;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,EAAA,CACP;AACH;AAEA,cAAc,MAAM,CAAC,UAAU;AAC7B,UAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAQ,KAAK,CAAC;AAChB,CAAC;"}