sunpeak 0.5.20 → 0.5.23

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 (55) hide show
  1. package/README.md +9 -4
  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 +28 -71
  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 +5 -2
  22. package/{template/dev/main.tsx → src/dev/entry.tsx} +20 -8
  23. package/src/vite-env.d.ts +10 -0
  24. package/template/.sunpeak/dev.tsx +5 -0
  25. package/template/README.md +17 -35
  26. package/template/index.html +2 -2
  27. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +3 -3
  28. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +1 -1
  29. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +11 -11
  30. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Textarea.js +3 -3
  31. package/template/node_modules/.vite/deps/_metadata.json +34 -34
  32. package/template/node_modules/.vite/deps/{chunk-EVJ3DVH5.js → chunk-LR7NKCX5.js} +7 -7
  33. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  34. package/template/nodemon.json +1 -1
  35. package/template/package.json +3 -16
  36. package/template/src/components/album/albums.tsx +2 -2
  37. package/template/src/dev/entry.tsx +0 -0
  38. package/template/src/mcp/entry.ts +0 -0
  39. package/template/src/simulations/index.ts +3 -3
  40. package/cli/validate.mjs +0 -245
  41. package/template/_prettierignore +0 -4
  42. package/template/_prettierrc +0 -9
  43. package/template/eslint.config.cjs +0 -49
  44. package/template/mcp/server.ts +0 -19
  45. package/template/node_modules/.bin/eslint +0 -21
  46. package/template/node_modules/.bin/eslint-config-prettier +0 -21
  47. package/template/node_modules/.bin/prettier +0 -21
  48. package/template/node_modules/.bin/ts-node +0 -21
  49. package/template/node_modules/.bin/ts-node-cwd +0 -21
  50. package/template/node_modules/.bin/ts-node-esm +0 -21
  51. package/template/node_modules/.bin/ts-node-script +0 -21
  52. package/template/node_modules/.bin/ts-node-transpile-only +0 -21
  53. package/template/node_modules/.bin/ts-script +0 -21
  54. /package/template/node_modules/.vite/deps/{chunk-EVJ3DVH5.js.map → chunk-LR7NKCX5.js.map} +0 -0
  55. /package/template/{assets → public}/favicon.ico +0 -0
package/README.md CHANGED
@@ -36,11 +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
- # Install the CLI globally
40
- pnpm add -g sunpeak
39
+ # Create a new project (no install needed)
40
+ npx sunpeak new my-app
41
41
 
42
- # Create a new project
43
- sunpeak new
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
44
49
  ```
45
50
 
46
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)) {
@@ -105,17 +91,16 @@ async function init(projectName) {
105
91
  console.log(`
106
92
  Done! To get started:
107
93
 
108
- # Install the CLI (if not already installed)
109
- pnpm add -g sunpeak
110
-
111
- # Navigate to your project and install dependencies
112
94
  cd ${projectName}
113
95
  pnpm install
96
+ pnpm dev
114
97
 
115
- # Start development
116
- sunpeak dev
98
+ That's it! Your project commands:
117
99
 
118
- Alternatively, use "pnpm dlx sunpeak dev" if you prefer not to install globally.
100
+ pnpm dev # Start development server
101
+ pnpm build # Build for production
102
+ pnpm mcp # Start MCP server
103
+ pnpm test # Run tests
119
104
 
120
105
  See README.md for more details.
121
106
  `);
@@ -138,45 +123,23 @@ const [, , command, ...args] = process.argv;
138
123
  break;
139
124
 
140
125
  case 'dev':
141
- runCommand('pnpm', ['dev', ...args]);
126
+ {
127
+ const { dev } = await import(join(COMMANDS_DIR, 'dev.mjs'));
128
+ await dev(process.cwd(), args);
129
+ }
142
130
  break;
143
131
 
144
132
  case 'build':
145
133
  {
146
- const { build } = await import(join(CLI_DIR, 'build.mjs'));
134
+ const { build } = await import(join(COMMANDS_DIR, 'build.mjs'));
147
135
  await build(process.cwd());
148
136
  }
149
137
  break;
150
138
 
151
139
  case 'mcp':
152
- case 'mcp:serve':
153
- if (command === 'mcp:serve' || args[0] === 'serve' || args[0] === ':serve') {
154
- runCommand('pnpm', ['mcp:serve', ...(command === 'mcp:serve' ? args : args.slice(1))]);
155
- } else {
156
- runCommand('pnpm', ['mcp', ...args]);
157
- }
158
- break;
159
-
160
- case 'lint':
161
- runCommand('pnpm', ['lint', ...args]);
162
- break;
163
-
164
- case 'typecheck':
165
- runCommand('pnpm', ['typecheck', ...args]);
166
- break;
167
-
168
- case 'test':
169
- runCommand('pnpm', ['test', ...args]);
170
- break;
171
-
172
- case 'format':
173
- runCommand('pnpm', ['format', ...args]);
174
- break;
175
-
176
- case 'validate':
177
140
  {
178
- const { validate } = await import(join(CLI_DIR, 'validate.mjs'));
179
- await validate(process.cwd());
141
+ const { mcp } = await import(join(COMMANDS_DIR, 'mcp.mjs'));
142
+ await mcp(process.cwd(), args);
180
143
  }
181
144
  break;
182
145
 
@@ -186,26 +149,20 @@ const [, , command, ...args] = process.argv;
186
149
  ☀️ 🏔️ sunpeak - The MCP App SDK
187
150
 
188
151
  Usage:
189
- sunpeak <command> [options]
190
-
191
- Commands:
192
- new [name] Create a new project from template
193
- dev Start the development server
194
- build Build all resources for production
195
- mcp Run the MCP server with nodemon
196
- mcp:serve Run the MCP server directly
197
- lint Run ESLint to check code quality
198
- typecheck Run TypeScript type checking
199
- test Run tests with Vitest
200
- format Format code with Prettier
201
- validate Run full validation suite
202
- help Show this help message
203
-
204
- Examples:
205
- sunpeak new my-app
206
- sunpeak dev
207
- sunpeak build
208
- 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
209
166
 
210
167
  For more information, visit: https://sunpeak.ai/
211
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;"}