@kosuke-ai/cli 0.0.30 → 0.0.31

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 (38) hide show
  1. package/dist/kosuke/commands/ship.d.ts.map +1 -1
  2. package/dist/kosuke/commands/ship.js +57 -22
  3. package/dist/kosuke/commands/ship.js.map +1 -1
  4. package/dist/kosuke/commands/test.d.ts +8 -9
  5. package/dist/kosuke/commands/test.d.ts.map +1 -1
  6. package/dist/kosuke/commands/test.js +68 -288
  7. package/dist/kosuke/commands/test.js.map +1 -1
  8. package/dist/kosuke/types.d.ts +8 -16
  9. package/dist/kosuke/types.d.ts.map +1 -1
  10. package/dist/kosuke/utils/browser-agent.d.ts +33 -0
  11. package/dist/kosuke/utils/browser-agent.d.ts.map +1 -0
  12. package/dist/kosuke/utils/browser-agent.js +102 -0
  13. package/dist/kosuke/utils/browser-agent.js.map +1 -0
  14. package/dist/kosuke/utils/error-analyzer.d.ts +6 -3
  15. package/dist/kosuke/utils/error-analyzer.d.ts.map +1 -1
  16. package/dist/kosuke/utils/error-analyzer.js +35 -57
  17. package/dist/kosuke/utils/error-analyzer.js.map +1 -1
  18. package/dist/kosuke/utils/prompt-generator.d.ts +13 -0
  19. package/dist/kosuke/utils/prompt-generator.d.ts.map +1 -0
  20. package/dist/kosuke/utils/prompt-generator.js +44 -0
  21. package/dist/kosuke/utils/prompt-generator.js.map +1 -0
  22. package/dist/lib.d.ts +1 -1
  23. package/dist/lib.d.ts.map +1 -1
  24. package/dist/lib.js.map +1 -1
  25. package/dist/package.json +3 -6
  26. package/package.json +3 -6
  27. package/dist/kosuke/utils/playwright-agent.d.ts +0 -47
  28. package/dist/kosuke/utils/playwright-agent.d.ts.map +0 -1
  29. package/dist/kosuke/utils/playwright-agent.js +0 -278
  30. package/dist/kosuke/utils/playwright-agent.js.map +0 -1
  31. package/dist/kosuke/utils/test-generator.d.ts +0 -22
  32. package/dist/kosuke/utils/test-generator.d.ts.map +0 -1
  33. package/dist/kosuke/utils/test-generator.js +0 -174
  34. package/dist/kosuke/utils/test-generator.js.map +0 -1
  35. package/dist/kosuke/utils/visual-tester.d.ts +0 -71
  36. package/dist/kosuke/utils/visual-tester.d.ts.map +0 -1
  37. package/dist/kosuke/utils/visual-tester.js +0 -202
  38. package/dist/kosuke/utils/visual-tester.js.map +0 -1
@@ -1,278 +0,0 @@
1
- /**
2
- * Playwright Agent - Test execution orchestration
3
- *
4
- * Executes Playwright tests with logging and visual regression
5
- */
6
- import { execSync } from 'child_process';
7
- import { existsSync, mkdirSync, writeFileSync } from 'fs';
8
- import { join } from 'path';
9
- /**
10
- * Run Playwright tests
11
- */
12
- export async function runPlaywrightTests(options) {
13
- const { testFile, baseUrl, headed = false, debug = false, cwd = process.cwd() } = options;
14
- // Ensure test results directory exists
15
- const resultsDir = join(cwd, 'test-results');
16
- if (!existsSync(resultsDir)) {
17
- mkdirSync(resultsDir, { recursive: true });
18
- }
19
- const ticketId = testFile.split('/').pop()?.replace('.spec.ts', '') || 'unknown';
20
- const tracePath = join(resultsDir, `trace-${ticketId}.zip`);
21
- // Build Playwright command
22
- const args = [
23
- 'playwright',
24
- 'test',
25
- testFile,
26
- `--config=${join(cwd, 'playwright.config.ts')}`,
27
- '--reporter=json',
28
- ];
29
- if (headed) {
30
- args.push('--headed');
31
- }
32
- if (debug) {
33
- args.push('--debug');
34
- }
35
- // Set environment variables
36
- const env = {
37
- ...process.env,
38
- BASE_URL: baseUrl,
39
- PLAYWRIGHT_TRACE: 'on',
40
- };
41
- console.log(` 🎯 Running Playwright tests...`);
42
- const startTime = Date.now();
43
- try {
44
- // Run Playwright using npx (works with any package manager)
45
- const output = execSync(`npx ${args.join(' ')}`, {
46
- cwd,
47
- env,
48
- encoding: 'utf-8',
49
- stdio: ['pipe', 'pipe', 'pipe'], // Capture all output
50
- });
51
- const duration = Date.now() - startTime;
52
- const result = parsePlaywrightOutput(output, tracePath, duration);
53
- return result;
54
- }
55
- catch (error) {
56
- // Playwright exits with non-zero code when tests fail
57
- const duration = Date.now() - startTime;
58
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
- const output = error instanceof Error && 'stdout' in error ? error.stdout : '';
60
- const result = parsePlaywrightOutput(output, tracePath, duration);
61
- return result;
62
- }
63
- }
64
- /**
65
- * Parse Playwright JSON output
66
- */
67
- function parsePlaywrightOutput(output, tracePath, duration) {
68
- try {
69
- // Try to parse JSON output
70
- const jsonMatch = output.match(/\{[\s\S]*"suites"[\s\S]*\}/);
71
- if (jsonMatch) {
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
- const json = JSON.parse(jsonMatch[0]);
74
- return parsePlaywrightJson(json, tracePath, duration);
75
- }
76
- }
77
- catch {
78
- // If JSON parsing fails, fall back to text parsing
79
- }
80
- // Fallback: parse text output
81
- return parsePlaywrightText(output, tracePath, duration);
82
- }
83
- /**
84
- * Parse Playwright JSON report
85
- */
86
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
- function parsePlaywrightJson(json, tracePath, duration) {
88
- const failures = [];
89
- let testsRun = 0;
90
- let testsPassed = 0;
91
- let testsFailed = 0;
92
- // Parse test results
93
- for (const suite of json.suites || []) {
94
- for (const spec of suite.specs || []) {
95
- for (const test of spec.tests || []) {
96
- testsRun++;
97
- const result = test.results?.[0];
98
- if (result?.status === 'passed') {
99
- testsPassed++;
100
- }
101
- else {
102
- testsFailed++;
103
- failures.push({
104
- testName: spec.title || 'Unknown test',
105
- errorMessage: result?.error?.message || 'Test failed',
106
- expected: extractExpected(result?.error?.message),
107
- received: extractReceived(result?.error?.message),
108
- });
109
- }
110
- }
111
- }
112
- }
113
- return {
114
- success: testsFailed === 0,
115
- testsRun,
116
- testsPassed,
117
- testsFailed,
118
- failures,
119
- tracePath,
120
- duration,
121
- };
122
- }
123
- /**
124
- * Parse Playwright text output (fallback)
125
- */
126
- function parsePlaywrightText(output, tracePath, duration) {
127
- const failures = [];
128
- // Look for test failures in output
129
- const failureMatches = output.matchAll(/✘ (.+?)\n[\s\S]*?Error: (.+?)(?:\n|$)/g);
130
- for (const match of failureMatches) {
131
- failures.push({
132
- testName: match[1].trim(),
133
- errorMessage: match[2].trim(),
134
- });
135
- }
136
- // Count tests
137
- const passedMatch = output.match(/(\d+) passed/);
138
- const failedMatch = output.match(/(\d+) failed/);
139
- const testsPassed = passedMatch ? parseInt(passedMatch[1]) : 0;
140
- const testsFailed = failedMatch ? parseInt(failedMatch[1]) : failures.length;
141
- const testsRun = testsPassed + testsFailed;
142
- return {
143
- success: testsFailed === 0,
144
- testsRun,
145
- testsPassed,
146
- testsFailed,
147
- failures,
148
- tracePath,
149
- duration,
150
- };
151
- }
152
- /**
153
- * Extract expected value from error message
154
- */
155
- function extractExpected(errorMessage) {
156
- if (!errorMessage)
157
- return undefined;
158
- const match = errorMessage.match(/Expected:?\s*(.+?)(?:\n|Received)/i);
159
- return match ? match[1].trim() : undefined;
160
- }
161
- /**
162
- * Extract received value from error message
163
- */
164
- function extractReceived(errorMessage) {
165
- if (!errorMessage)
166
- return undefined;
167
- const match = errorMessage.match(/Received:?\s*(.+?)(?:\n|$)/i);
168
- return match ? match[1].trim() : undefined;
169
- }
170
- /**
171
- * Check if Playwright is installed
172
- */
173
- export function isPlaywrightInstalled(cwd = process.cwd()) {
174
- try {
175
- execSync('npx playwright --version', {
176
- cwd,
177
- encoding: 'utf-8',
178
- stdio: 'ignore',
179
- });
180
- return true;
181
- }
182
- catch {
183
- return false;
184
- }
185
- }
186
- /**
187
- * Check if Playwright browsers are installed
188
- */
189
- export function areBrowsersInstalled() {
190
- try {
191
- // Run playwright install --dry-run to check if browsers need installation
192
- const output = execSync('npx playwright install chromium --dry-run', {
193
- encoding: 'utf-8',
194
- stdio: 'pipe',
195
- });
196
- // If output contains download URLs or "Install location", browsers need installation
197
- // If output is empty or very short, browsers are already installed
198
- const needsInstall = output.includes('Download url:') ||
199
- output.includes('Install location:') ||
200
- output.includes('browser:');
201
- return !needsInstall;
202
- }
203
- catch {
204
- // If command fails, assume browsers aren't installed
205
- return false;
206
- }
207
- }
208
- /**
209
- * Install Playwright
210
- */
211
- export async function installPlaywright(cwd = process.cwd()) {
212
- console.log('📦 Installing Playwright...');
213
- try {
214
- // Install @playwright/test
215
- execSync('npm install --save-dev @playwright/test', {
216
- cwd,
217
- encoding: 'utf-8',
218
- stdio: 'inherit',
219
- });
220
- // Install browsers
221
- await installBrowsers();
222
- console.log(' ✅ Playwright installed\n');
223
- }
224
- catch (error) {
225
- throw new Error(`Failed to install Playwright: ${error}`);
226
- }
227
- }
228
- /**
229
- * Install Playwright browsers only
230
- */
231
- export async function installBrowsers() {
232
- try {
233
- execSync('npx playwright install chromium', {
234
- encoding: 'utf-8',
235
- stdio: 'inherit',
236
- });
237
- console.log(' ✅ Browsers installed\n');
238
- }
239
- catch (error) {
240
- throw new Error(`Failed to install browsers: ${error}`);
241
- }
242
- }
243
- /**
244
- * Ensure Playwright config exists
245
- */
246
- export function ensurePlaywrightConfig(cwd = process.cwd()) {
247
- const configPath = join(cwd, 'playwright.config.ts');
248
- if (existsSync(configPath)) {
249
- return; // Config already exists
250
- }
251
- console.log('📝 Creating playwright.config.ts...');
252
- const configContent = `import { defineConfig, devices } from '@playwright/test';
253
-
254
- export default defineConfig({
255
- testDir: './.kosuke/tests',
256
- fullyParallel: false,
257
- forbidOnly: !!process.env.CI,
258
- retries: 0,
259
- workers: 1,
260
- reporter: 'html',
261
- use: {
262
- baseURL: process.env.BASE_URL || 'http://localhost:3000',
263
- trace: 'retain-on-failure',
264
- screenshot: 'only-on-failure',
265
- video: 'retain-on-failure',
266
- },
267
- projects: [
268
- {
269
- name: 'chromium',
270
- use: { ...devices['Desktop Chrome'] },
271
- },
272
- ],
273
- });
274
- `;
275
- writeFileSync(configPath, configContent, 'utf-8');
276
- console.log(' ✅ Config created\n');
277
- }
278
- //# sourceMappingURL=playwright-agent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"playwright-agent.js","sourceRoot":"","sources":["../../../kosuke/utils/playwright-agent.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- /**
2
- * Test Generator - AI-powered Playwright test generation
3
- *
4
- * Uses Claude to generate Playwright tests from ticket descriptions
5
- */
6
- import type { Ticket } from '../types.js';
7
- export interface GeneratedTest {
8
- filePath: string;
9
- content: string;
10
- tokensUsed: {
11
- input: number;
12
- output: number;
13
- cacheCreation: number;
14
- cacheRead: number;
15
- };
16
- cost: number;
17
- }
18
- /**
19
- * Generate Playwright test from ticket description
20
- */
21
- export declare function generateTest(ticket: Ticket, baseUrl: string, cwd?: string): Promise<GeneratedTest>;
22
- //# sourceMappingURL=test-generator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-generator.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/test-generator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAkDxB"}
@@ -1,174 +0,0 @@
1
- /**
2
- * Test Generator - AI-powered Playwright test generation
3
- *
4
- * Uses Claude to generate Playwright tests from ticket descriptions
5
- */
6
- import { existsSync, mkdirSync, writeFileSync } from 'fs';
7
- import { join } from 'path';
8
- import { runAgent } from './claude-agent.js';
9
- /**
10
- * Generate Playwright test from ticket description
11
- */
12
- export async function generateTest(ticket, baseUrl, cwd = process.cwd()) {
13
- const testDir = join(cwd, '.kosuke', 'tests');
14
- const testFilePath = join(testDir, `${ticket.id}.spec.ts`);
15
- // Ensure test directory exists
16
- if (!existsSync(testDir)) {
17
- mkdirSync(testDir, { recursive: true });
18
- }
19
- // Check if test already exists
20
- if (existsSync(testFilePath)) {
21
- console.log(` ✅ Test already exists: ${testFilePath}`);
22
- return {
23
- filePath: testFilePath,
24
- content: '',
25
- tokensUsed: {
26
- input: 0,
27
- output: 0,
28
- cacheCreation: 0,
29
- cacheRead: 0,
30
- },
31
- cost: 0,
32
- };
33
- }
34
- console.log(` 🤖 Generating test using Claude...`);
35
- const systemPrompt = buildTestGenerationPrompt(ticket, baseUrl);
36
- const result = await runAgent(`Generate Playwright test for ticket ${ticket.id}`, {
37
- systemPrompt,
38
- cwd,
39
- maxTurns: 15,
40
- verbosity: 'minimal',
41
- });
42
- // Extract test code from response
43
- const testContent = extractTestCode(result.response, ticket, baseUrl);
44
- // Save test file
45
- writeFileSync(testFilePath, testContent, 'utf-8');
46
- console.log(` ✅ Test generated: ${testFilePath}`);
47
- return {
48
- filePath: testFilePath,
49
- content: testContent,
50
- tokensUsed: result.tokensUsed,
51
- cost: result.cost,
52
- };
53
- }
54
- /**
55
- * Build system prompt for test generation
56
- */
57
- function buildTestGenerationPrompt(ticket, baseUrl) {
58
- return `You are an expert QA engineer creating Playwright end-to-end tests.
59
-
60
- **Your Task:**
61
- Generate a comprehensive Playwright test file for the following ticket.
62
-
63
- **Ticket Information:**
64
- - ID: ${ticket.id}
65
- - Title: ${ticket.title}
66
- - Description:
67
- ${ticket.description}
68
-
69
- **Application URL:** ${baseUrl}
70
-
71
- **Test Requirements:**
72
- 1. Create a complete Playwright test file in TypeScript
73
- 2. Include multiple test cases covering:
74
- - Happy path (main functionality)
75
- - Edge cases (validation, errors)
76
- - Visual regression test (one screenshot)
77
- 3. Use proper Playwright selectors (prefer getByRole, getByLabel, getByText)
78
- 4. Include proper assertions with expect()
79
- 5. Add comments explaining what each test does
80
- 6. Follow Playwright best practices
81
-
82
- **Test Structure:**
83
- \`\`\`typescript
84
- import { test, expect } from '@playwright/test';
85
-
86
- test.describe('${ticket.id}: ${ticket.title}', () => {
87
- test.beforeEach(async ({ page }) => {
88
- // Navigate to the relevant page
89
- await page.goto('${baseUrl}/...');
90
- });
91
-
92
- test('should [describe main functionality]', async ({ page }) => {
93
- // Test implementation
94
- });
95
-
96
- test('should handle [edge case]', async ({ page }) => {
97
- // Test implementation
98
- });
99
-
100
- test('visual regression: [page/component] renders correctly', async ({ page }) => {
101
- // Wait for page to be stable
102
- await page.waitForLoadState('networkidle');
103
-
104
- // Take screenshot
105
- const screenshot = await page.screenshot({ fullPage: true });
106
-
107
- // Compare with baseline (handled by visual tester)
108
- expect(screenshot).toBeDefined();
109
- });
110
- });
111
- \`\`\`
112
-
113
- **Critical Instructions:**
114
- 1. Analyze the ticket description to understand what features to test
115
- 2. Determine the correct URL paths based on the feature
116
- 3. Generate realistic test data (emails, names, etc.)
117
- 4. Include proper waits (waitForLoadState, waitForSelector)
118
- 5. Test both success and failure scenarios
119
- 6. Add one visual regression test at the end
120
- 7. Output ONLY the test code - no explanations outside the code
121
-
122
- Generate the complete test file now:`;
123
- }
124
- /**
125
- * Extract test code from Claude's response
126
- */
127
- function extractTestCode(response, ticket, baseUrl) {
128
- // Look for code blocks in the response
129
- const codeBlockMatch = response.match(/```(?:typescript|ts)?\n([\s\S]+?)\n```/);
130
- if (codeBlockMatch) {
131
- return codeBlockMatch[1].trim();
132
- }
133
- // If no code block found, try to use the whole response
134
- // or generate a basic template
135
- if (response.includes('import') && response.includes('test(')) {
136
- return response.trim();
137
- }
138
- // Fallback: generate basic template
139
- console.log(' ⚠️ Could not extract test code, generating basic template');
140
- return generateBasicTemplate(ticket, baseUrl);
141
- }
142
- /**
143
- * Generate a basic test template as fallback
144
- */
145
- function generateBasicTemplate(ticket, baseUrl) {
146
- return `import { test, expect } from '@playwright/test';
147
-
148
- test.describe('${ticket.id}: ${ticket.title}', () => {
149
- test.beforeEach(async ({ page }) => {
150
- // TODO: Update this URL to the correct path for the feature
151
- await page.goto('${baseUrl}');
152
- });
153
-
154
- test('should load the page', async ({ page }) => {
155
- // TODO: Add assertions to verify the page loaded correctly
156
- await expect(page.locator('body')).toBeVisible();
157
- });
158
-
159
- test('should interact with main feature', async ({ page }) => {
160
- // TODO: Add test steps for the main functionality
161
- // Example:
162
- // await page.getByRole('button', { name: 'Submit' }).click();
163
- // await expect(page.getByText('Success')).toBeVisible();
164
- });
165
-
166
- test('visual regression: page renders correctly', async ({ page }) => {
167
- await page.waitForLoadState('networkidle');
168
- const screenshot = await page.screenshot({ fullPage: true });
169
- expect(screenshot).toBeDefined();
170
- });
171
- });
172
- `;
173
- }
174
- //# sourceMappingURL=test-generator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-generator.js","sourceRoot":"","sources":["../../../kosuke/utils/test-generator.ts"],"names":[],"mappings":"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"}
@@ -1,71 +0,0 @@
1
- /**
2
- * Visual Tester - Visual regression testing with screenshot comparison
3
- *
4
- * Inspired by Subito.it's approach:
5
- * - Capture screenshots of pages
6
- * - Compare against baseline images
7
- * - Detect pixel differences above threshold
8
- * - Hide dynamic content (ads, analytics)
9
- */
10
- import type { Page } from '@playwright/test';
11
- export interface VisualDiff {
12
- testName: string;
13
- diffPixels: number;
14
- diffPercentage: number;
15
- threshold: number;
16
- passed: boolean;
17
- baselinePath: string;
18
- currentPath: string;
19
- diffPath: string;
20
- }
21
- export interface VisualTestOptions {
22
- ticketId: string;
23
- testName: string;
24
- threshold?: number;
25
- updateBaseline?: boolean;
26
- }
27
- /**
28
- * Visual Tester class for screenshot comparison
29
- */
30
- export declare class VisualTester {
31
- private cwd;
32
- private diffs;
33
- constructor(cwd?: string);
34
- /**
35
- * Hide dynamic content that shouldn't be tested
36
- */
37
- hideDynamicContent(page: Page): Promise<void>;
38
- /**
39
- * Take a screenshot and compare with baseline
40
- */
41
- captureAndCompare(page: Page, options: VisualTestOptions): Promise<VisualDiff>;
42
- /**
43
- * Compare two images and generate diff
44
- */
45
- private compareImages;
46
- /**
47
- * Get all visual diffs
48
- */
49
- getDiffs(): VisualDiff[];
50
- /**
51
- * Get failed visual diffs
52
- */
53
- getFailedDiffs(): VisualDiff[];
54
- /**
55
- * Check if there are any visual regressions
56
- */
57
- hasRegressions(): boolean;
58
- /**
59
- * Format visual diff report
60
- */
61
- formatReport(): string;
62
- /**
63
- * Clear all diffs
64
- */
65
- clear(): void;
66
- /**
67
- * Ensure directory exists
68
- */
69
- private ensureDir;
70
- }
71
- //# sourceMappingURL=visual-tester.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visual-tester.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/visual-tester.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAoB;gBAErB,GAAG,GAAE,MAAsB;IAIvC;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnD;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuDpF;;OAEG;IACH,OAAO,CAAC,aAAa;IAwErB;;OAEG;IACH,QAAQ,IAAI,UAAU,EAAE;IAIxB;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAI9B;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;OAEG;IACH,YAAY,IAAI,MAAM;IA2BtB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,SAAS;CAKlB"}