@cementic/cementic-test 0.2.16 → 0.2.17

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/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/new.ts","../src/commands/normalize.ts","../src/commands/test.ts","../src/commands/tc.ts","../src/core/prefix.ts","../src/core/llm-provider.ts","../src/core/llm.ts","../src/core/analyse.ts","../src/core/report.ts","../src/commands/report.ts","../src/commands/serve.ts","../src/commands/flow.ts","../src/commands/ci.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { newCmd } from './commands/new.js';\nimport { normalizeCmd } from './commands/normalize.js';\nimport { genCmd } from './commands/gen.js';\nimport { testCmd } from './commands/test.js';\nimport { tcCmd } from './commands/tc.js';\nimport { reportCmd } from './commands/report.js';\nimport { serveCmd } from './commands/serve.js';\nimport { flowCmd } from './commands/flow.js';\nimport { ciCmd } from './commands/ci.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json');\n\nconst program = new Command();\nprogram\n .name('ct')\n .description('CementicTest CLI: cases → normalized → POM tests → Playwright')\n .version(version);\n\nprogram.addCommand(newCmd());\nprogram.addCommand(normalizeCmd());\nprogram.addCommand(genCmd());\nprogram.addCommand(testCmd());\nprogram.addCommand(tcCmd());\nprogram.addCommand(reportCmd());\nprogram.addCommand(serveCmd());\nprogram.addCommand(flowCmd());\nprogram.addCommand(ciCmd());\n\nprogram.parseAsync(process.argv);","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync, existsSync, readFileSync, cpSync, readdirSync, statSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { dirname } from 'node:path';\nimport { platform, release } from 'node:os';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst LEGACY_MACOS_DARWIN_MAJOR = 23;\nconst LEGACY_PLAYWRIGHT_VERSION = '^1.48.2';\nconst LEGACY_ALLURE_VERSION = '^2.15.1';\n\ntype BrowserInstallProfile = 'auto' | 'all' | 'chromium';\n\ntype BootstrapPlan = {\n browserInstallArgs: string[];\n browserProfile: Exclude<BrowserInstallProfile, 'auto'>;\n isLegacyMacOs: boolean;\n packageVersionOverrides: Record<string, string>;\n reason?: string;\n};\n\nfunction resolveTemplatePath(templateDir: string): string | undefined {\n const candidates = [\n resolve(__dirname, `templates/${templateDir}`),\n resolve(__dirname, `../templates/${templateDir}`),\n resolve(__dirname, `../../templates/${templateDir}`),\n resolve(process.cwd(), `templates/${templateDir}`),\n ];\n\n return candidates.find(candidate => existsSync(candidate));\n}\n\nfunction getHostPlatform(env: NodeJS.ProcessEnv = process.env): string {\n return (env.CT_OS_PLATFORM_OVERRIDE ?? platform()).trim().toLowerCase();\n}\n\nfunction getHostRelease(env: NodeJS.ProcessEnv = process.env): string {\n return (env.CT_OS_RELEASE_OVERRIDE ?? release()).trim();\n}\n\nfunction isLegacyMacOs(env: NodeJS.ProcessEnv = process.env): boolean {\n if (getHostPlatform(env) !== 'darwin') return false;\n\n const majorVersion = parseInt(getHostRelease(env).split('.')[0], 10);\n return Number.isFinite(majorVersion) && majorVersion < LEGACY_MACOS_DARWIN_MAJOR;\n}\n\nfunction resolveBrowserInstallProfile(raw?: string): BrowserInstallProfile {\n const profile = String(raw ?? 'auto').trim().toLowerCase();\n if (profile === 'auto' || profile === 'all' || profile === 'chromium') return profile;\n\n console.error(`❌ Unsupported browser install profile \"${raw}\". Use \"auto\", \"all\", or \"chromium\".`);\n process.exit(1);\n}\n\nfunction resolveBootstrapPlan(\n browserProfile: BrowserInstallProfile,\n env: NodeJS.ProcessEnv = process.env,\n): BootstrapPlan {\n const legacyMacOs = isLegacyMacOs(env);\n const resolvedProfile =\n browserProfile === 'auto'\n ? (legacyMacOs ? 'chromium' : 'all')\n : browserProfile;\n\n return {\n browserInstallArgs: resolvedProfile === 'chromium' ? ['playwright', 'install', 'chromium'] : ['playwright', 'install'],\n browserProfile: resolvedProfile,\n isLegacyMacOs: legacyMacOs,\n packageVersionOverrides: legacyMacOs\n ? {\n '@playwright/test': LEGACY_PLAYWRIGHT_VERSION,\n 'allure-playwright': LEGACY_ALLURE_VERSION,\n }\n : {},\n reason: legacyMacOs\n ? 'Detected macOS 13 or older. Using a legacy-compatible Playwright toolchain and Chromium-only browser install.'\n : undefined,\n };\n}\n\nfunction applyPackageVersionOverrides(projectPath: string, versionOverrides: Record<string, string>): void {\n if (Object.keys(versionOverrides).length === 0) return;\n\n const pkgJsonPath = join(projectPath, 'package.json');\n if (!existsSync(pkgJsonPath)) return;\n\n try {\n const pkgContent = readFileSync(pkgJsonPath, 'utf-8');\n const pkg = JSON.parse(pkgContent);\n const devDependencies = pkg.devDependencies ?? {};\n\n let changed = false;\n for (const [name, version] of Object.entries(versionOverrides)) {\n if (typeof devDependencies[name] !== 'string') continue;\n devDependencies[name] = version;\n changed = true;\n }\n\n if (!changed) return;\n\n pkg.devDependencies = devDependencies;\n writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2));\n console.log('✅ Applied compatibility dependency pins for this machine.');\n } catch (err) {\n console.warn('⚠️ Failed to adjust package.json for OS compatibility:', err);\n }\n}\n\nexport function newCmd() {\n const cmd = new Command('new')\n .arguments('<projectName>')\n .description('Scaffold a new CementicTest + Playwright project from scratch')\n .addHelpText('after', `\nExamples:\n $ ct new my-awesome-test-suite\n $ ct new e2e-ts --lang ts\n $ ct new e2e-tests --no-browsers\n`)\n .option('--mode <mode>', 'greenfield|enhance', 'greenfield')\n .option('--lang <lang>', 'Scaffold language (js|ts)', 'js')\n .option('--browser-set <profile>', 'Browser install profile (auto|all|chromium)', 'auto')\n .option('--no-browsers', 'do not run \"npx playwright install\" during setup')\n .action((projectName: string, opts) => {\n const mode = String(opts.mode ?? 'greenfield').trim().toLowerCase();\n if (mode !== 'greenfield') {\n console.error(`❌ Unsupported scaffold mode \"${opts.mode}\". Only \"greenfield\" is currently implemented.`);\n process.exit(1);\n }\n const browserInstallProfile = resolveBrowserInstallProfile(opts.browserSet);\n const bootstrapPlan = resolveBootstrapPlan(browserInstallProfile);\n\n const root = process.cwd();\n const projectPath = join(root, projectName);\n\n console.log(`🚀 Initializing new CementicTest project in ${projectName}...`);\n\n // 1. Create project directory\n if (existsSync(projectPath)) {\n console.error(`❌ Directory ${projectName} already exists.`);\n process.exit(1);\n }\n mkdirSync(projectPath, { recursive: true });\n\n const lang = opts.lang === 'ts' ? 'ts' : 'js';\n const templateDir = lang === 'ts' ? 'student-framework-ts' : 'student-framework';\n const templatePath = resolveTemplatePath(templateDir);\n\n if (!templatePath) {\n console.error(`❌ Could not locate template \"${templateDir}\"`);\n console.error('Please ensure the package is built correctly with templates included.');\n process.exit(1);\n }\n\n console.log(`📦 Copying template from ${templatePath}...`);\n \n // Recursive copy function\n function copyRecursive(src: string, dest: string) {\n if (statSync(src).isDirectory()) {\n mkdirSync(dest, { recursive: true });\n readdirSync(src).forEach(child => {\n copyRecursive(join(src, child), join(dest, child));\n });\n } else {\n cpSync(src, dest);\n }\n }\n\n copyRecursive(templatePath, projectPath);\n\n if (bootstrapPlan.reason) {\n console.log(`🍎 ${bootstrapPlan.reason}`);\n }\n applyPackageVersionOverrides(projectPath, bootstrapPlan.packageVersionOverrides);\n\n // 3. Initialize git\n try {\n execSync('git init', { cwd: projectPath, stdio: 'ignore' });\n // Create .gitignore if not exists (template should have it, but just in case)\n const gitignorePath = join(projectPath, '.gitignore');\n if (!existsSync(gitignorePath)) {\n writeFileSync(gitignorePath, 'node_modules\\n.env\\ntest-results\\nplaywright-report\\n.cementic\\n');\n }\n } catch (e) {\n console.warn('⚠️ Failed to initialize git repository.');\n }\n\n // 4. Install dependencies\n console.log('📦 Installing dependencies...');\n let dependenciesInstalled = false;\n try {\n execSync('npm install', { cwd: projectPath, stdio: 'inherit' });\n dependenciesInstalled = true;\n } catch (e) {\n console.error('❌ Failed to install dependencies. Please run \"npm install\" manually.');\n }\n\n // 5. Install browsers (optional)\n // Commander maps --no-browsers to opts.browsers = false\n if (opts.browsers !== false && dependenciesInstalled) {\n console.log('🌐 Installing Playwright browsers...');\n try {\n const installCommand = `npx ${bootstrapPlan.browserInstallArgs.join(' ')}`;\n if (bootstrapPlan.browserProfile === 'chromium' && bootstrapPlan.isLegacyMacOs) {\n console.log('⚠️ WebKit is not supported on this macOS version. Installing Chromium only...');\n } else if (bootstrapPlan.browserProfile === 'chromium') {\n console.log('ℹ️ Installing Chromium only because --browser-set chromium was requested.');\n }\n execSync(installCommand, { cwd: projectPath, stdio: 'inherit' });\n console.log(\n bootstrapPlan.browserProfile === 'chromium'\n ? '✅ Chromium installed successfully.'\n : '✅ Playwright browsers installed successfully.',\n );\n } catch (e) {\n console.warn('⚠️ Browser installation did not complete. You can finish setup with:');\n console.warn(` npx ${bootstrapPlan.browserInstallArgs.join(' ')}`);\n }\n }\n\n console.log(`\\n✅ Project ${projectName} created successfully!`);\n console.log(`\\nTo get started:\\n`);\n console.log(` cd ${projectName}`);\n console.log(` npx playwright test`);\n console.log(`\\nHappy testing! 🧪`);\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport fg from 'fast-glob';\nimport { readFileSync, mkdirSync, writeFileSync, statSync } from 'node:fs';\nimport { join, basename, resolve } from 'node:path';\n\ntype NormalizedCase = {\n id?: string;\n title: string;\n tags?: string[];\n steps: string[];\n step_hints?: Array<{ selector?: string }>;\n expected: string[];\n assertion_hints?: Array<{ playwright?: string }>;\n needs_review: boolean;\n review_reasons: string[];\n source: string;\n url?: string;\n};\n\n/** Grab @tags from the title line */\nfunction parseTags(title: string): { clean: string; tags: string[] } {\n const tags = Array.from(title.matchAll(/@([\\w-]+)/g)).map((m) => m[1]);\n const clean = title.replace(/@[\\w-]+/g, '').trim();\n return { clean, tags };\n}\n\n/** Try to extract an ID prefix like AUTH-001 from the title */\nfunction parseId(title: string): string | undefined {\n const m = title.match(/\\b([A-Z]+-\\d+)\\b/);\n return m?.[1];\n}\n\nfunction stripIdPrefixFromTitle(title: string, id?: string): string {\n if (!id) return title.trim();\n return title.replace(new RegExp(`^${id}\\\\s*[—\\\\-–:]\\\\s*`), '').trim();\n}\n\n/** Split a markdown file into case blocks by top-level \"# \" headings */\nfunction splitCasesByHeading(fileText: string): Array<{ titleLine: string; body: string }> {\n const lines = fileText.split(/\\r?\\n/);\n const blocks: Array<{ titleLine: string; body: string }> = [];\n let currentTitle: string | null = null;\n let buf: string[] = [];\n\n const flush = () => {\n if (currentTitle !== null) {\n blocks.push({ titleLine: currentTitle, body: buf.join('\\n') });\n }\n buf = [];\n };\n\n for (const line of lines) {\n const h1 = line.match(/^\\s*#\\s+(.+)$/); // \"# Title\"\n if (h1) {\n if (currentTitle !== null) flush();\n currentTitle = h1[1].trim();\n } else {\n buf.push(line);\n }\n }\n if (currentTitle !== null) flush();\n\n // If no H1 at all, treat whole file as one case (first non-empty line is title).\n if (blocks.length === 0) {\n const first = lines.find((l) => l.trim());\n const title = first?.replace(/^#\\s*/, '').trim() || 'Untitled';\n return [{ titleLine: title, body: lines.join('\\n') }];\n }\n return blocks;\n}\n\n/** From a case body, extract Steps and Expected sections */\nfunction extractSections(body: string): {\n steps: string[];\n stepHints: Array<{ selector?: string }>;\n expected: string[];\n assertionHints: Array<{ playwright?: string }>;\n} {\n // Find sections by H2 headings\n // Supports: \"## Steps\", \"## Expected\", \"## Expected Results\"\n const sectionRegex = /^\\s*##\\s*(.+?)\\s*$/gim;\n const sections: Record<string, string> = {};\n let match: RegExpExecArray | null;\n const indices: Array<{ name: string; index: number }> = [];\n\n while ((match = sectionRegex.exec(body))) {\n indices.push({ name: match[1].toLowerCase(), index: match.index });\n }\n\n // Add end sentinel\n indices.push({ name: '__END__', index: body.length });\n\n for (let i = 0; i < indices.length - 1; i++) {\n const name = indices[i].name;\n const slice = body.slice(indices[i].index, indices[i + 1].index);\n sections[name] = slice;\n }\n\n const stepsBlock =\n sections['steps'] ??\n ''; // if absent, we’ll infer from bullets later\n\n const expectedBlock =\n sections['expected'] ??\n sections['expected results'] ??\n sections['then'] ??\n '';\n\n const bullet = /^\\s*(?:\\d+\\.|[-*])\\s+(.+)$/gm;\n\n const parsedSteps = Array.from(stepsBlock.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'selector'));\n const steps = parsedSteps.map((entry) => entry.text);\n const stepHints = parsedSteps.map((entry) => ({ selector: entry.hint }));\n\n // Fallback: if no dedicated steps section, collect bullets until a new H2\n if (steps.length === 0) {\n const alt = Array.from(body.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'selector'));\n // Heuristic: take the first bullet run in the body\n steps.push(...alt.map((entry) => entry.text));\n stepHints.push(...alt.map((entry) => ({ selector: entry.hint })));\n }\n\n const parsedExpected = Array.from(expectedBlock.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'playwright'));\n const expectedLines = parsedExpected.map((entry) => entry.text);\n const assertionHints = parsedExpected.map((entry) => ({ playwright: entry.hint }));\n\n // Fallback: lines that start with Expected/Then/Verify/Assert in the whole body\n if (expectedLines.length === 0) {\n const exp = Array.from(\n body.matchAll(/^\\s*(?:Expected|Then|Verify|Assert)[^\\n]*:?[\\s-]*(.+)$/gim)\n ).map((m) => parseHintedLine(m[1].trim(), 'playwright'));\n expectedLines.push(...exp.map((entry) => entry.text));\n assertionHints.push(...exp.map((entry) => ({ playwright: entry.hint })));\n }\n\n return { steps, stepHints, expected: expectedLines, assertionHints };\n}\n\nfunction extractUrlMetadata(body: string): string | undefined {\n const match = body.match(/<!--\\s*ct:url\\s+(https?:\\/\\/[^\\s>]+)\\s*-->/i);\n return match?.[1];\n}\n\nfunction stripCtMetadata(body: string): string {\n return body.replace(/^\\s*<!--\\s*ct:url\\s+https?:\\/\\/[^\\s>]+\\s*-->\\s*\\n?/im, '');\n}\n\nfunction parseHintedLine(\n value: string,\n hintType: 'selector' | 'playwright',\n): { text: string; hint?: string } {\n const match = value.match(new RegExp(`^(.*?)\\\\s*<!--\\\\s*${hintType}:\\\\s*([\\\\s\\\\S]*?)\\\\s*-->\\\\s*$`, 'i'));\n if (!match) return { text: value.trim() };\n return {\n text: match[1].trim(),\n hint: match[2].trim() || undefined,\n };\n}\n\nfunction extractUrlFromSteps(steps: string[]): string | undefined {\n for (const step of steps) {\n const match = step.match(/https?:\\/\\/[^\\s'\"]+/i);\n if (match) return match[0];\n }\n return undefined;\n}\n\n/** Build one normalized case from a title line + body */\nfunction normalizeOne(titleLine: string, body: string, source: string): NormalizedCase {\n const { clean, tags } = parseTags(titleLine);\n const id = parseId(clean);\n const metadataUrl = extractUrlMetadata(body);\n const cleanBody = stripCtMetadata(body);\n const { steps, stepHints, expected, assertionHints } = extractSections(cleanBody);\n const reviewReasons: string[] = [];\n\n if (steps.length === 0) reviewReasons.push('No steps section or bullets were parsed');\n if (expected.length === 0) reviewReasons.push('No expected results section or assertions were parsed');\n\n return {\n id,\n title: stripIdPrefixFromTitle(clean, id),\n tags: tags.length ? tags : undefined,\n steps,\n step_hints: stepHints.some(hint => hint.selector) ? stepHints : undefined,\n expected,\n assertion_hints: assertionHints.some(hint => hint.playwright) ? assertionHints : undefined,\n needs_review: reviewReasons.length > 0,\n review_reasons: reviewReasons,\n source,\n url: metadataUrl ?? extractUrlFromSteps(steps),\n };\n}\n\n/** ===== Commander command ===== */\nexport function normalizeCmd() {\n const cmd = new Command('normalize')\n .argument('<path>', 'Input directory or file pattern containing test cases (Markdown, Text, CSV)')\n .description('Convert human-readable test cases into machine-readable JSON format')\n .addHelpText('after', `\nExamples:\n $ ct normalize ./cases\n $ ct normalize \"cases/**/*.md\"\n $ ct normalize ./cases --and-gen --lang ts (Normalize and generate tests in one go)\n`)\n .option('--report', 'Generate a summary report of the normalization process', true)\n .option('--and-gen', 'Automatically run test generation after normalization', false)\n .option('--lang <lang>', 'Target language for generation (ts|js) when using --and-gen', 'ts')\n .action(async (inputPath: string, opts: { report?: boolean; andGen?: boolean; lang?: string }) => {\n // Accept directory OR glob\n let patterns: string[] = [];\n try {\n const abs = resolve(inputPath);\n if (statSync(abs).isDirectory()) {\n const base = inputPath.replace(/\\/$/, '');\n patterns = [`${base}/**/*.{md,markdown,txt,feature,csv,json}`];\n } else {\n patterns = [inputPath];\n }\n } catch {\n patterns = [inputPath];\n }\n\n const files = await fg(patterns, { dot: false, onlyFiles: true });\n if (files.length === 0) {\n console.error(`No files found for: ${inputPath}`);\n process.exit(2);\n }\n\n const outDir = '.cementic/normalized';\n mkdirSync(outDir, { recursive: true });\n\n const index = {\n summary: { total: 0, parsed: 0, withWarnings: 0 },\n cases: [] as Array<{ file: string; normalized: string; status: string }>\n };\n\n for (const f of files) {\n const content = readFileSync(f, 'utf8');\n\n // Split into multiple cases by \"# \"\n const blocks = splitCasesByHeading(content);\n for (const block of blocks) {\n const norm = normalizeOne(block.titleLine, block.body, f);\n\n // filename: <stem>.<ID or sanitized-title>.json\n const stem = basename(f).replace(/\\.[^/.]+$/, '');\n const suffix = (norm.id || norm.title).replace(/[^\\w-]+/g, '-');\n const outFile = join(outDir, `${stem}.${suffix}.json`);\n\n writeFileSync(outFile, JSON.stringify(norm, null, 2));\n\n index.summary.total++;\n index.summary.parsed++;\n if (norm.needs_review) index.summary.withWarnings++;\n index.cases.push({ file: f, normalized: outFile, status: norm.needs_review ? 'warning' : 'ok' });\n }\n }\n\n writeFileSync(join(outDir, '_index.json'), JSON.stringify(index, null, 2));\n\n if (opts.report !== false) {\n const lines = [\n '# Normalize Report',\n '',\n `Total cases: ${index.summary.total} | Parsed: ${index.summary.parsed} | With warnings: ${index.summary.withWarnings}`,\n '',\n '| Source File | Normalized JSON | Status |',\n '|-------------|-----------------|--------|',\n ...index.cases.map(c => `| ${c.file} | ${c.normalized} | ${c.status} |`)\n ];\n mkdirSync('.cementic/reports', { recursive: true });\n writeFileSync('.cementic/reports/normalize-report.md', lines.join('\\n'));\n }\n\n console.log(`✅ Normalized ${index.summary.parsed} case(s). Output → .cementic/normalized/`);\n\n if (opts.andGen) {\n const { gen } = await import('./gen.js');\n await gen({ lang: opts.lang || 'ts', out: 'tests/generated' });\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nexport function testCmd() {\n const cmd = new Command('test')\n .description('Run Playwright tests via \"npx playwright test\"')\n .allowUnknownOption(true)\n .allowExcessArguments(true)\n .argument('[...pwArgs]', 'Arguments to pass through to Playwright')\n .action((pwArgs: string[] = []) => {\n const child = spawn(\n 'npx',\n ['playwright', 'test', ...pwArgs],\n {\n stdio: 'inherit',\n shell: process.platform === 'win32', // needed for Windows\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { inferPrefix } from '../core/prefix.js';\nimport { generateTcMarkdownWithAi } from '../core/llm.js';\nimport { analyseElements } from '../core/analyse.js';\nimport { captureElements, formatCaptureFailure, toPageSummary } from '../core/capture.js';\nimport {\n printCaptureReport,\n saveCaptureJson,\n saveCasesMarkdown,\n saveSpecPreview,\n} from '../core/report.js';\n\nfunction slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'tc'\n );\n}\n\nfunction injectUrlMetadata(markdown: string, url?: string): string {\n if (!url || /<!--\\s*ct:url\\s+/i.test(markdown)) return markdown;\n\n const lines = markdown.split('\\n');\n const output: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n output.push(lines[i]);\n if (/^\\s*#\\s+/.test(lines[i])) {\n output.push(`<!-- ct:url ${url} -->`);\n }\n }\n\n return output.join('\\n');\n}\n\nfunction buildManualCasesMarkdown(opts: {\n prefix: string;\n feature: string;\n url?: string;\n numCases: number;\n startIndex?: number;\n}): string {\n const { prefix, feature, url, numCases } = opts;\n const startIndex = opts.startIndex ?? 1;\n const lines: string[] = [];\n\n for (let i = 0; i < numCases; i++) {\n const idx = startIndex + i;\n const id = `${prefix}-${String(idx).padStart(3, '0')}`;\n\n lines.push(`# ${id} — ${feature} - scenario ${idx} @regression @ui`);\n if (url) lines.push(`<!-- ct:url ${url} -->`);\n lines.push(`## Steps`);\n lines.push(`1. Navigate to ${url ?? '<PAGE_URL>'}`);\n lines.push(`2. Perform the main user action for this scenario`);\n lines.push(`3. Observe the result`);\n lines.push('');\n lines.push(`## Expected Results`);\n lines.push(`- The page responds correctly for this scenario`);\n lines.push(`- UI reflects the expected change`);\n lines.push('');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nasync function promptBasicQuestions(opts: {\n url?: string;\n feature?: string;\n appDescription?: string;\n numCases?: number;\n}) {\n // Non-interactive mode: all required options were passed as flags\n if (opts.feature) {\n const n = Math.min(Math.max(opts.numCases ?? 3, 1), 10);\n return {\n feature: opts.feature,\n appDescription: opts.appDescription ?? '',\n numCases: n,\n url: opts.url,\n };\n }\n\n // Interactive mode\n const rl = createInterface({ input, output });\n\n const feature = (await rl.question('🧩 Feature or page to test: ')).trim();\n const appDescription = (await rl.question('📝 Short app description (optional): ')).trim();\n const numCasesRaw = (await rl.question('🔢 How many test cases? (1–10) [3]: ')).trim();\n\n rl.close();\n\n let numCases = parseInt(numCasesRaw, 10);\n if (isNaN(numCases) || numCases < 1) numCases = 3;\n if (numCases > 10) numCases = 10;\n\n return { feature, appDescription, numCases, url: opts.url };\n}\n\nasync function runTcInteractive(params: {\n url?: string;\n explicitPrefix?: string;\n feature?: string;\n appDescription?: string;\n numCases?: number;\n useAi: boolean;\n headed?: boolean;\n captureOnly?: boolean;\n}) {\n const { feature, appDescription, numCases, url } = await promptBasicQuestions({\n url: params.url,\n feature: params.feature,\n appDescription: params.appDescription,\n numCases: params.numCases,\n });\n\n const prefix = inferPrefix({\n featureText: feature,\n url,\n explicitPrefix: params.explicitPrefix,\n });\n\n mkdirSync('cases', { recursive: true });\n const fileName = `${prefix.toLowerCase()}-${slugify(feature)}.md`;\n const fullPath = join('cases', fileName);\n\n let markdown: string;\n let pageSummary = undefined;\n\n if (params.useAi) {\n if (url) {\n try {\n console.log(`🔍 Capturing page: ${url}`);\n const elementMap = await captureElements(url, {\n headless: !(params.headed ?? false),\n verbose: true,\n });\n printCaptureReport(elementMap);\n\n const jsonPath = saveCaptureJson(elementMap);\n console.log(`📄 Saved capture JSON → ${jsonPath}`);\n pageSummary = toPageSummary(elementMap);\n\n if (params.captureOnly) {\n console.log('Capture-only mode requested. No test cases were generated.');\n return;\n }\n\n const analysis = await analyseElements(elementMap, { verbose: true, feature });\n printCaptureReport(elementMap, analysis);\n\n const previewPath = saveSpecPreview(analysis);\n if (previewPath) {\n console.log(`🧪 Saved preview spec → ${previewPath}`);\n }\n\n const captureFileName = `${prefix.toLowerCase()}-${slugify(feature)}.md`;\n const generatedPath = saveCasesMarkdown(analysis, 'cases', captureFileName);\n console.log(`✅ Capture-based AI generated test cases → ${generatedPath}`);\n console.log('\\nNext steps:');\n console.log(` ct normalize ${generatedPath} --and-gen --lang ts`);\n console.log(' ct test');\n return;\n } catch (e: any) {\n printWarningBlock(formatCaptureFailure(e));\n console.warn('⚠️ Falling back to AI text generation without capture context.');\n if (params.captureOnly) {\n return;\n }\n }\n }\n\n try {\n markdown = await generateTcMarkdownWithAi({\n appDescription: appDescription || undefined,\n feature,\n url,\n pageSummary,\n prefix,\n startIndex: 1,\n numCases,\n });\n markdown = injectUrlMetadata(markdown, url);\n console.log('✅ AI generated test cases.');\n } catch (err: any) {\n printWarningBlock([\n 'AI generation failed.',\n err?.message ?? String(err),\n ]);\n markdown = buildManualCasesMarkdown({ prefix, feature, url, numCases, startIndex: 1 });\n console.log('📝 Generated manual test case templates instead.');\n }\n } else {\n markdown = buildManualCasesMarkdown({ prefix, feature, url, numCases, startIndex: 1 });\n console.log('📝 Generated manual test case templates (pass --ai to use AI).');\n }\n\n writeFileSync(fullPath, markdown);\n\n console.log(`\\n✍️ Wrote ${numCases} case(s) → ${fullPath}`);\n console.log('\\nNext steps:');\n console.log(' ct normalize ./cases --and-gen --lang ts');\n console.log(' ct test');\n}\n\nfunction printWarningBlock(lines: string[]): void {\n if (lines.length === 0) return;\n\n console.warn(`⚠️ ${lines[0]}`);\n for (const line of lines.slice(1)) {\n console.warn(line);\n }\n}\n\n// ─── Shared options factory ───────────────────────────────────────────────────\n\nfunction addSharedOptions(cmd: Command): Command {\n return cmd\n .option('--ai', 'Use AI to generate test cases (requires API key)')\n .option('--prefix <prefix>', 'Explicit ID prefix, e.g. AUTH, DASH, CART')\n .option('--feature <name>', 'Feature name — skips interactive prompt')\n .option('--desc <text>', 'App description — skips interactive prompt')\n .option('--count <n>', 'Number of cases (1–10)', parseInt);\n}\n\nfunction resolveCommanderOpts<T extends Record<string, unknown>>(opts: T | Command): T {\n if (typeof (opts as Command).optsWithGlobals === 'function') {\n return (opts as Command).optsWithGlobals<T>();\n }\n if (typeof (opts as Command).opts === 'function') {\n return (opts as Command).opts<T>();\n }\n return opts as T;\n}\n\n// ─── Command definition ───────────────────────────────────────────────────────\n\nexport function tcCmd() {\n const root = new Command('tc')\n .description('Create CementicTest case files (Markdown) under ./cases')\n .addHelpText('after', `\nExamples:\n $ ct tc --feature \"Login form\" --ai\n $ ct tc --feature \"Checkout\" --count 5 --prefix CHK\n $ ct tc url https://example.com/login --ai --feature \"Auth\"\n`);\n\n addSharedOptions(root).action(\n async (opts: { ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number } | Command) => {\n const resolvedOpts = resolveCommanderOpts<{ ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number }>(opts);\n await runTcInteractive({\n url: undefined,\n explicitPrefix: resolvedOpts.prefix,\n feature: resolvedOpts.feature,\n appDescription: resolvedOpts.desc,\n numCases: resolvedOpts.count,\n useAi: resolvedOpts.ai ?? false,\n });\n }\n );\n\n addSharedOptions(\n root\n .command('url')\n .argument('<url>', 'Page URL to use as live capture and AI context')\n .description('Generate test cases with capture-aware context from a specific live page')\n .option('--headed', 'Show the browser while capturing the page')\n .option('--capture-only', 'Run live page capture and save artifacts without generating cases')\n ).action(\n async (\n url: string,\n opts: { ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number; headed?: boolean; captureOnly?: boolean } | Command,\n command?: Command,\n ) => {\n const resolvedOpts = resolveCommanderOpts<{ ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number; headed?: boolean; captureOnly?: boolean }>(command ?? opts);\n await runTcInteractive({\n url,\n explicitPrefix: resolvedOpts.prefix,\n feature: resolvedOpts.feature,\n appDescription: resolvedOpts.desc,\n numCases: resolvedOpts.count,\n useAi: resolvedOpts.ai ?? false,\n headed: resolvedOpts.headed ?? false,\n captureOnly: resolvedOpts.captureOnly ?? false,\n });\n }\n );\n\n return root;\n}\n","// src/core/prefix.ts\n\nconst PREFIX_MAP: Array<{ keywords: string[]; prefix: string }> = [\n { keywords: ['login', 'sign in', 'signin', 'auth', 'authentication'], prefix: 'AUTH' },\n { keywords: ['dashboard', 'home'], prefix: 'DASH' },\n { keywords: ['profile', 'account'], prefix: 'PROF' },\n { keywords: ['cart', 'basket'], prefix: 'CART' },\n { keywords: ['checkout', 'payment', 'pay'], prefix: 'CHK' },\n { keywords: ['order', 'orders'], prefix: 'ORD' },\n { keywords: ['settings', 'preferences', 'config'], prefix: 'SET' },\n];\n\nfunction normalizeText(text: string): string {\n return text.toLowerCase().trim();\n}\n\nfunction deriveFromFreeText(text: string): string | undefined {\n const norm = normalizeText(text);\n for (const entry of PREFIX_MAP) {\n if (entry.keywords.some(k => norm.includes(k))) {\n return entry.prefix;\n }\n }\n // fallback: first word, first 4 alphanumerics\n const firstWord = norm.split(/\\s+/).find(w => /[a-z0-9]/.test(w));\n if (!firstWord) return undefined;\n return firstWord.replace(/[^a-z0-9]/gi, '').slice(0, 4).toUpperCase() || undefined;\n}\n\nfunction deriveFromUrl(url: string): string | undefined {\n try {\n const u = new URL(url);\n const segments = u.pathname.split('/').filter(Boolean);\n const last = segments[segments.length - 1] || '';\n if (!last) return undefined;\n return deriveFromFreeText(last);\n } catch {\n return undefined;\n }\n}\n\nexport function inferPrefix(params: {\n featureText?: string;\n url?: string;\n explicitPrefix?: string;\n}): string {\n // 1) explicit flag wins\n if (params.explicitPrefix) {\n return params.explicitPrefix.trim().toUpperCase();\n }\n\n // 2) feature text\n if (params.featureText) {\n const fromFeature = deriveFromFreeText(params.featureText);\n if (fromFeature) return fromFeature;\n }\n\n // 3) url\n if (params.url) {\n const fromUrl = deriveFromUrl(params.url);\n if (fromUrl) return fromUrl;\n }\n\n // 4) last-resort default\n return 'TC';\n}","export type ProviderName = 'deepseek' | 'anthropic' | 'gemini' | 'qwen' | 'kimi' | 'openai';\nexport type ProviderTransport = 'anthropic' | 'openai-compatible';\n\nexport type ProviderConfig = {\n provider: ProviderName;\n displayName: string;\n apiKey: string;\n model: string;\n baseUrl?: string;\n transport: ProviderTransport;\n};\n\nconst PROVIDER_ORDER: ProviderName[] = ['deepseek', 'anthropic', 'gemini', 'qwen', 'kimi', 'openai'];\n\nexport function resolveLlmProvider(env: NodeJS.ProcessEnv = process.env): ProviderConfig {\n const explicitProvider = (env.CT_LLM_PROVIDER ?? '').trim().toLowerCase();\n const providers = buildProviderConfigs(env);\n\n if (explicitProvider) {\n if (!(explicitProvider in providers)) {\n throw new Error(\n `Unsupported CT_LLM_PROVIDER=\"${explicitProvider}\". Use deepseek, anthropic, gemini, qwen, kimi, or openai.`\n );\n }\n\n const selected = providers[explicitProvider as ProviderName];\n if (!selected.apiKey) {\n throw new Error(\n `CT_LLM_PROVIDER=${explicitProvider} is set but the matching API key is missing.\\n${buildProviderSetupHelp()}`\n );\n }\n\n return selected;\n }\n\n for (const providerName of PROVIDER_ORDER) {\n if (providers[providerName].apiKey) return providers[providerName];\n }\n\n throw new Error(`No LLM API key found.\\n${buildProviderSetupHelp()}`);\n}\n\nexport function buildProviderSetupHelp(): string {\n return [\n ' OpenAI: export OPENAI_API_KEY=your-key',\n ' Anthropic: export ANTHROPIC_API_KEY=your-key',\n ' Gemini: export GEMINI_API_KEY=your-key',\n ' DeepSeek: export DEEPSEEK_API_KEY=your-key',\n ' Qwen: export QWEN_API_KEY=your-key',\n ' Kimi: export KIMI_API_KEY=your-key',\n ' Generic: export CT_LLM_API_KEY=your-key',\n ' export CT_LLM_BASE_URL=https://your-openai-compatible-endpoint/v1',\n ].join('\\n');\n}\n\nfunction buildProviderConfigs(env: NodeJS.ProcessEnv): Record<ProviderName, ProviderConfig> {\n return {\n deepseek: {\n provider: 'deepseek',\n displayName: 'DeepSeek',\n apiKey: env.DEEPSEEK_API_KEY ?? env.CT_DEEPSEEK_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.DEEPSEEK_MODEL ?? 'deepseek-chat',\n baseUrl: env.DEEPSEEK_BASE_URL ?? 'https://api.deepseek.com/v1',\n transport: 'openai-compatible',\n },\n anthropic: {\n provider: 'anthropic',\n displayName: 'Claude',\n apiKey: env.ANTHROPIC_API_KEY ?? env.CT_ANTHROPIC_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.ANTHROPIC_MODEL ?? 'claude-sonnet-4-5',\n baseUrl: 'https://api.anthropic.com',\n transport: 'anthropic',\n },\n gemini: {\n provider: 'gemini',\n displayName: 'Gemini',\n apiKey: env.GEMINI_API_KEY ?? env.GOOGLE_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.GEMINI_MODEL ?? 'gemini-2.5-flash',\n baseUrl: env.GEMINI_BASE_URL ?? 'https://generativelanguage.googleapis.com/v1beta/openai',\n transport: 'openai-compatible',\n },\n qwen: {\n provider: 'qwen',\n displayName: 'Qwen',\n apiKey: env.QWEN_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.QWEN_MODEL ?? 'qwen-plus',\n baseUrl: env.QWEN_BASE_URL ?? 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',\n transport: 'openai-compatible',\n },\n kimi: {\n provider: 'kimi',\n displayName: 'Kimi',\n apiKey: env.KIMI_API_KEY ?? env.MOONSHOT_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.KIMI_MODEL ?? 'moonshot-v1-8k',\n baseUrl: env.KIMI_BASE_URL ?? 'https://api.moonshot.ai/v1',\n transport: 'openai-compatible',\n },\n openai: {\n provider: 'openai',\n displayName: env.CT_LLM_API_KEY && env.CT_LLM_BASE_URL ? 'OpenAI-compatible' : 'OpenAI',\n apiKey: env.CT_LLM_API_KEY ?? env.OPENAI_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.OPENAI_MODEL ?? 'gpt-4o-mini',\n baseUrl: env.CT_LLM_BASE_URL ?? 'https://api.openai.com/v1',\n transport: 'openai-compatible',\n },\n };\n}\n","import type { PageSummary } from './capture.js';\nimport { resolveLlmProvider } from './llm-provider.js';\n\nexport type TcAiContext = {\n appDescription?: string;\n feature: string;\n url?: string;\n pageSummary?: PageSummary;\n prefix: string;\n startIndex: number;\n numCases: number;\n};\n\nfunction getAvailableCtVarKeys(): string[] {\n return Object.keys(process.env)\n .filter((key) => /^CT_VAR_[A-Z0-9_]+$/.test(key))\n .sort();\n}\n\nconst RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE = `\nRULE 10 - PLAYWRIGHT KNOWLEDGE BASE\n(sourced from playwright.dev official documentation)\n\nYou are an expert in Playwright TypeScript. Apply this knowledge\nwhen generating test code. Always use web-first assertions that\nauto-wait. Never use manual waits or non-awaited assertions.\n\nLOCATOR PRIORITY (use in this order)\n1. page.getByRole('button', { name: 'Submit' }) <- best\n2. page.getByLabel('Email address')\n3. page.getByPlaceholder('Enter email')\n4. page.getByText('Welcome')\n5. page.getByAltText('logo')\n6. page.getByTitle('Close')\n7. page.getByTestId('submit-btn')\n8. page.locator('#id') or page.locator('.class') <- last resort\n\nChain locators to narrow scope:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' }).click()\n\nLOCATOR ASSERTIONS (always await, always web-first)\nVisibility:\n await expect(locator).toBeVisible()\n await expect(locator).toBeHidden()\n await expect(locator).toBeInViewport()\n\nState:\n await expect(locator).toBeEnabled()\n await expect(locator).toBeDisabled()\n await expect(locator).toBeChecked()\n await expect(locator).not.toBeChecked()\n await expect(locator).toBeFocused()\n await expect(locator).toBeEditable()\n await expect(locator).toBeEmpty()\n await expect(locator).toBeAttached()\n\nText content:\n await expect(locator).toHaveText('exact text')\n await expect(locator).toHaveText(/regex/)\n await expect(locator).toContainText('partial')\n await expect(locator).toContainText(['item1', 'item2'])\n\nValue and attributes:\n await expect(locator).toHaveValue('input value')\n await expect(locator).toHaveValues(['opt1', 'opt2']) // multi-select\n await expect(locator).toHaveAttribute('href', /pattern/)\n await expect(locator).toHaveClass(/active/)\n await expect(locator).toHaveCSS('color', 'rgb(0,0,0)')\n await expect(locator).toHaveId('submit-btn')\n await expect(locator).toHaveAccessibleName('Submit form')\n await expect(locator).toHaveAccessibleDescription('...')\n\nCounting (PREFER toHaveCount over .count() to avoid flakiness):\n await expect(locator).toHaveCount(3)\n await expect(locator).toHaveCount(0) // none exist\n // Only use .count() when you need the actual number:\n const n = await page.getByRole('button').count();\n console.log(\\`Found \\${n} buttons\\`);\n\nPAGE ASSERTIONS\n await expect(page).toHaveTitle(/Playwright/)\n await expect(page).toHaveTitle('Exact Title')\n await expect(page).toHaveURL('https://example.com/dashboard')\n await expect(page).toHaveURL(/\\\\/dashboard/)\n\nACTIONS (Playwright auto-waits before each action)\nNavigation:\n await page.goto('https://example.com')\n await page.goBack()\n await page.goForward()\n await page.reload()\n\nClicking:\n await locator.click()\n await locator.dblclick()\n await locator.click({ button: 'right' })\n await locator.click({ modifiers: ['Shift'] })\n\nForms:\n await locator.fill('text') // clears then types\n await locator.clear()\n await locator.pressSequentially('slow typing', { delay: 50 })\n await locator.selectOption('value')\n await locator.selectOption({ label: 'Blue' })\n await locator.check()\n await locator.uncheck()\n await locator.setInputFiles('path/to/file.pdf')\n\nHover and focus:\n await locator.hover()\n await locator.focus()\n await locator.blur()\n\nKeyboard:\n await page.keyboard.press('Enter')\n await page.keyboard.press('Tab')\n await page.keyboard.press('Escape')\n await page.keyboard.press('Control+A')\n\nScroll:\n await locator.scrollIntoViewIfNeeded()\n await page.mouse.wheel(0, 500)\n\nBEST PRACTICES (from playwright.dev/docs/best-practices)\nDO use web-first assertions:\n await expect(page.getByText('welcome')).toBeVisible()\n\nNEVER use synchronous assertions:\n expect(await page.getByText('welcome').isVisible()).toBe(true)\n\nDO chain locators:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' })\n\nNEVER use fragile CSS/XPath selectors:\n page.locator('button.buttonIcon.episode-actions-later')\n\nDO use role-based locators:\n page.getByRole('button', { name: 'submit' })\n\nINTENT -> PATTERN MAPPING\n\nCOUNTING:\n \"how many X\" / \"count X\" / \"number of X\" / \"return the count\"\n -> const n = await page.getByRole('X').count();\n console.log(\\`Found \\${n} X elements\\`);\n expect(n).toBeGreaterThan(0);\n\n \"there are N X\" / \"exactly N X\"\n -> await expect(page.getByRole('X')).toHaveCount(N);\n\n CRITICAL: Never use getByText(\"how many X\") - count intent\n means call .count() or toHaveCount(), not search for text.\n\nPRESENCE:\n \"X is present/visible/shown/exists\"\n -> await expect(locator).toBeVisible()\n\n \"X is hidden/not present/gone\"\n -> await expect(locator).toBeHidden()\n\nTEXT:\n \"text says X\" / \"shows X\" / \"message is X\"\n -> await expect(locator).toHaveText('X')\n\n \"contains X\" / \"includes X\"\n -> await expect(locator).toContainText('X')\n\n \"page title is X\"\n -> await expect(page).toHaveTitle(/X/i)\n\n \"heading says X\"\n -> await expect(page.getByRole('heading')).toContainText('X')\n\n \"error says X\"\n -> await expect(page.getByRole('alert')).toContainText('X')\n\nSTATE:\n \"X is enabled/disabled\"\n -> await expect(locator).toBeEnabled() / toBeDisabled()\n\n \"X is checked/unchecked\"\n -> await expect(locator).toBeChecked() / not.toBeChecked()\n\n \"X has value Y\"\n -> await expect(locator).toHaveValue('Y')\n\n \"X is active / has class Y\"\n -> await expect(locator).toHaveClass(/Y/)\n\nNAVIGATION:\n \"redirects to X\" / \"goes to X\" / \"URL contains X\"\n -> await expect(page).toHaveURL(/X/)\n\n \"stays on same page\"\n -> await expect(page).toHaveURL(/currentPath/)\n\n \"opens new tab\"\n -> const [newPage] = await Promise.all([\n context.waitForEvent('page'),\n locator.click()\n ]);\n\nFORMS:\n \"form submits successfully\"\n -> fill fields + click submit + assert URL change or success message\n\n \"validation error shown\"\n -> submit empty + await expect(page.getByRole('alert')).toBeVisible()\n\n \"required field X\"\n -> submit without X + assert error message for X visible\n\nAUTH:\n \"login with valid credentials\"\n -> fill(CT_VAR_USERNAME) + fill(CT_VAR_PASSWORD) + click login\n + await expect(page).toHaveURL(/dashboard|home|app/)\n\n \"login fails / invalid credentials\"\n -> fill bad values + click login\n + await expect(page.getByRole('alert')).toBeVisible()\n\n \"logout works\"\n -> click logout + await expect(page).toHaveURL(/login|home/)\n\nTHEME / VISUAL:\n \"dark mode / theme toggle\"\n -> await locator.click()\n + await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')\n // OR: await expect(page.locator('body')).toHaveClass(/dark/)\n\nTIMING:\n \"X loads / X appears\"\n -> await expect(locator).toBeVisible({ timeout: 10000 })\n\n \"spinner disappears / loader gone\"\n -> await expect(spinner).toBeHidden({ timeout: 10000 })\n\n \"modal closes\"\n -> await expect(modal).toBeHidden()\n\nACCESSIBILITY:\n \"has alt text\"\n -> await expect(page.locator('img')).toHaveAttribute('alt', /.+/)\n\n \"keyboard navigable\"\n -> await page.keyboard.press('Tab')\n + await expect(firstFocusable).toBeFocused()\n\nCRITICAL RULES\n1. NEVER use intent words as locator text.\n \"count buttons\" != getByText(\"count buttons\")\n \"verify heading\" != getByText(\"verify heading\")\n\n2. ALWAYS use web-first assertions (await expect).\n NEVER use: expect(await locator.isVisible()).toBe(true)\n\n3. For counting, prefer toHaveCount() over .count() unless\n you need the actual number for logging.\n\n4. Auto-waiting: Playwright automatically waits for elements\n to be actionable before click/fill/etc. Do not add\n manual waitForTimeout() unless testing timing specifically.\n\n5. Use not. prefix for negative assertions:\n await expect(locator).not.toBeVisible()\n await expect(locator).not.toBeChecked()\n`.trim();\n\nconst ADVANCED_DOC_MAP: Record<string, string> = {\n upload: 'https://playwright.dev/docs/input',\n 'file upload': 'https://playwright.dev/docs/input',\n intercept: 'https://playwright.dev/docs/mock',\n mock: 'https://playwright.dev/docs/mock',\n 'api mock': 'https://playwright.dev/docs/mock',\n accessibility: 'https://playwright.dev/docs/accessibility-testing',\n 'screen reader': 'https://playwright.dev/docs/accessibility-testing',\n visual: 'https://playwright.dev/docs/screenshots',\n screenshot: 'https://playwright.dev/docs/screenshots',\n mobile: 'https://playwright.dev/docs/emulation',\n responsive: 'https://playwright.dev/docs/emulation',\n viewport: 'https://playwright.dev/docs/emulation',\n network: 'https://playwright.dev/docs/network',\n 'api call': 'https://playwright.dev/docs/network',\n iframe: 'https://playwright.dev/docs/frames',\n frame: 'https://playwright.dev/docs/frames',\n auth: 'https://playwright.dev/docs/auth',\n 'sign in': 'https://playwright.dev/docs/auth',\n 'stay logged': 'https://playwright.dev/docs/auth',\n cookie: 'https://playwright.dev/docs/auth',\n storage: 'https://playwright.dev/docs/auth',\n download: 'https://playwright.dev/docs/downloads',\n pdf: 'https://playwright.dev/docs/downloads',\n dialog: 'https://playwright.dev/docs/dialogs',\n alert: 'https://playwright.dev/docs/dialogs',\n confirm: 'https://playwright.dev/docs/dialogs',\n 'new tab': 'https://playwright.dev/docs/pages',\n 'new page': 'https://playwright.dev/docs/pages',\n popup: 'https://playwright.dev/docs/pages',\n};\n\nasync function fetchDocContext(intent: string): Promise<string> {\n const intentLower = intent.toLowerCase();\n const matched = new Set<string>();\n\n for (const [keyword, url] of Object.entries(ADVANCED_DOC_MAP)) {\n if (intentLower.includes(keyword)) {\n matched.add(url);\n }\n }\n\n if (matched.size === 0) return '';\n\n const fetched: string[] = [];\n\n for (const url of matched) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const html = await res.text();\n const text = html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s{3,}/g, '\\n\\n')\n .slice(0, 3000);\n\n fetched.push(`\\n// From ${url}:\\n${text}`);\n } catch {\n // Non-fatal - continue without this doc\n }\n }\n\n if (fetched.length === 0) return '';\n\n return `\\n\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\nADDITIONAL PLAYWRIGHT DOCS (fetched for this intent)\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${fetched.join('\\n')}`;\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────────────────\n\nfunction buildSystemMessage(): string {\n return `\nYou are a senior software test architect with 10 years of Playwright experience.\nYou translate user requirements into precise, minimal, executable test scenarios.\n\nRULE 1 - INTENT IS THE REQUIREMENT\nParse the user's feature description into specific testable claims BEFORE examining page context.\nGenerate scenarios for the user's intent, not for every element on the page.\n\nRULE 2 - GENERATE TESTS FOR THE INTENT, NOT THE PAGE INVENTORY\nOnly generate tests for claims extracted from the intent.\nNever generate tests for page elements that were not requested.\nPage context improves selector quality and wording, but it does not define test scope.\n\nRULE 3 - SELECTOR HIERARCHY\nWhen choosing selectors, prefer:\n1. Exact page-context match when available\n2. getByRole() with text from the intent\n3. getByLabel() for form inputs\n4. getByText() with text from the intent\n5. getByPlaceholder() for inputs\n6. locator('#id') only when the id appears stable\n\nTie-breaker when multiple elements match:\n1. Prefer the highest-confidence page-context match\n2. Prefer visible elements over hidden\n3. Prefer interactive elements over static elements\n4. If still ambiguous, use the first match and note it with a short comment in the step text\n\nRULE 4 - TITLE DISAMBIGUATION\n\"verify title\" means the main visible heading on the page.\nUse a heading assertion first.\nDo NOT treat \"title\" as the browser tab title unless the intent explicitly says \"browser title\", \"tab title\", or \"page title\".\n\nRULE 5 - PRESENCE-ONLY INTENTS\nFor presence-only intents such as \"verify X\", \"check X is present\", or \"X is visible\":\n- Only assert visibility\n- Do NOT click the element\n- Do NOT assert redirects, state changes, or side effects\n\nRULE 6 - NEGATIVE CASES\nGenerate negative scenarios only when the intent implies interaction:\n- Form testing: always include an invalid-input scenario\n- Authentication: always include a wrong-credentials scenario\n- Presence checks: no negative case needed\n- Button click: negative case only if the button can be disabled\n\nRULE 7 - SETUP DEPENDENCIES\nIf authentication is required to reach the page:\n- Add setup steps using CT_VAR_USERNAME and CT_VAR_PASSWORD\n- Tag the scenario with @requires-auth\n- Mention the dependency in a short step or assertion note when needed\n\nRULE 8 - TEST DATA\nNever use the literal word 'value' as a placeholder.\nWhen filling a field:\n- If the user context lists a matching CT_VAR_* variable, write it exactly as '` + '${CT_VAR_FIELDNAME}' + `'\n- Otherwise use a field-specific fallback such as 'test-username', 'test-email@example.com', 'test-password', or 'test-search'\n\nRULE 9 - SCOPE DISCIPLINE\nMatch scenario count to intent complexity:\n- 1 to 2 claims: 1 to 2 scenarios maximum\n- 3 to 5 claims: 3 to 5 scenarios maximum\n- Full flow: 4 to 8 scenarios maximum\nNever exceed 8 scenarios.\n\n${RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE}\n\nCOMMON TESTING VOCABULARY\n\"verify/check X is present/visible\" -> toBeVisible()\n\"verify title/heading\" -> heading is visible\n\"button/link is present\" -> button or link is visible\n\"can click X\" -> click then assert visible outcome\n\"form submits\" -> fill + click + assert success or URL\n\"error shows\" -> trigger error + assert error visible\n\"redirects to X\" -> URL contains or equals X\n\"text says X\" -> text equals or contains X\n\"page loads\" -> main heading or key element is visible\n\nOUTPUT FORMAT - EXACT MARKDOWN SCHEMA\nOutput valid markdown in this exact format. No preamble. No explanation. Just the markdown.\n\n# {PREFIX}-001 - {scenario-slug} - {Human readable title} @tag1 @tag2\n\n## Steps\n1. Navigate to {url}\n2. {action verb} {target description}\n\n## Expected Results\n- {specific observable assertion}\n- {specific observable assertion}\n\n---\n\n# {PREFIX}-002 - {scenario-slug} - {Human readable title} @tag1 @tag2\n\n## Steps\n1. Navigate to {url}\n2. {action verb} {target description}\n\n## Expected Results\n- {specific observable assertion}\n\nRules for the markdown schema:\n- id format: PREFIX-NNN using the provided prefix and numbering\n- slug format: kebab-case, max 5 words, derived from the scenario subject\n- title: human readable and aligned to the user's intent\n- tags: include at least one of @smoke @regression @negative @happy-path plus a relevant domain tag such as @auth @ui @navigation @form @checkout\n- steps: numbered, start with Navigate, then actions, written in plain English\n- assertions: bullet points with observable outcomes only\n- never write \"test passes\" or \"works correctly\"\n- do NOT wrap the output in code fences\n`.trim();\n}\n\nfunction buildUserMessage(ctx: TcAiContext): string {\n const lines: string[] = [];\n const availableCtVarKeys = getAvailableCtVarKeys();\n\n lines.push(`App / product description:`);\n lines.push(ctx.appDescription || 'N/A');\n lines.push('');\n\n lines.push(`Primary test intent:`);\n lines.push(ctx.feature);\n lines.push('');\n\n lines.push(`Interpret the feature text above as the source of truth.`);\n lines.push(`Only generate scenarios for claims that are explicitly implied by that intent.`);\n lines.push('');\n\n if (ctx.url) {\n lines.push(`Page URL: ${ctx.url}`);\n lines.push('');\n }\n\n if (ctx.pageSummary) {\n const s = ctx.pageSummary;\n lines.push(`Live page analysis:`);\n\n if (s.title) lines.push(`- Page title: ${s.title}`);\n\n if (s.headings.length) {\n lines.push(`- Headings: ${s.headings.join(' | ')}`);\n }\n\n if (s.inputs.length) {\n const inputDescs = s.inputs.map(i => {\n const parts = [\n i.label && `label=\"${i.label}\"`,\n i.placeholder && `placeholder=\"${i.placeholder}\"`,\n i.name && `name=\"${i.name}\"`,\n i.type && i.type !== 'text' && `type=\"${i.type}\"`,\n i.testId && `data-testid=\"${i.testId}\"`,\n ].filter(Boolean);\n return parts.join(', ');\n });\n lines.push(`- Form inputs: ${inputDescs.join(' | ')}`);\n }\n\n if (s.buttons.length) {\n lines.push(`- Buttons: ${s.buttons.join(' | ')}`);\n }\n\n if (s.links.length) {\n lines.push(`- Links: ${s.links.slice(0, 20).join(' | ')}`);\n }\n\n lines.push('');\n }\n\n if (availableCtVarKeys.length > 0) {\n lines.push('Available CT_VAR_* test variables:');\n for (const envKey of availableCtVarKeys) {\n lines.push(`- ${envKey}`);\n }\n lines.push('');\n lines.push(`Use a listed variable when it clearly matches a form field, written exactly as '` + '${CT_VAR_NAME}' + `'.`);\n lines.push('');\n }\n\n lines.push(`Test ID prefix: ${ctx.prefix}`);\n lines.push(`Start numbering from: ${String(ctx.startIndex).padStart(3, '0')}`);\n lines.push(`Requested number of test cases: ${ctx.numCases}`);\n lines.push('');\n lines.push(`Use the requested count only when it fits the intent complexity. Prefer fewer scenarios when the request is simple.`);\n lines.push(`Output ONLY the test cases. No explanation, no preamble.`);\n\n return lines.join('\\n');\n}\n\n// ─── Anthropic call ───────────────────────────────────────────────────────────\n\nasync function callAnthropic(\n apiKey: string,\n model: string,\n system: string,\n user: string\n): Promise<string> {\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 4096,\n system,\n messages: [{ role: 'user', content: user }],\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Anthropic API error ${response.status}: ${text}`);\n }\n\n const json: any = await response.json();\n const content = json.content?.[0]?.text?.trim() ?? '';\n if (!content) throw new Error('Anthropic response had no content');\n return content;\n}\n\n// ─── OpenAI-compatible call ───────────────────────────────────────────────────\n\nasync function callOpenAiCompatible(\n apiKey: string,\n model: string,\n baseUrl: string,\n displayName: string,\n system: string,\n user: string\n): Promise<string> {\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n temperature: 0.2,\n messages: [\n { role: 'system', content: system },\n { role: 'user', content: user },\n ],\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`${displayName} API error ${response.status}: ${text}`);\n }\n\n const json: any = await response.json();\n const content = json.choices?.[0]?.message?.content?.trim() ?? '';\n if (!content) throw new Error('OpenAI response had no content');\n return content;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport async function generateTcMarkdownWithAi(ctx: TcAiContext): Promise<string> {\n const providerConfig = resolveLlmProvider();\n\n const docContext = await fetchDocContext(ctx.feature);\n const system = buildSystemMessage() + docContext;\n const user = buildUserMessage(ctx);\n\n console.log(`🤖 Using ${providerConfig.displayName} (${providerConfig.model})`);\n\n if (providerConfig.transport === 'anthropic') {\n return callAnthropic(providerConfig.apiKey, providerConfig.model, system, user);\n }\n\n return callOpenAiCompatible(\n providerConfig.apiKey,\n providerConfig.model,\n providerConfig.baseUrl ?? 'https://api.openai.com/v1',\n providerConfig.displayName,\n system,\n user,\n );\n}\n","import type { CapturedElement, ElementMap } from './capture.js';\nimport { resolveLlmProvider } from './llm-provider.js';\nimport { inferPrefix as inferSuggestedPrefix } from './prefix.js';\n\nexport type AnalysisStep = {\n action: 'navigate' | 'fill' | 'click' | 'select' | 'check' | 'keyboard' | 'hover';\n selector: string;\n value: string;\n human: string;\n};\n\nexport type AnalysisAssertion = {\n type: string;\n selector: string;\n expected: string;\n human: string;\n playwright: string;\n};\n\nexport type AnalysisScenario = {\n id: string;\n title: string;\n tags: string[];\n steps: AnalysisStep[];\n assertions: AnalysisAssertion[];\n narrator: string;\n codeLevel: 'beginner' | 'intermediate' | 'advanced';\n};\n\nexport type AnalysisResult = {\n url: string;\n feature: string;\n suggestedPrefix: string;\n scenarios: AnalysisScenario[];\n analysisNotes?: string;\n audioSummary?: string;\n};\n\ntype AuthElements = {\n usernameInput?: CapturedElement;\n passwordInput?: CapturedElement;\n submitButton?: CapturedElement;\n heading?: CapturedElement;\n};\n\ntype AnalysisOptions = {\n verbose?: boolean;\n feature?: string;\n};\n\ntype IntentMode = 'count' | 'presence' | 'auth' | 'form' | 'flow' | 'generic';\n\ntype IntentProfile = {\n feature: string;\n mode: IntentMode;\n maxScenarios: number;\n wantsHeading: boolean;\n};\n\nfunction escapeForRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\\\/]/g, '\\\\$&');\n}\n\nconst RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE = `\nRULE 10 - PLAYWRIGHT KNOWLEDGE BASE\n(sourced from playwright.dev official documentation)\n\nYou are an expert in Playwright TypeScript. Apply this knowledge\nwhen generating test code. Always use web-first assertions that\nauto-wait. Never use manual waits or non-awaited assertions.\n\nLOCATOR PRIORITY (use in this order)\n1. page.getByRole('button', { name: 'Submit' }) <- best\n2. page.getByLabel('Email address')\n3. page.getByPlaceholder('Enter email')\n4. page.getByText('Welcome')\n5. page.getByAltText('logo')\n6. page.getByTitle('Close')\n7. page.getByTestId('submit-btn')\n8. page.locator('#id') or page.locator('.class') <- last resort\n\nChain locators to narrow scope:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' }).click()\n\nLOCATOR ASSERTIONS (always await, always web-first)\nVisibility:\n await expect(locator).toBeVisible()\n await expect(locator).toBeHidden()\n await expect(locator).toBeInViewport()\n\nState:\n await expect(locator).toBeEnabled()\n await expect(locator).toBeDisabled()\n await expect(locator).toBeChecked()\n await expect(locator).not.toBeChecked()\n await expect(locator).toBeFocused()\n await expect(locator).toBeEditable()\n await expect(locator).toBeEmpty()\n await expect(locator).toBeAttached()\n\nText content:\n await expect(locator).toHaveText('exact text')\n await expect(locator).toHaveText(/regex/)\n await expect(locator).toContainText('partial')\n await expect(locator).toContainText(['item1', 'item2'])\n\nValue and attributes:\n await expect(locator).toHaveValue('input value')\n await expect(locator).toHaveValues(['opt1', 'opt2']) // multi-select\n await expect(locator).toHaveAttribute('href', /pattern/)\n await expect(locator).toHaveClass(/active/)\n await expect(locator).toHaveCSS('color', 'rgb(0,0,0)')\n await expect(locator).toHaveId('submit-btn')\n await expect(locator).toHaveAccessibleName('Submit form')\n await expect(locator).toHaveAccessibleDescription('...')\n\nCounting (PREFER toHaveCount over .count() to avoid flakiness):\n await expect(locator).toHaveCount(3)\n await expect(locator).toHaveCount(0) // none exist\n // Only use .count() when you need the actual number:\n const n = await page.getByRole('button').count();\n console.log(\\`Found \\${n} buttons\\`);\n\nPAGE ASSERTIONS\n await expect(page).toHaveTitle(/Playwright/)\n await expect(page).toHaveTitle('Exact Title')\n await expect(page).toHaveURL('https://example.com/dashboard')\n await expect(page).toHaveURL(/\\\\/dashboard/)\n\nACTIONS (Playwright auto-waits before each action)\nNavigation:\n await page.goto('https://example.com')\n await page.goBack()\n await page.goForward()\n await page.reload()\n\nClicking:\n await locator.click()\n await locator.dblclick()\n await locator.click({ button: 'right' })\n await locator.click({ modifiers: ['Shift'] })\n\nForms:\n await locator.fill('text') // clears then types\n await locator.clear()\n await locator.pressSequentially('slow typing', { delay: 50 })\n await locator.selectOption('value')\n await locator.selectOption({ label: 'Blue' })\n await locator.check()\n await locator.uncheck()\n await locator.setInputFiles('path/to/file.pdf')\n\nHover and focus:\n await locator.hover()\n await locator.focus()\n await locator.blur()\n\nKeyboard:\n await page.keyboard.press('Enter')\n await page.keyboard.press('Tab')\n await page.keyboard.press('Escape')\n await page.keyboard.press('Control+A')\n\nScroll:\n await locator.scrollIntoViewIfNeeded()\n await page.mouse.wheel(0, 500)\n\nBEST PRACTICES (from playwright.dev/docs/best-practices)\nDO use web-first assertions:\n await expect(page.getByText('welcome')).toBeVisible()\n\nNEVER use synchronous assertions:\n expect(await page.getByText('welcome').isVisible()).toBe(true)\n\nDO chain locators:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' })\n\nNEVER use fragile CSS/XPath selectors:\n page.locator('button.buttonIcon.episode-actions-later')\n\nDO use role-based locators:\n page.getByRole('button', { name: 'submit' })\n\nINTENT -> PATTERN MAPPING\n\nCOUNTING:\n \"how many X\" / \"count X\" / \"number of X\" / \"return the count\"\n -> const n = await page.getByRole('X').count();\n console.log(\\`Found \\${n} X elements\\`);\n expect(n).toBeGreaterThan(0);\n\n \"there are N X\" / \"exactly N X\"\n -> await expect(page.getByRole('X')).toHaveCount(N);\n\n CRITICAL: Never use getByText(\"how many X\") - count intent\n means call .count() or toHaveCount(), not search for text.\n\nPRESENCE:\n \"X is present/visible/shown/exists\"\n -> await expect(locator).toBeVisible()\n\n \"X is hidden/not present/gone\"\n -> await expect(locator).toBeHidden()\n\nTEXT:\n \"text says X\" / \"shows X\" / \"message is X\"\n -> await expect(locator).toHaveText('X')\n\n \"contains X\" / \"includes X\"\n -> await expect(locator).toContainText('X')\n\n \"page title is X\"\n -> await expect(page).toHaveTitle(/X/i)\n\n \"heading says X\"\n -> await expect(page.getByRole('heading')).toContainText('X')\n\n \"error says X\"\n -> await expect(page.getByRole('alert')).toContainText('X')\n\nSTATE:\n \"X is enabled/disabled\"\n -> await expect(locator).toBeEnabled() / toBeDisabled()\n\n \"X is checked/unchecked\"\n -> await expect(locator).toBeChecked() / not.toBeChecked()\n\n \"X has value Y\"\n -> await expect(locator).toHaveValue('Y')\n\n \"X is active / has class Y\"\n -> await expect(locator).toHaveClass(/Y/)\n\nNAVIGATION:\n \"redirects to X\" / \"goes to X\" / \"URL contains X\"\n -> await expect(page).toHaveURL(/X/)\n\n \"stays on same page\"\n -> await expect(page).toHaveURL(/currentPath/)\n\n \"opens new tab\"\n -> const [newPage] = await Promise.all([\n context.waitForEvent('page'),\n locator.click()\n ]);\n\nFORMS:\n \"form submits successfully\"\n -> fill fields + click submit + assert URL change or success message\n\n \"validation error shown\"\n -> submit empty + await expect(page.getByRole('alert')).toBeVisible()\n\n \"required field X\"\n -> submit without X + assert error message for X visible\n\nAUTH:\n \"login with valid credentials\"\n -> fill(CT_VAR_USERNAME) + fill(CT_VAR_PASSWORD) + click login\n + await expect(page).toHaveURL(/dashboard|home|app/)\n\n \"login fails / invalid credentials\"\n -> fill bad values + click login\n + await expect(page.getByRole('alert')).toBeVisible()\n\n \"logout works\"\n -> click logout + await expect(page).toHaveURL(/login|home/)\n\nTHEME / VISUAL:\n \"dark mode / theme toggle\"\n -> await locator.click()\n + await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')\n // OR: await expect(page.locator('body')).toHaveClass(/dark/)\n\nTIMING:\n \"X loads / X appears\"\n -> await expect(locator).toBeVisible({ timeout: 10000 })\n\n \"spinner disappears / loader gone\"\n -> await expect(spinner).toBeHidden({ timeout: 10000 })\n\n \"modal closes\"\n -> await expect(modal).toBeHidden()\n\nACCESSIBILITY:\n \"has alt text\"\n -> await expect(page.locator('img')).toHaveAttribute('alt', /.+/)\n\n \"keyboard navigable\"\n -> await page.keyboard.press('Tab')\n + await expect(firstFocusable).toBeFocused()\n\nCRITICAL RULES\n1. NEVER use intent words as locator text.\n \"count buttons\" != getByText(\"count buttons\")\n \"verify heading\" != getByText(\"verify heading\")\n\n2. ALWAYS use web-first assertions (await expect).\n NEVER use: expect(await locator.isVisible()).toBe(true)\n\n3. For counting, prefer toHaveCount() over .count() unless\n you need the actual number for logging.\n\n4. Auto-waiting: Playwright automatically waits for elements\n to be actionable before click/fill/etc. Do not add\n manual waitForTimeout() unless testing timing specifically.\n\n5. Use not. prefix for negative assertions:\n await expect(locator).not.toBeVisible()\n await expect(locator).not.toBeChecked()\n`.trim();\n\nconst ADVANCED_DOC_MAP: Record<string, string> = {\n upload: 'https://playwright.dev/docs/input',\n 'file upload': 'https://playwright.dev/docs/input',\n intercept: 'https://playwright.dev/docs/mock',\n mock: 'https://playwright.dev/docs/mock',\n 'api mock': 'https://playwright.dev/docs/mock',\n accessibility: 'https://playwright.dev/docs/accessibility-testing',\n 'screen reader': 'https://playwright.dev/docs/accessibility-testing',\n visual: 'https://playwright.dev/docs/screenshots',\n screenshot: 'https://playwright.dev/docs/screenshots',\n mobile: 'https://playwright.dev/docs/emulation',\n responsive: 'https://playwright.dev/docs/emulation',\n viewport: 'https://playwright.dev/docs/emulation',\n network: 'https://playwright.dev/docs/network',\n 'api call': 'https://playwright.dev/docs/network',\n iframe: 'https://playwright.dev/docs/frames',\n frame: 'https://playwright.dev/docs/frames',\n auth: 'https://playwright.dev/docs/auth',\n 'sign in': 'https://playwright.dev/docs/auth',\n 'stay logged': 'https://playwright.dev/docs/auth',\n cookie: 'https://playwright.dev/docs/auth',\n storage: 'https://playwright.dev/docs/auth',\n download: 'https://playwright.dev/docs/downloads',\n pdf: 'https://playwright.dev/docs/downloads',\n dialog: 'https://playwright.dev/docs/dialogs',\n alert: 'https://playwright.dev/docs/dialogs',\n confirm: 'https://playwright.dev/docs/dialogs',\n 'new tab': 'https://playwright.dev/docs/pages',\n 'new page': 'https://playwright.dev/docs/pages',\n popup: 'https://playwright.dev/docs/pages',\n};\n\nasync function fetchDocContext(intent: string): Promise<string> {\n const intentLower = intent.toLowerCase();\n const matched = new Set<string>();\n\n for (const [keyword, url] of Object.entries(ADVANCED_DOC_MAP)) {\n if (intentLower.includes(keyword)) {\n matched.add(url);\n }\n }\n\n if (matched.size === 0) return '';\n\n const fetched: string[] = [];\n\n for (const url of matched) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const html = await res.text();\n const text = html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s{3,}/g, '\\n\\n')\n .slice(0, 3000);\n\n fetched.push(`\\n// From ${url}:\\n${text}`);\n } catch {\n // Non-fatal - continue without this doc\n }\n }\n\n if (fetched.length === 0) return '';\n\n return `\\n\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\nADDITIONAL PLAYWRIGHT DOCS (fetched for this intent)\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${fetched.join('\\n')}`;\n}\n\nexport async function analyseElements(\n elementMap: ElementMap,\n options: AnalysisOptions = {},\n): Promise<AnalysisResult> {\n const { verbose = false, feature } = options;\n const requestedFeature = normalizeRequestedFeature(feature, elementMap);\n\n let providerConfig;\n try {\n providerConfig = resolveLlmProvider();\n } catch (error: any) {\n log(verbose, `\\n[analyse] ${shortErrorMessage(error)}`);\n log(verbose, '[analyse] Falling back to deterministic capture analysis.');\n return buildDeterministicAnalysis(elementMap, requestedFeature);\n }\n\n log(verbose, `\\n[analyse] Sending capture to ${providerConfig.displayName} (${providerConfig.model})`);\n\n try {\n const docContext = await fetchDocContext(requestedFeature);\n const systemPrompt = buildSystemPrompt() + docContext;\n const userPrompt = buildUserPrompt(elementMap, requestedFeature);\n\n const rawResponse = providerConfig.transport === 'anthropic'\n ? await callAnthropic(providerConfig.apiKey, providerConfig.model, systemPrompt, userPrompt)\n : await callOpenAiCompatible(\n providerConfig.apiKey,\n providerConfig.model,\n providerConfig.baseUrl ?? 'https://api.openai.com/v1',\n providerConfig.displayName,\n systemPrompt,\n userPrompt,\n );\n\n const parsed = parseAnalysisJson(rawResponse);\n return sanitizeAnalysis(parsed, elementMap, requestedFeature);\n } catch (error: any) {\n log(verbose, `[analyse] Remote analysis failed: ${shortErrorMessage(error)}`);\n log(verbose, '[analyse] Falling back to deterministic capture analysis.');\n return buildDeterministicAnalysis(elementMap, requestedFeature);\n }\n}\n\nfunction buildSystemPrompt(): string {\n return `\nYou are a senior QA automation engineer and Playwright expert working on CementicTest.\n\nYour job is to analyse a structured map of interactive elements extracted from a live web page,\nthen produce a complete set of Playwright test scenarios.\n\nRULES:\n1. The user's feature description is the PRIMARY requirement. Generate scenarios that test what the user asked for.\n2. Every assertion must include an exact \"playwright\" field with a complete await expect(...) statement.\n3. Use captured elements as the first selector source. If the intent names text that was not captured, you may fall back to a safe Playwright selector derived from the intent such as getByRole(), getByText(), getByLabel(), getByPlaceholder(), or locator('#id').\n4. Include happy-path and negative scenarios only when the intent implies interaction, and stay evidence-backed.\n5. Output only valid JSON matching the requested schema.\n6. Do not invent redirect targets, success pages, error text, password clearing, or security scenarios unless the capture explicitly supports them.\n7. If no status or alert region was captured, avoid scenarios that depend on unseen server-side validation messages.\n8. Scope must match intent complexity. Simple 1 to 2 claim requests should produce only 1 to 2 scenarios.\n9. For presence-only intents such as \"verify X\" or \"X is present\", only assert visibility. Do not click and do not assert outcomes after clicking.\n${RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE}\n11. For fill steps, never use the literal word \"value\". If matching CT_VAR_* variables are listed in the prompt, use them in human-readable step text and use a realistic non-generic runtime value in the JSON value field. Otherwise use a field-specific fallback such as test-username or test-password.\n12. When a CTA could realistically be a button or a link, prefer a resilient selector such as getByRole('button', { name: /Join Now/i }).or(page.getByRole('link', { name: /Join Now/i })).\n13. The \"selector\" field must be a raw selector expression such as locator(\"#username\") or getByRole('button', { name: \"Login\" }). Never wrap selectors in page. or page.locator(\"...\") inside JSON, except inside Locator.or(...) where the alternate locator must be page-scoped.\n14. Tie-breaker for multiple matching elements: prefer highest confidence, then interactive elements, then the first visible-looking candidate.\n15. If a page clearly contains login or auth fields, do not create submit scenarios that only click the button. Include realistic fill steps for captured username/email and password inputs when the intent asks for auth interaction.\n16. \"verify title\" means the main visible heading on the page, not the browser tab title, unless the intent explicitly says browser title, tab title, or page title.\n\nOUTPUT SCHEMA:\n{\n \"url\": string,\n \"feature\": string,\n \"suggestedPrefix\": string,\n \"scenarios\": [\n {\n \"id\": string,\n \"title\": string,\n \"tags\": string[],\n \"steps\": [\n {\n \"action\": \"navigate\"|\"fill\"|\"click\"|\"select\"|\"check\"|\"keyboard\"|\"hover\",\n \"selector\": string,\n \"value\": string,\n \"human\": string\n }\n ],\n \"assertions\": [\n {\n \"type\": string,\n \"selector\": string,\n \"expected\": string,\n \"human\": string,\n \"playwright\": string\n }\n ],\n \"narrator\": string,\n \"codeLevel\": \"beginner\"|\"intermediate\"|\"advanced\"\n }\n ],\n \"analysisNotes\": string,\n \"audioSummary\": string\n}`.trim();\n}\n\nfunction buildUserPrompt(elementMap: ElementMap, feature: string): string {\n const lines: string[] = [];\n const authElements = detectAuthElements(elementMap);\n const availableCtVarKeys = getAvailableCtVarKeys();\n const intentProfile = buildIntentProfile(feature);\n\n lines.push('USER INTENT');\n lines.push(`Feature description: ${feature}`);\n lines.push(`Intent mode: ${intentProfile.mode}`);\n lines.push(`Maximum scenarios for this request: ${intentProfile.maxScenarios}`);\n lines.push('');\n\n lines.push('PAGE INFORMATION');\n lines.push(`URL: ${elementMap.url}`);\n lines.push(`Title: ${elementMap.title}`);\n lines.push(`Captured in: ${elementMap.mode} mode`);\n lines.push('');\n\n for (const category of ['input', 'button', 'link', 'heading', 'status'] as const) {\n const items = elementMap.elements.filter((element) => element.category === category);\n if (items.length === 0) continue;\n\n lines.push(`${category.toUpperCase()}S (${items.length} found):`);\n for (const item of items.slice(0, category === 'link' ? 10 : items.length)) {\n lines.push(` - [${item.confidence}] ${item.selector}`);\n lines.push(` Purpose: ${item.purpose}`);\n if (item.selectorAlt.length > 0) {\n lines.push(` Fallbacks: ${item.selectorAlt.slice(0, 2).join(' | ')}`);\n }\n }\n lines.push('');\n }\n\n if (elementMap.warnings.length > 0) {\n lines.push('CAPTURE WARNINGS:');\n for (const warning of elementMap.warnings) {\n lines.push(` - ${warning}`);\n }\n lines.push('');\n }\n\n if (availableCtVarKeys.length > 0) {\n lines.push('AVAILABLE CT_VAR_* VARIABLES:');\n for (const envKey of availableCtVarKeys) {\n lines.push(` - ${envKey}`);\n }\n lines.push('');\n }\n\n const interactiveCount = elementMap.elements.filter((element) => (\n element.category === 'input' || element.category === 'button' || element.category === 'link'\n )).length;\n const statusCount = elementMap.elements.filter((element) => element.category === 'status').length;\n\n lines.push('EVIDENCE CONSTRAINTS:');\n lines.push(` - Interactive elements captured: ${interactiveCount}`);\n lines.push(` - Status or alert regions captured: ${statusCount}`);\n lines.push(' - If no redirect target is explicitly captured, do not assert a destination path.');\n lines.push(' - If no status region was captured, avoid exact server-side credential error claims.');\n lines.push(' - Generate scenarios only for the requested feature description.');\n if (authElements.usernameInput && authElements.passwordInput && authElements.submitButton) {\n lines.push(' - This page contains a captured auth form. Include fill steps for the username/email and password fields in credential-submission scenarios.');\n lines.push(' - For auth pages without captured post-submit evidence, prefer evidence-backed form-state assertions over invented success redirects.');\n }\n lines.push('');\n lines.push('Generate only the JSON response.');\n\n return lines.join('\\n');\n}\n\nasync function callAnthropic(\n apiKey: string,\n model: string,\n systemPrompt: string,\n userPrompt: string,\n): Promise<string> {\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Anthropic API ${response.status}: ${await response.text()}`);\n }\n\n const json: any = await response.json();\n const content = json.content?.[0]?.text?.trim() ?? '';\n if (!content) throw new Error('Anthropic returned empty content');\n return content;\n}\n\nasync function callOpenAiCompatible(\n apiKey: string,\n model: string,\n baseUrl: string,\n displayName: string,\n systemPrompt: string,\n userPrompt: string,\n): Promise<string> {\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n temperature: 0.1,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`${displayName} API ${response.status}: ${await response.text()}`);\n }\n\n const json: any = await response.json();\n const content = json.choices?.[0]?.message?.content?.trim() ?? '';\n if (!content) throw new Error('OpenAI-compatible provider returned empty content');\n return content;\n}\n\nfunction parseAnalysisJson(raw: string): AnalysisResult {\n const stripped = raw\n .replace(/^```(?:json)?\\s*/m, '')\n .replace(/\\s*```\\s*$/m, '')\n .trim();\n\n try {\n return JSON.parse(stripped);\n } catch (error: any) {\n throw new Error(\n `Failed to parse LLM response as JSON.\\nParse error: ${error?.message ?? error}\\nRaw response:\\n${raw.slice(0, 500)}`\n );\n }\n}\n\nfunction sanitizeAnalysis(\n analysis: AnalysisResult,\n elementMap: ElementMap,\n requestedFeature: string,\n): AnalysisResult {\n const selectors = new Set<string>();\n for (const element of elementMap.elements) {\n selectors.add(element.selector);\n for (const alt of element.selectorAlt) selectors.add(alt);\n }\n\n const rawScenarios = Array.isArray(analysis.scenarios) ? analysis.scenarios : [];\n const intentProfile = buildIntentProfile(requestedFeature);\n const currentUrl = new URL(elementMap.url);\n const authElements = detectAuthElements(elementMap);\n const resolvedFeature = requestedFeature || analysis.feature || inferFeatureName(elementMap);\n const resolvedPrefix = (analysis.suggestedPrefix || inferSuggestedPrefix({\n featureText: resolvedFeature,\n url: elementMap.url,\n })).toUpperCase();\n const knownPaths = new Set([\n currentUrl.pathname,\n ...elementMap.elements\n .filter((element) => element.category === 'link')\n .map((element) => {\n const href = element.attributes?.href;\n if (typeof href !== 'string') return '';\n try {\n return new URL(href, elementMap.url).pathname;\n } catch {\n return href;\n }\n })\n .filter(Boolean),\n ]);\n\n const sanitizedScenarios = rawScenarios\n .map((scenario) => normalizeScenario(scenario, selectors, elementMap.url))\n .filter((scenario) => scenario.steps.length > 0 && scenario.assertions.length > 0)\n .map((scenario) => ({\n ...scenario,\n tags: scenario.tags.map(normalizeTag),\n assertions: scenario.assertions.filter((assertion) => {\n if (assertion.type !== 'url') return true;\n const combined = `${assertion.expected} ${assertion.human} ${assertion.playwright}`;\n const pathMatch = combined.match(/\\/[a-z0-9/_-]+/i);\n if (!pathMatch) return true;\n return knownPaths.has(pathMatch[0]);\n }),\n }))\n .filter((scenario) => scenario.assertions.length > 0);\n\n const intentAlignedScenarios = applyIntentPolicy(\n sanitizedScenarios,\n elementMap,\n intentProfile,\n resolvedPrefix,\n ).slice(0, intentProfile.maxScenarios);\n\n const useAuthFallback = shouldUseAuthFallback(authElements, intentAlignedScenarios, intentProfile);\n const fallbackScenarios = intentProfile.mode === 'presence'\n ? buildPresenceOnlyScenarios(elementMap, requestedFeature, resolvedPrefix)\n : useAuthFallback\n ? buildAuthFallbackScenarios(elementMap, resolvedPrefix, authElements, requestedFeature)\n : buildFallbackScenarios(elementMap, resolvedPrefix, requestedFeature);\n const finalScenarios = useAuthFallback\n ? fallbackScenarios.slice(0, intentProfile.maxScenarios)\n : intentAlignedScenarios.length > 0\n ? intentAlignedScenarios\n : fallbackScenarios.slice(0, intentProfile.maxScenarios);\n\n return {\n ...analysis,\n url: analysis.url || elementMap.url,\n feature: resolvedFeature,\n suggestedPrefix: resolvedPrefix,\n scenarios: finalScenarios,\n analysisNotes: [\n analysis.analysisNotes,\n useAuthFallback ? 'Replaced low-evidence auth scenarios with deterministic evidence-backed auth coverage.' : '',\n `Sanitized to ${finalScenarios.length} evidence-backed scenario(s) from ${rawScenarios.length} raw scenario(s).`,\n ].filter(Boolean).join(' '),\n audioSummary: analysis.audioSummary || buildAudioSummary(resolvedFeature, finalScenarios),\n };\n}\n\nfunction normalizeScenario(candidate: any, selectors: Set<string>, url: string): AnalysisScenario {\n const steps = Array.isArray(candidate?.steps)\n ? candidate.steps\n .map((step: any) => normalizeStep(step, selectors))\n .filter(Boolean) as AnalysisStep[]\n : [];\n\n const assertions = Array.isArray(candidate?.assertions)\n ? candidate.assertions\n .map((assertion: any) => normalizeAssertion(assertion, selectors))\n .filter(Boolean) as AnalysisAssertion[]\n : [];\n\n const normalizedSteps = ensureNavigateStep(steps, url);\n\n return {\n id: candidate?.id ?? 'FLOW-001',\n title: candidate?.title ?? 'Captured page flow',\n tags: Array.isArray(candidate?.tags) ? candidate.tags : [],\n steps: normalizedSteps,\n assertions,\n narrator: candidate?.narrator ?? 'Let us run this captured test flow.',\n codeLevel: candidate?.codeLevel ?? 'beginner',\n };\n}\n\nfunction normalizeStep(candidate: any, selectors: Set<string>): AnalysisStep | null {\n if (!candidate) return null;\n\n const selector = String(candidate.selector ?? '').trim();\n if (!isAllowedSelector(selector, selectors)) return null;\n\n const action = String(candidate.action ?? '').trim() as AnalysisStep['action'];\n if (!['navigate', 'fill', 'click', 'select', 'check', 'keyboard', 'hover'].includes(action)) return null;\n\n const rawValue = String(candidate.value ?? '');\n const value = action === 'fill' || action === 'select'\n ? resolveFieldRuntimeValue(selector, rawValue)\n : rawValue;\n const human = normalizeStepHuman(\n String(candidate.human ?? '').trim() || defaultStepHuman(action, selector, value),\n action,\n selector,\n value,\n );\n\n return {\n action,\n selector,\n value,\n human,\n };\n}\n\nfunction normalizeAssertion(candidate: any, selectors: Set<string>): AnalysisAssertion | null {\n if (!candidate) return null;\n\n const selector = String(candidate.selector ?? '').trim();\n if (!isAllowedSelector(selector, selectors)) return null;\n\n const assertion: AnalysisAssertion = {\n type: String(candidate.type ?? 'visible').trim() || 'visible',\n selector,\n expected: String(candidate.expected ?? '').trim(),\n human: String(candidate.human ?? '').trim() || 'Expected state is verified',\n playwright: String(candidate.playwright ?? '').trim(),\n };\n\n assertion.playwright = normalizePlaywrightAssertion(assertion);\n return assertion;\n}\n\nfunction buildFallbackScenarios(elementMap: ElementMap, prefix: string): AnalysisScenario[] {\n return buildFallbackScenariosForFeature(elementMap, prefix, '');\n}\n\nfunction buildFallbackScenariosForFeature(\n elementMap: ElementMap,\n prefix: string,\n feature: string,\n): AnalysisScenario[] {\n const normalizedFeature = feature.toLowerCase();\n const heading = elementMap.elements.find((element) => element.category === 'heading');\n const emailInput = elementMap.elements.find((element) => (\n element.category === 'input' &&\n (element.attributes.type === 'email' || /email/.test(`${element.name ?? ''} ${String(element.attributes.label ?? '')}`.toLowerCase()))\n ));\n const passwordInput = elementMap.elements.find((element) => (\n element.category === 'input' && element.attributes.type === 'password'\n ));\n const submitButton = elementMap.elements.find((element) => (\n element.category === 'button' && /login|sign in|submit|continue/i.test(element.name ?? '')\n )) ?? elementMap.elements.find((element) => element.category === 'button');\n const alert = findAlertElement(elementMap);\n\n const scenarios: AnalysisScenario[] = [];\n const tag = (value: string) => normalizeTag(value);\n const nextId = (index: number) => `${prefix}-${String(900 + index).padStart(3, '0')}`;\n const wantsHiddenAlertOnLoad =\n /\\b(error|alert|message)\\b/.test(normalizedFeature) &&\n /\\b(not shown|not visible|hidden|not present|gone|absent)\\b/.test(normalizedFeature) &&\n /\\b(first load|first loads|first loads?|page first loads|initial load|on load)\\b/.test(normalizedFeature);\n const wantsVisibleAlert =\n /\\b(error|alert|message|invalid|incorrect|required|validation)\\b/.test(normalizedFeature) &&\n !wantsHiddenAlertOnLoad;\n\n if (wantsHiddenAlertOnLoad && alert) {\n return [{\n id: `${prefix}-001`,\n title: 'Error message is hidden on initial load',\n tags: [tag('negative'), tag('ui')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'hidden',\n selector: alert.selector,\n expected: 'hidden',\n human: `${alert.name || 'Error message'} is not shown when the page first loads`,\n playwright: `await expect(page.${alert.selector}).toBeHidden();`,\n },\n ],\n narrator: 'We verify that the page does not expose an error surface before any user action.',\n codeLevel: 'beginner',\n }];\n }\n\n if (wantsVisibleAlert && alert) {\n return [{\n id: `${prefix}-001`,\n title: 'Page exposes an alert message when requested',\n tags: [tag('negative'), tag('ui')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'text',\n selector: alert.selector,\n expected: alert.name || 'error',\n human: 'An alert message is shown',\n playwright: `await expect(page.${alert.selector}).toContainText(/invalid|error|required/i);`,\n },\n ],\n narrator: 'We validate the alert channel directly when the intent asks about an error message.',\n codeLevel: 'beginner',\n }];\n }\n\n if (heading) {\n scenarios.push({\n id: nextId(scenarios.length + 1),\n title: 'Page loads with expected heading',\n tags: [tag('smoke'), tag('page-load')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'visible',\n selector: heading.selector,\n expected: 'visible',\n human: `${heading.name || 'Primary heading'} is visible`,\n playwright: `await expect(page.${heading.selector}).toBeVisible();`,\n },\n ],\n narrator: 'We will first confirm that the expected page heading is visible.',\n codeLevel: 'beginner',\n });\n }\n\n if (emailInput && passwordInput && submitButton) {\n const emailValue = resolveFieldRuntimeValue(emailInput.selector, '');\n scenarios.push({\n id: nextId(scenarios.length + 1),\n title: 'Submitting without a password keeps the user on the form',\n tags: [tag('validation'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n {\n action: 'fill',\n selector: emailInput.selector,\n value: emailValue,\n human: buildFillHuman('Fill in the email field', emailInput.selector, emailValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the submit button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: new URL(elementMap.url).pathname,\n human: 'User remains on the same page',\n playwright: `await expect(page).toHaveURL('${elementMap.url}');`,\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: 'Password field stays visible for correction',\n playwright: `await expect(page.${passwordInput.selector}).toBeVisible();`,\n },\n ],\n narrator: 'Next we will leave the password blank and confirm the form does not advance.',\n codeLevel: 'beginner',\n });\n }\n\n return scenarios.slice(0, 5);\n}\n\nfunction buildAuthFallbackScenarios(\n elementMap: ElementMap,\n prefix: string,\n authElements: AuthElements,\n feature: string,\n): AnalysisScenario[] {\n const { usernameInput, passwordInput, submitButton, heading } = authElements;\n if (!usernameInput || !passwordInput || !submitButton) {\n return buildFallbackScenariosForFeature(elementMap, prefix, feature);\n }\n\n const normalizedFeature = feature.toLowerCase();\n const scenarios: AnalysisScenario[] = [];\n const tag = (value: string) => normalizeTag(value);\n const nextId = (index: number) => `${prefix}-${String(index).padStart(3, '0')}`;\n const usernameValue = inferAuthValue(usernameInput, 'username');\n const passwordValue = inferAuthValue(passwordInput, 'password');\n const alert = findAlertElement(elementMap);\n const wantsNavigation =\n /\\b(valid credentials|correct credentials|successful login|log in successfully|login succeeds|sign in succeeds)\\b/.test(normalizedFeature) ||\n /\\b(redirect|redirects|redirected|secure area|dashboard|redirected to|goes to|navigates? to)\\b/.test(normalizedFeature);\n const wantsError =\n /\\b(wrong password|wrong credentials|invalid|incorrect|error message|shows an error|alert)\\b/.test(normalizedFeature);\n const successUrlPattern = deriveSuccessUrlPattern(elementMap, normalizedFeature);\n\n if (wantsNavigation) {\n return [{\n id: `${prefix}-001`,\n title: 'Valid credentials redirect to the authenticated area',\n tags: [tag('auth'), tag('happy-path')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: passwordValue,\n human: buildFillHuman('Fill in the password field', passwordInput.selector, passwordValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: successUrlPattern,\n human: 'User is redirected to the secure area',\n playwright: `await expect(page).toHaveURL(/${successUrlPattern}/);`,\n },\n ],\n narrator: 'We submit valid credentials and confirm that authentication changes the page URL.',\n codeLevel: 'beginner',\n }];\n }\n\n if (wantsError) {\n return [{\n id: `${prefix}-001`,\n title: 'Wrong password shows an authentication error',\n tags: [tag('auth'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: 'wrong-password',\n human: buildFillHuman('Fill in the password field', passwordInput.selector, 'wrong-password'),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n alert\n ? {\n type: 'text',\n selector: alert.selector,\n expected: alert.name || 'error',\n human: 'An alert communicates the login failure',\n playwright: `await expect(page.${alert.selector}).toContainText(/invalid|error|required/i);`,\n }\n : {\n type: 'text',\n selector: usernameInput.selector,\n expected: 'error',\n human: 'An authentication error message is shown',\n playwright: `await expect(page.getByRole('alert')).toContainText(/invalid|error|required/i);`,\n },\n ],\n narrator: 'We use an invalid password and confirm the page surfaces an authentication error.',\n codeLevel: 'beginner',\n }];\n }\n\n scenarios.push({\n id: nextId(1),\n title: 'Login form renders expected controls',\n tags: [tag('smoke'), tag('auth')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n ],\n assertions: [\n ...(heading ? [{\n type: 'visible',\n selector: heading.selector,\n expected: 'visible',\n human: `${heading.name || 'Login heading'} is visible`,\n playwright: visibleAssertion(heading.selector),\n }] : []),\n {\n type: 'visible',\n selector: usernameInput.selector,\n expected: 'visible',\n human: `${usernameInput.name || 'Username field'} is visible`,\n playwright: visibleAssertion(usernameInput.selector),\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: `${passwordInput.name || 'Password field'} is visible`,\n playwright: visibleAssertion(passwordInput.selector),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Submit button'} is visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'We first confirm that the captured login form is present and interactive.',\n codeLevel: 'beginner',\n });\n\n scenarios.push({\n id: nextId(2),\n title: 'User can enter credentials before submission',\n tags: [tag('auth'), tag('happy-path')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: passwordValue,\n human: buildFillHuman('Fill in the password field', passwordInput.selector, passwordValue),\n },\n ],\n assertions: [\n {\n type: 'value',\n selector: usernameInput.selector,\n expected: usernameValue,\n human: 'Username input contains the entered value',\n playwright: valueAssertion(usernameInput.selector, usernameValue),\n },\n {\n type: 'value',\n selector: passwordInput.selector,\n expected: passwordValue,\n human: 'Password input contains the entered value',\n playwright: valueAssertion(passwordInput.selector, passwordValue),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Submit button'} remains visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'Next we verify that both credential fields accept input before we submit the form.',\n codeLevel: 'beginner',\n });\n\n scenarios.push({\n id: nextId(3),\n title: 'Submitting without a password keeps the login form visible',\n tags: [tag('auth'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: elementMap.url,\n human: 'User remains on the same login URL',\n playwright: `await expect(page).toHaveURL('${elementMap.url}');`,\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: 'Password field remains visible for correction',\n playwright: visibleAssertion(passwordInput.selector),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Login button'} remains visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'Finally we submit incomplete credentials and confirm the captured login form remains available for correction.',\n codeLevel: 'beginner',\n });\n\n return scenarios;\n}\n\nfunction normalizeRequestedFeature(feature: string | undefined, elementMap: ElementMap): string {\n return String(feature ?? '').trim() || inferFeatureName(elementMap);\n}\n\nfunction inferFeatureName(elementMap: ElementMap): string {\n const heading = elementMap.elements.find((element) => element.category === 'heading' && element.name);\n return heading?.name || elementMap.title || 'Captured page';\n}\n\nfunction getAvailableCtVarKeys(): string[] {\n return Object.keys(process.env)\n .filter((key) => /^CT_VAR_[A-Z0-9_]+$/.test(key))\n .sort();\n}\n\nfunction buildIntentProfile(feature: string): IntentProfile {\n const normalized = feature.toLowerCase();\n const countIntent = /\\b(?:how many|count|number of|return the count|exactly\\s+\\d+|there (?:is|are)\\s+\\d+)/.test(normalized);\n const wantsHeading = /\\b(?:title|heading)\\b/.test(normalized)\n && !/\\b(?:browser title|tab title|page title)\\b/.test(normalized);\n const presenceOnly = isPresenceOnlyIntent(normalized);\n const authIntent = /\\b(?:login|log in|sign in|auth|credentials?)\\b/.test(normalized) && !presenceOnly;\n const formIntent = /\\b(?:form|submit|field|input|enter|fill|type)\\b/.test(normalized) && !presenceOnly && !authIntent;\n const flowIntent = /\\b(?:flow|journey|checkout|purchase|complete|works?)\\b/.test(normalized) && !presenceOnly && !authIntent && !formIntent;\n const mode: IntentMode = countIntent\n ? 'count'\n : presenceOnly\n ? 'presence'\n : authIntent\n ? 'auth'\n : formIntent\n ? 'form'\n : flowIntent\n ? 'flow'\n : 'generic';\n const claimCount = countIntentClaims(feature);\n\n return {\n feature,\n mode,\n maxScenarios:\n mode === 'count' ? 1\n : mode === 'presence' ? Math.min(Math.max(claimCount, 1), 2)\n : mode === 'auth' || mode === 'form' ? Math.min(Math.max(claimCount, 3), 5)\n : mode === 'flow' ? Math.min(Math.max(claimCount, 4), 6)\n : Math.min(Math.max(claimCount, 1), 3),\n wantsHeading,\n };\n}\n\nfunction countIntentClaims(feature: string): number {\n const quoted = Array.from(feature.matchAll(/[\"“”']([^\"“”']+)[\"“”']/g)).length;\n const segments = feature\n .split(/\\s+(?:and|&)\\s+|,\\s*/i)\n .map((segment) => segment.trim())\n .filter(Boolean);\n return Math.max(quoted, segments.length || 1);\n}\n\nfunction isPresenceOnlyIntent(normalizedFeature: string): boolean {\n const presenceWords = /\\b(?:verify|check|confirm|ensure|present|visible|shown|showing|available|exists?|title|heading)\\b/.test(normalizedFeature);\n const actionWords = /\\b(?:click|submit|fill|type|enter|login|log in|sign in|checkout|purchase|complete|flow|journey|error|invalid|disabled|enabled)\\b/.test(normalizedFeature);\n return presenceWords && !actionWords;\n}\n\nfunction applyIntentPolicy(\n scenarios: AnalysisScenario[],\n elementMap: ElementMap,\n intentProfile: IntentProfile,\n prefix: string,\n): AnalysisScenario[] {\n if (intentProfile.mode === 'count') {\n return buildCountScenarios(elementMap, intentProfile.feature, prefix);\n }\n if (intentProfile.mode !== 'presence') {\n return scenarios.slice(0, intentProfile.maxScenarios);\n }\n return buildPresenceOnlyScenarios(elementMap, intentProfile.feature, prefix);\n}\n\nfunction buildCountScenarios(\n elementMap: ElementMap,\n feature: string,\n prefix: string,\n): AnalysisScenario[] {\n const normalized = feature.toLowerCase();\n const countedElements = pickCountedElements(elementMap, normalized);\n const selector = countSelectorForFeature(normalized, countedElements);\n const count = countedElements.length;\n\n return [{\n id: `${prefix}-${String(1).padStart(3, '0')}`,\n title: feature,\n tags: ['@smoke', '@ui'],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: `Navigate to ${elementMap.url}`,\n },\n ],\n assertions: [{\n type: 'count',\n selector,\n expected: String(count),\n human: `There are exactly ${count} matching elements`,\n playwright: `await expect(page.${selector}).toHaveCount(${count});`,\n }],\n narrator: 'We count only the element type requested by the user.',\n codeLevel: 'beginner',\n }];\n}\n\nfunction buildPresenceOnlyScenarios(\n elementMap: ElementMap,\n feature: string,\n prefix: string,\n): AnalysisScenario[] {\n const claims = extractPresenceClaims(feature, elementMap);\n if (claims.length === 0) return buildFallbackScenarios(elementMap, prefix).slice(0, 1);\n\n return [{\n id: `${prefix}-${String(1).padStart(3, '0')}`,\n title: feature,\n tags: ['@smoke', '@ui'],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: `Navigate to ${elementMap.url}`,\n },\n ],\n assertions: claims.map((claim) => ({\n type: 'visible',\n selector: claim.selector,\n expected: 'visible',\n human: claim.human,\n playwright: visibleAssertion(claim.selector),\n })),\n narrator: 'We verify only the elements explicitly requested by the user.',\n codeLevel: 'beginner',\n }];\n}\n\nfunction extractPresenceClaims(\n feature: string,\n elementMap: ElementMap,\n): Array<{ selector: string; human: string }> {\n const segments = feature\n .split(/\\s+(?:and|&)\\s+|,\\s*/i)\n .map((segment) => segment.trim())\n .filter(Boolean);\n const claims: Array<{ selector: string; human: string }> = [];\n\n for (const segment of segments) {\n const normalized = segment.toLowerCase();\n if (/\\b(?:title|heading)\\b/.test(normalized) && !/\\b(?:browser title|tab title|page title)\\b/.test(normalized)) {\n claims.push({\n selector: `getByRole('heading')`,\n human: `${chooseHeadingElement(elementMap)?.name || 'Main page heading'} is visible`,\n });\n continue;\n }\n\n const text = extractIntentLabel(segment);\n if (!text) continue;\n const match = findBestMatchingElement(elementMap, text, normalized);\n const selector = buildIntentSelector(text, normalized, match);\n claims.push({\n selector,\n human: `${text} is visible`,\n });\n }\n\n return claims;\n}\n\nfunction chooseHeadingElement(elementMap: ElementMap): CapturedElement | undefined {\n return rankElements(\n elementMap.elements.filter((element) => element.category === 'heading'),\n )[0];\n}\n\nfunction extractIntentLabel(segment: string): string {\n const unquoted = Array.from(segment.matchAll(/[\"“”']([^\"“”']+)[\"“”']/g)).map((match) => match[1].trim());\n if (unquoted.length > 0) return unquoted[0];\n\n return segment\n .replace(/\\b(?:verify|check|confirm|ensure)\\b/gi, ' ')\n .replace(/\\b(?:the|a|an)\\b/gi, ' ')\n .replace(/\\b(?:is|are|be|should be)\\b/gi, ' ')\n .replace(/\\b(?:present|visible|shown|showing|available|exists?)\\b/gi, ' ')\n .replace(/\\b(?:on|in)\\s+(?:the\\s+)?page\\b/gi, ' ')\n .replace(/\\b(?:button|link|cta|label|text)\\b/gi, ' ')\n .replace(/[.?!,:;]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction findBestMatchingElement(\n elementMap: ElementMap,\n text: string,\n segment: string,\n): CapturedElement | undefined {\n const preferredCategory =\n /\\bbutton\\b/.test(segment) ? 'button'\n : /\\blink\\b/.test(segment) ? 'link'\n : /\\bheading\\b/.test(segment) ? 'heading'\n : undefined;\n const query = text.toLowerCase();\n const candidates = elementMap.elements.filter((element) => {\n const haystack = `${element.name ?? ''} ${element.purpose}`.toLowerCase();\n return haystack.includes(query);\n });\n\n if (!preferredCategory) return rankElements(candidates)[0];\n\n const preferred = candidates.filter((element) => element.category === preferredCategory);\n if (preferred.length > 0) return rankElements(preferred)[0];\n\n if (\n (preferredCategory === 'button' || preferredCategory === 'link')\n && shouldUseAmbiguousCtaSelector(segment, text)\n ) {\n const alternateCategory = preferredCategory === 'button' ? 'link' : 'button';\n const alternates = candidates.filter((element) => element.category === alternateCategory);\n if (alternates.length > 0) return rankElements(alternates)[0];\n }\n\n return rankElements(candidates)[0];\n}\n\nfunction rankElements(elements: CapturedElement[]): CapturedElement[] {\n const confidenceWeight = (confidence: string): number => (\n confidence === 'high' ? 3 : confidence === 'medium' ? 2 : 1\n );\n const interactiveWeight = (category: string): number => (\n category === 'button' || category === 'link' || category === 'input' ? 2 : 1\n );\n\n return [...elements].sort((left, right) => {\n const confidenceDelta = confidenceWeight(right.confidence) - confidenceWeight(left.confidence);\n if (confidenceDelta !== 0) return confidenceDelta;\n const interactiveDelta = interactiveWeight(right.category) - interactiveWeight(left.category);\n if (interactiveDelta !== 0) return interactiveDelta;\n return 0;\n });\n}\n\nfunction buildIntentSelector(\n text: string,\n segment: string,\n match?: CapturedElement,\n): string {\n if (shouldUseAmbiguousCtaSelector(segment, text)) {\n if (/\\blink\\b/.test(segment)) return buildAmbiguousRoleSelector(text, 'link');\n if (/\\bbutton\\b/.test(segment) || match?.category === 'link' || match?.category === 'button') {\n return buildAmbiguousRoleSelector(text, 'button');\n }\n }\n\n return match?.selector ?? buildFallbackSelector(text, segment);\n}\n\nfunction shouldUseAmbiguousCtaSelector(segment: string, text: string): boolean {\n const haystack = `${segment} ${text}`.toLowerCase();\n return /\\b(?:button|link|cta)\\b/.test(haystack)\n && (\n /\\b(?:join|start|get started|sign up|signup|subscribe|buy|purchase|learn more|see how it works|continue)\\b/.test(haystack)\n || /[$€£]/.test(text)\n );\n}\n\nfunction buildAmbiguousRoleSelector(text: string, preferredRole: 'button' | 'link'): string {\n const primary = buildRoleSelector(preferredRole, text);\n const alternate = buildRoleSelector(preferredRole === 'button' ? 'link' : 'button', text);\n return `${primary}.or(page.${alternate})`;\n}\n\nfunction buildRoleSelector(role: 'button' | 'link' | 'heading', text: string): string {\n const safeRegex = text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return `getByRole('${role}', { name: /${safeRegex}/i })`;\n}\n\nfunction buildFallbackSelector(text: string, segment: string): string {\n if (/\\bbutton\\b/.test(segment)) return buildRoleSelector('button', text);\n if (/\\blink\\b/.test(segment)) return buildRoleSelector('link', text);\n if (/\\b(?:title|heading)\\b/.test(segment)) return buildRoleSelector('heading', text);\n return `getByText(${JSON.stringify(text)})`;\n}\n\nfunction buildAudioSummary(feature: string, scenarios: AnalysisScenario[]): string {\n return `We finished validating ${feature || 'the captured page'} with ${scenarios.length} evidence-backed scenario${scenarios.length === 1 ? '' : 's'}.`;\n}\n\nfunction normalizeTag(value: string): string {\n const cleaned = String(value ?? '').trim().replace(/^@+/, '');\n return cleaned ? `@${cleaned}` : '@ui';\n}\n\nfunction detectAuthElements(elementMap: ElementMap): AuthElements {\n const usernameInput = elementMap.elements.find((element) => (\n element.category === 'input' &&\n /user(name)?|email|login/.test(`${element.name ?? ''} ${String(element.attributes.label ?? '')} ${String(element.attributes.name ?? '')}`.toLowerCase())\n ));\n const passwordInput = elementMap.elements.find((element) => (\n element.category === 'input' && String(element.attributes.type ?? '').toLowerCase() === 'password'\n ));\n const submitButton = elementMap.elements.find((element) => (\n element.category === 'button' && /login|log in|sign in|submit|continue/.test((element.name ?? '').toLowerCase())\n )) ?? elementMap.elements.find((element) => element.category === 'button');\n const heading = elementMap.elements.find((element) => (\n element.category === 'heading' && /login|sign in|auth/.test((element.name ?? '').toLowerCase())\n )) ?? elementMap.elements.find((element) => element.category === 'heading');\n\n return { usernameInput, passwordInput, submitButton, heading };\n}\n\nfunction findAlertElement(elementMap: ElementMap): CapturedElement | undefined {\n return elementMap.elements.find((element) => (\n element.role === 'alert' ||\n element.category === 'status' ||\n String(element.attributes.role ?? '').toLowerCase() === 'alert'\n ));\n}\n\nfunction deriveSuccessUrlPattern(elementMap: ElementMap, normalizedFeature: string): string {\n const explicitPath =\n normalizedFeature.match(/\\/[a-z0-9/_-]+/i)?.[0] ??\n (/\\bsecure area\\b/.test(normalizedFeature) ? '/secure' : undefined);\n if (explicitPath) {\n return explicitPath\n .replace(/^\\/+/, '')\n .split('/')\n .map(escapeForRegex)\n .join('\\\\/');\n }\n\n const authLink = elementMap.elements.find((element) => {\n if (element.category !== 'link') return false;\n const href = String(element.attributes.href ?? '');\n const label = `${element.name ?? ''} ${href}`.toLowerCase();\n return /\\b(secure|dashboard|home|app)\\b/.test(label);\n });\n\n const href = String(authLink?.attributes.href ?? '');\n if (href.startsWith('/')) {\n return href\n .replace(/^\\/+/, '')\n .split('/')\n .map(escapeForRegex)\n .join('\\\\/');\n }\n\n return 'secure|dashboard|home|app';\n}\n\nfunction buildDeterministicAnalysis(\n elementMap: ElementMap,\n requestedFeature: string,\n): AnalysisResult {\n const intentProfile = buildIntentProfile(requestedFeature);\n const suggestedPrefix = inferSuggestedPrefix({\n featureText: requestedFeature,\n url: elementMap.url,\n }).toUpperCase();\n const authElements = detectAuthElements(elementMap);\n\n let scenarios =\n intentProfile.mode === 'count'\n ? buildCountScenarios(elementMap, requestedFeature, suggestedPrefix)\n : intentProfile.mode === 'presence'\n ? buildPresenceOnlyScenarios(elementMap, requestedFeature, suggestedPrefix)\n : (intentProfile.mode === 'auth' || intentProfile.mode === 'form')\n ? buildAuthFallbackScenarios(elementMap, suggestedPrefix, authElements, requestedFeature)\n : buildFallbackScenariosForFeature(elementMap, suggestedPrefix, requestedFeature);\n\n if (scenarios.length === 0 && (authElements.usernameInput || authElements.passwordInput || authElements.submitButton)) {\n scenarios = buildAuthFallbackScenarios(elementMap, suggestedPrefix, authElements, requestedFeature);\n }\n if (scenarios.length === 0) {\n scenarios = buildFallbackScenariosForFeature(elementMap, suggestedPrefix, requestedFeature);\n }\n\n const finalScenarios = scenarios.slice(0, intentProfile.maxScenarios);\n\n return {\n url: elementMap.url,\n feature: requestedFeature,\n suggestedPrefix,\n scenarios: finalScenarios,\n analysisNotes: 'Generated deterministic capture-backed scenarios because LLM analysis was unavailable.',\n audioSummary: buildAudioSummary(requestedFeature, finalScenarios),\n };\n}\n\nfunction shortErrorMessage(error: unknown): string {\n return String((error as Error | undefined)?.message ?? error ?? 'Unknown error').split('\\n')[0];\n}\n\nfunction shouldUseAuthFallback(\n authElements: AuthElements,\n scenarios: AnalysisScenario[],\n intentProfile: IntentProfile,\n): boolean {\n if (intentProfile.mode !== 'auth' && intentProfile.mode !== 'form') return false;\n if (!authElements.usernameInput || !authElements.passwordInput || !authElements.submitButton) return false;\n if (scenarios.length === 0) return true;\n\n const hasCredentialEntry = scenarios.some((scenario) => {\n const filledSelectors = new Set(\n scenario.steps\n .filter((step) => step.action === 'fill')\n .map((step) => step.selector),\n );\n\n return filledSelectors.has(authElements.usernameInput!.selector) && filledSelectors.has(authElements.passwordInput!.selector);\n });\n\n const hasBrokenLocatorWrapper = scenarios.some((scenario) => (\n scenario.assertions.some((assertion) => /page\\.locator\\((['\"])(getBy|locator\\()/i.test(assertion.playwright))\n ));\n\n return hasBrokenLocatorWrapper || !hasCredentialEntry;\n}\n\nfunction defaultStepHuman(action: AnalysisStep['action'], selector: string, value: string): string {\n if (action === 'navigate') return `Navigate to ${value || 'the page'}`;\n if (action === 'fill') return buildFillHuman(`Fill the field ${selector}`, selector, value);\n if (action === 'click') return `Click ${selector}`;\n if (action === 'select') return `Select ${value} in ${selector}`;\n if (action === 'check') return `Check ${selector}`;\n if (action === 'keyboard') return `Press ${value}`;\n return `Interact with ${selector}`;\n}\n\nfunction normalizeStepHuman(\n human: string,\n action: AnalysisStep['action'],\n selector: string,\n value: string,\n): string {\n if (action !== 'fill' && action !== 'select') return human;\n if (!value) return human;\n const explicitTemplate = /\\$\\{CT_VAR_[A-Z0-9_]+\\}/.test(human);\n const quotedValue = human.match(/\\bwith\\s+['\"`]([^'\"`]+)['\"`]/i)?.[1];\n if (explicitTemplate) return human;\n if (quotedValue && !isGenericFillValue(quotedValue)) return human;\n const rewrittenBase = human.replace(/\\s+with\\s+['\"`][^'\"`]+['\"`]\\s*$/i, '').trim() || human;\n return buildFillHuman(rewrittenBase, selector, value);\n}\n\nfunction pickCountedElements(elementMap: ElementMap, normalizedFeature: string): CapturedElement[] {\n const category =\n /\\bbutton/.test(normalizedFeature) ? 'button'\n : /\\blink/.test(normalizedFeature) ? 'link'\n : /\\bheading|title/.test(normalizedFeature) ? 'heading'\n : /\\binput|field|textbox|text box/.test(normalizedFeature) ? 'input'\n : undefined;\n\n if (category) {\n return elementMap.elements.filter((element) => element.category === category);\n }\n\n return elementMap.elements.filter((element) => (\n element.category === 'button' || element.category === 'link' || element.category === 'input'\n ));\n}\n\nfunction countSelectorForFeature(normalizedFeature: string, elements: CapturedElement[]): string {\n if (/\\bbutton/.test(normalizedFeature)) return `getByRole('button')`;\n if (/\\blink/.test(normalizedFeature)) return `getByRole('link')`;\n if (/\\bheading|title/.test(normalizedFeature)) return `getByRole('heading')`;\n if (/\\binput|field|textbox|text box/.test(normalizedFeature)) return `getByRole('textbox')`;\n return elements[0]?.selector ?? `locator('*')`;\n}\n\nfunction normalizePlaywrightAssertion(assertion: AnalysisAssertion): string {\n const repaired = scopeBareSelectorsInAssertion(unwrapWrappedSelectorAssertion(assertion.playwright));\n if (repaired) return ensureStatement(repaired);\n\n const built = buildPlaywrightAssertion(assertion);\n if (built) return built;\n\n return ensureStatement(assertion.playwright);\n}\n\nfunction unwrapWrappedSelectorAssertion(playwright: string): string {\n const trimmed = String(playwright ?? '').trim();\n if (!trimmed) return '';\n\n return trimmed.replace(\n /page\\.locator\\(([\"'])(getBy(?:Role|Text|Label|Placeholder|TestId)\\((?:\\\\.|(?!\\1).)*?\\)|locator\\((?:\\\\.|(?!\\1).)*?\\))\\1\\)/g,\n 'page.$2',\n );\n}\n\nfunction scopeBareSelectorsInAssertion(playwright: string): string {\n const trimmed = String(playwright ?? '').trim();\n if (!trimmed) return '';\n\n return trimmed.replace(\n /\\bexpect\\((getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\(/g,\n 'expect(page.$1(',\n );\n}\n\nfunction buildPlaywrightAssertion(assertion: AnalysisAssertion): string {\n if (assertion.selector === 'page') {\n if (assertion.type === 'url' && assertion.expected) {\n return `await expect(page).toHaveURL(${JSON.stringify(assertion.expected)});`;\n }\n return '';\n }\n\n const target = selectorTarget(assertion.selector);\n if (!target) return '';\n\n if (assertion.type === 'value' && assertion.expected) {\n return `await expect(${target}).toHaveValue(${JSON.stringify(assertion.expected)});`;\n }\n\n const combined = `${assertion.expected} ${assertion.human} ${assertion.playwright}`.toLowerCase();\n if (/hidden|not visible|no longer visible|disappear/.test(combined)) {\n return `await expect(${target}).not.toBeVisible();`;\n }\n\n return `await expect(${target}).toBeVisible();`;\n}\n\nfunction selectorTarget(selector: string): string {\n const trimmed = String(selector ?? '').trim();\n if (!trimmed || trimmed === 'page') return 'page';\n if (trimmed.startsWith('page.')) return trimmed;\n return `page.${trimmed}`;\n}\n\nfunction visibleAssertion(selector: string): string {\n return `await expect(${selectorTarget(selector)}).toBeVisible();`;\n}\n\nfunction valueAssertion(selector: string, value: string): string {\n return `await expect(${selectorTarget(selector)}).toHaveValue(${JSON.stringify(value)});`;\n}\n\nfunction inferAuthValue(element: CapturedElement, kind: 'username' | 'password'): string {\n if (kind === 'password') return resolveFieldRuntimeValue(element.selector, 'test-password');\n return resolveFieldRuntimeValue(element.selector, '');\n}\n\nfunction buildFillHuman(base: string, selector: string, runtimeValue: string): string {\n const displayValue = resolveFieldDisplayValue(selector, runtimeValue);\n return `${base} with '${displayValue}'`;\n}\n\nfunction resolveFieldRuntimeValue(selector: string, currentValue: string): string {\n if (currentValue && !isGenericFillValue(currentValue) && !extractCtVarTemplate(currentValue)) {\n return currentValue;\n }\n\n const envKey = matchCtVarKey(selector);\n if (envKey && process.env[envKey]) {\n return String(process.env[envKey]);\n }\n\n return fallbackFieldValue(selector);\n}\n\nfunction resolveFieldDisplayValue(selector: string, runtimeValue: string): string {\n const envKey = matchCtVarKey(selector);\n if (envKey) return `\\${${envKey}}`;\n return runtimeValue;\n}\n\nfunction matchCtVarKey(selectorOrText: string): string | undefined {\n const haystack = selectorOrText.toLowerCase();\n const preferred =\n /\\bemail\\b/.test(haystack) ? 'CT_VAR_EMAIL'\n : /\\bpassword\\b/.test(haystack) ? 'CT_VAR_PASSWORD'\n : /\\bsearch\\b/.test(haystack) ? 'CT_VAR_SEARCH'\n : /\\bphone|tel\\b/.test(haystack) ? 'CT_VAR_PHONE'\n : /\\bname\\b/.test(haystack) ? 'CT_VAR_NAME'\n : /\\buser(?:name)?|login\\b/.test(haystack) ? 'CT_VAR_USERNAME'\n : undefined;\n if (preferred && process.env[preferred] !== undefined) return preferred;\n return getAvailableCtVarKeys().find((key) => new RegExp(key.replace(/^CT_VAR_/, '').toLowerCase()).test(haystack));\n}\n\nfunction fallbackFieldValue(selectorOrText: string): string {\n const haystack = selectorOrText.toLowerCase();\n if (/\\bemail\\b/.test(haystack)) return 'test-email@example.com';\n if (/\\bpassword\\b/.test(haystack)) return 'test-password';\n if (/\\bsearch\\b/.test(haystack)) return 'test-search';\n if (/\\bphone|tel\\b/.test(haystack)) return 'test-phone';\n if (/\\bname\\b/.test(haystack) && !/\\buser(?:name)?\\b/.test(haystack)) return 'test-name';\n if (/\\buser(?:name)?|login\\b/.test(haystack)) return 'test-username';\n return 'test-input';\n}\n\nfunction isGenericFillValue(value: string): boolean {\n return /^(?:value|text|input|option|selection|selected value|default)$/i.test(value.trim());\n}\n\nfunction extractCtVarTemplate(value: string): string | undefined {\n return value.match(/^\\$\\{(CT_VAR_[A-Z0-9_]+)\\}$/)?.[1];\n}\n\nfunction isAllowedSelector(selector: string, selectors: Set<string>): boolean {\n if (selector === 'page') return true;\n if (selectors.has(selector)) return true;\n if (/\\.or\\(page\\.(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\(/.test(selector)) {\n const primary = selector.replace(/\\.or\\(page\\.(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\([\\s\\S]*\\)\\)\\s*$/, '');\n return isAllowedSelector(primary, selectors);\n }\n\n return /^(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId)\\(/.test(selector)\n || /^locator\\((['\"])(#.+?)\\1\\)$/.test(selector);\n}\n\nfunction ensureStatement(value: string): string {\n const trimmed = String(value ?? '').trim();\n if (!trimmed) return '';\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n}\n\nfunction ensureNavigateStep(steps: AnalysisStep[], url: string): AnalysisStep[] {\n if (!url || steps.length === 0) return steps;\n if (steps.some((step) => step.action === 'navigate')) return steps;\n\n return [\n {\n action: 'navigate',\n selector: 'page',\n value: url,\n human: `Navigate to ${url}`,\n },\n ...steps,\n ];\n}\n\nfunction log(verbose: boolean, message: string): void {\n if (verbose) console.log(message);\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { AnalysisResult } from './analyse.js';\nimport type { ElementMap } from './capture.js';\n\nexport function printCaptureReport(elementMap: ElementMap, analysis?: AnalysisResult | null): void {\n console.log('');\n console.log('='.repeat(60));\n console.log('CementicTest Capture Report');\n console.log('='.repeat(60));\n console.log(`URL: ${elementMap.url}`);\n console.log(`Title: ${elementMap.title}`);\n console.log(`Captured: ${elementMap.timestamp} (${elementMap.mode})`);\n console.log('');\n console.log('Elements:');\n\n for (const [category, count] of Object.entries(elementMap.summary.byCategory)) {\n console.log(` ${category}: ${count}`);\n }\n\n if (elementMap.warnings.length > 0) {\n console.log('');\n console.log('Warnings:');\n for (const warning of elementMap.warnings) {\n console.log(` - ${warning}`);\n }\n }\n\n if (analysis) {\n console.log('');\n console.log(`AI scenarios: ${analysis.scenarios.length}`);\n console.log(`Feature: ${analysis.feature}`);\n console.log(`Prefix: ${analysis.suggestedPrefix}`);\n }\n\n console.log('');\n}\n\nexport function saveCaptureJson(\n elementMap: ElementMap,\n analysis?: AnalysisResult | null,\n outputDir = '.cementic/capture',\n): string {\n mkdirSync(outputDir, { recursive: true });\n\n const fileName = `capture-${slugify(elementMap.url)}-${Date.now()}.json`;\n const filePath = join(outputDir, fileName);\n\n writeFileSync(filePath, JSON.stringify({\n _meta: {\n version: '0.2.16',\n generatedAt: new Date().toISOString(),\n tool: '@cementic/cementic-test',\n },\n elementMap,\n analysis: analysis ?? null,\n }, null, 2));\n\n return filePath;\n}\n\nexport function buildCasesMarkdown(analysis: AnalysisResult): string {\n const lines: string[] = [];\n\n for (const scenario of analysis.scenarios) {\n lines.push(`# ${scenario.id} — ${scenario.title} ${scenario.tags.map(normalizeTag).join(' ')}`.trim());\n lines.push(`<!-- ct:url ${analysis.url} -->`);\n lines.push(`<!-- ct:feature ${analysis.feature} -->`);\n lines.push(`<!-- ct:generated-by capture -->`);\n lines.push(`<!-- narrator: ${sanitizeComment(scenario.narrator)} -->`);\n lines.push(`<!-- code-level: ${scenario.codeLevel} -->`);\n lines.push('');\n lines.push('## Steps');\n\n scenario.steps.forEach((step, index) => {\n const hint = step.selector && step.selector !== 'page'\n ? ` <!-- selector: ${step.selector} -->`\n : '';\n lines.push(`${index + 1}. ${step.human}${hint}`);\n });\n\n lines.push('');\n lines.push('## Expected Results');\n\n scenario.assertions.forEach((assertion) => {\n const hint = assertion.playwright\n ? ` <!-- playwright: ${sanitizeComment(assertion.playwright)} -->`\n : '';\n lines.push(`- ${assertion.human}${hint}`);\n });\n\n lines.push('');\n lines.push('---');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nexport function saveCasesMarkdown(\n analysis: AnalysisResult,\n outputDir = 'cases',\n fileName?: string,\n): string {\n mkdirSync(outputDir, { recursive: true });\n\n const resolvedFileName = fileName ?? `${slugify(analysis.feature || analysis.url)}.md`;\n const filePath = join(outputDir, resolvedFileName);\n\n writeFileSync(filePath, buildCasesMarkdown(analysis));\n return filePath;\n}\n\nexport function saveSpecPreview(\n analysis: AnalysisResult,\n outputDir = 'tests/preview',\n): string | null {\n if (analysis.scenarios.length === 0) return null;\n\n mkdirSync(outputDir, { recursive: true });\n\n const fileName = `spec-preview-${slugify(analysis.url)}-${Date.now()}.spec.cjs`;\n const filePath = join(outputDir, fileName);\n const lines: string[] = [];\n\n lines.push('/**');\n lines.push(' * CementicTest Capture Preview');\n lines.push(` * Generated from: ${analysis.url}`);\n lines.push(` * Feature: ${analysis.feature}`);\n lines.push(' */');\n lines.push('');\n lines.push(`const { test, expect } = require('@playwright/test');`);\n lines.push('');\n\n for (const scenario of analysis.scenarios) {\n lines.push(`test(${JSON.stringify(`${scenario.id} — ${scenario.title}`)}, async ({ page }) => {`);\n for (const step of scenario.steps) {\n if (step.action === 'navigate') {\n lines.push(` await page.goto(${JSON.stringify(step.value)});`);\n continue;\n }\n\n if (step.selector === 'page') continue;\n const selector = `page.${step.selector}`;\n\n if (step.action === 'fill') lines.push(` await ${selector}.fill(${JSON.stringify(step.value)});`);\n if (step.action === 'click') lines.push(` await ${selector}.click();`);\n if (step.action === 'select') lines.push(` await ${selector}.selectOption(${JSON.stringify(step.value)});`);\n if (step.action === 'check') lines.push(` await ${selector}.check();`);\n if (step.action === 'keyboard') lines.push(` await page.keyboard.press(${JSON.stringify(step.value)});`);\n if (step.action === 'hover') lines.push(` await ${selector}.hover();`);\n }\n\n for (const assertion of scenario.assertions) {\n lines.push(` ${renderPreviewAssertion(assertion.playwright, assertion.human)}`);\n }\n\n lines.push('});');\n lines.push('');\n }\n\n writeFileSync(filePath, lines.join('\\n'));\n return filePath;\n}\n\nfunction slugify(value: string): string {\n return (value || 'capture')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase()\n .slice(0, 60);\n}\n\nfunction normalizeTag(value: string): string {\n const cleaned = String(value ?? '').trim();\n if (!cleaned) return '@ui';\n return cleaned.startsWith('@') ? cleaned : `@${cleaned}`;\n}\n\nfunction sanitizeComment(value: string): string {\n return String(value ?? '').replace(/-->/g, '-- >');\n}\n\nfunction ensureStatement(value: string): string {\n const trimmed = String(value ?? '').trim();\n if (!trimmed) return '// TODO: add assertion';\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n}\n\nfunction renderPreviewAssertion(playwright: string, human?: string): string {\n const statement = ensureStatement(playwright);\n const headingMatch = statement.match(/^await expect\\(page\\.getByRole\\((['\"])heading\\1\\)\\)\\.toBeVisible\\(\\);$/);\n const visibleSubject = String(human ?? '').match(/^(.+?) is visible$/)?.[1]?.trim();\n\n if (headingMatch && visibleSubject && !/main page heading/i.test(visibleSubject)) {\n return `await expect(page.getByRole(\"heading\", { name: ${JSON.stringify(visibleSubject)} })).toBeVisible();`;\n }\n\n return statement;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nexport function reportCmd() {\n const cmd = new Command('report')\n .description('Open the Playwright HTML report')\n .action(() => {\n console.log('📊 Opening Playwright HTML report...');\n \n const child = spawn(\n 'npx',\n ['playwright', 'show-report'],\n {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport function serveCmd() {\n const cmd = new Command('serve')\n .description('Serve the Allure report')\n .action(() => {\n console.log('📊 Serving Allure report...');\n\n // Try to find the local allure binary first (more reliable than global/npx sometimes)\n const localAllureBin = join(process.cwd(), 'node_modules', 'allure-commandline', 'bin', 'allure');\n \n let executable = 'npx';\n let args = ['allure', 'serve', './allure-results'];\n\n // If we can find the direct binary, use it (node node_modules/.../allure)\n // This bypasses the \"require('../')\" issue in the .bin wrapper\n if (existsSync(localAllureBin)) {\n executable = 'node';\n args = [localAllureBin, 'serve', './allure-results'];\n }\n\n console.log(`> ${executable} ${args.join(' ')}`);\n\n const child = spawn(\n executable,\n args,\n {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\n\nfunction runStep(cmd: string, args: string[], stepName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n console.log(`\\n🌊 Flow Step: ${stepName}`);\n console.log(`> ${cmd} ${args.join(' ')}`);\n\n const child = spawn(cmd, args, {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`${stepName} failed with exit code ${code}`));\n }\n });\n });\n}\n\nexport function flowCmd() {\n const cmd = new Command('flow')\n .description('End-to-end flow: Normalize -> Generate -> Run Tests')\n .argument('[casesDir]', 'Directory containing test cases', './cases')\n .option('--lang <lang>', 'Target language (ts|js)', 'ts')\n .option('--no-run', 'Skip running tests')\n .action(async (casesDir, opts) => {\n const cliBin = resolve(process.argv[1]); // The current CLI executable\n\n try {\n // 1. Normalize\n await runStep(process.execPath, [cliBin, 'normalize', casesDir], 'Normalize Cases');\n\n // 2. Generate\n await runStep(process.execPath, [cliBin, 'gen', '--lang', opts.lang], 'Generate Tests');\n\n // 3. Test (unless skipped)\n if (opts.run) {\n await runStep(process.execPath, [cliBin, 'test'], 'Run Playwright Tests');\n } else {\n console.log('\\n⏭️ Skipping test execution (--no-run)');\n }\n\n console.log('\\n✅ Flow completed successfully!');\n } catch (err: any) {\n console.error(`\\n❌ Flow failed: ${err.message}`);\n process.exit(1);\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst WORKFLOW_CONTENT = `name: Playwright Tests\non:\n push:\n branches: [ main, master ]\n pull_request:\n branches: [ main, master ]\njobs:\n test:\n timeout-minutes: 60\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: lts/*\n - name: Install dependencies\n run: npm ci\n - name: Install Playwright Browsers\n run: npx playwright install --with-deps\n - name: Run Playwright tests\n run: npx playwright test\n - uses: actions/upload-artifact@v4\n if: always()\n with:\n name: playwright-report\n path: playwright-report/\n retention-days: 30\n`;\n\nexport function ciCmd() {\n const cmd = new Command('ci')\n .description('Generate GitHub Actions workflow for CI')\n .action(() => {\n const githubDir = join(process.cwd(), '.github');\n const workflowsDir = join(githubDir, 'workflows');\n const workflowFile = join(workflowsDir, 'cementic.yml');\n\n console.log('🤖 Setting up CI/CD workflow...');\n\n if (!existsSync(workflowsDir)) {\n mkdirSync(workflowsDir, { recursive: true });\n console.log(`Created directory: ${workflowsDir}`);\n }\n\n if (existsSync(workflowFile)) {\n console.warn(`⚠️ Workflow file already exists at ${workflowFile}. Skipping.`);\n return;\n }\n\n writeFileSync(workflowFile, WORKFLOW_CONTENT.trim() + '\\n');\n console.log(`✅ CI workflow generated at: ${workflowFile}`);\n console.log('Next steps:');\n console.log('1. Commit and push the new file');\n console.log('2. Check the \"Actions\" tab in your GitHub repository');\n });\n\n return cmd;\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["Command","version","Command","readFileSync","mkdirSync","writeFileSync","statSync","join","resolve","Command","Command","mkdirSync","writeFileSync","join","RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE","ADVANCED_DOC_MAP","fetchDocContext","callAnthropic","callOpenAiCompatible","getAvailableCtVarKeys","href","mkdirSync","writeFileSync","join","normalizeTag","ensureStatement","slugify","output","mkdirSync","join","writeFileSync","Command","Command","spawn","Command","spawn","existsSync","join","Command","spawn","resolve","Command","mkdirSync","writeFileSync","existsSync","join","require","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/new.ts","../src/commands/normalize.ts","../src/commands/test.ts","../src/commands/tc.ts","../src/core/prefix.ts","../src/core/llm-provider.ts","../src/core/llm.ts","../src/core/analyse.ts","../src/core/report.ts","../src/commands/report.ts","../src/commands/serve.ts","../src/commands/flow.ts","../src/commands/ci.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { newCmd } from './commands/new.js';\nimport { normalizeCmd } from './commands/normalize.js';\nimport { genCmd } from './commands/gen.js';\nimport { testCmd } from './commands/test.js';\nimport { tcCmd } from './commands/tc.js';\nimport { reportCmd } from './commands/report.js';\nimport { serveCmd } from './commands/serve.js';\nimport { flowCmd } from './commands/flow.js';\nimport { ciCmd } from './commands/ci.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json');\n\nconst program = new Command();\nprogram\n .name('ct')\n .description('CementicTest CLI: cases → normalized → POM tests → Playwright')\n .version(version);\n\nprogram.addCommand(newCmd());\nprogram.addCommand(normalizeCmd());\nprogram.addCommand(genCmd());\nprogram.addCommand(testCmd());\nprogram.addCommand(tcCmd());\nprogram.addCommand(reportCmd());\nprogram.addCommand(serveCmd());\nprogram.addCommand(flowCmd());\nprogram.addCommand(ciCmd());\n\nprogram.parseAsync(process.argv);","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync, existsSync, readFileSync, cpSync, readdirSync, statSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { dirname } from 'node:path';\nimport { platform, release } from 'node:os';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst LEGACY_MACOS_DARWIN_MAJOR = 23;\nconst LEGACY_PLAYWRIGHT_VERSION = '^1.48.2';\nconst LEGACY_ALLURE_VERSION = '^2.15.1';\n\ntype BrowserInstallProfile = 'auto' | 'all' | 'chromium';\n\ntype BootstrapPlan = {\n browserInstallArgs: string[];\n browserProfile: Exclude<BrowserInstallProfile, 'auto'>;\n isLegacyMacOs: boolean;\n packageVersionOverrides: Record<string, string>;\n reason?: string;\n};\n\nfunction resolveTemplatePath(templateDir: string): string | undefined {\n const candidates = [\n resolve(__dirname, `templates/${templateDir}`),\n resolve(__dirname, `../templates/${templateDir}`),\n resolve(__dirname, `../../templates/${templateDir}`),\n resolve(process.cwd(), `templates/${templateDir}`),\n ];\n\n return candidates.find(candidate => existsSync(candidate));\n}\n\nfunction getHostPlatform(env: NodeJS.ProcessEnv = process.env): string {\n return (env.CT_OS_PLATFORM_OVERRIDE ?? platform()).trim().toLowerCase();\n}\n\nfunction getHostRelease(env: NodeJS.ProcessEnv = process.env): string {\n return (env.CT_OS_RELEASE_OVERRIDE ?? release()).trim();\n}\n\nfunction isLegacyMacOs(env: NodeJS.ProcessEnv = process.env): boolean {\n if (getHostPlatform(env) !== 'darwin') return false;\n\n const majorVersion = parseInt(getHostRelease(env).split('.')[0], 10);\n return Number.isFinite(majorVersion) && majorVersion < LEGACY_MACOS_DARWIN_MAJOR;\n}\n\nfunction resolveBrowserInstallProfile(raw?: string): BrowserInstallProfile {\n const profile = String(raw ?? 'auto').trim().toLowerCase();\n if (profile === 'auto' || profile === 'all' || profile === 'chromium') return profile;\n\n console.error(`❌ Unsupported browser install profile \"${raw}\". Use \"auto\", \"all\", or \"chromium\".`);\n process.exit(1);\n}\n\nfunction resolveBootstrapPlan(\n browserProfile: BrowserInstallProfile,\n env: NodeJS.ProcessEnv = process.env,\n): BootstrapPlan {\n const legacyMacOs = isLegacyMacOs(env);\n const resolvedProfile =\n browserProfile === 'auto'\n ? (legacyMacOs ? 'chromium' : 'all')\n : browserProfile;\n\n return {\n browserInstallArgs: resolvedProfile === 'chromium' ? ['playwright', 'install', 'chromium'] : ['playwright', 'install'],\n browserProfile: resolvedProfile,\n isLegacyMacOs: legacyMacOs,\n packageVersionOverrides: legacyMacOs\n ? {\n '@playwright/test': LEGACY_PLAYWRIGHT_VERSION,\n 'allure-playwright': LEGACY_ALLURE_VERSION,\n }\n : {},\n reason: legacyMacOs\n ? 'Detected macOS 13 or older. Using a legacy-compatible Playwright toolchain and Chromium-only browser install.'\n : undefined,\n };\n}\n\nfunction applyPackageVersionOverrides(projectPath: string, versionOverrides: Record<string, string>): void {\n if (Object.keys(versionOverrides).length === 0) return;\n\n const pkgJsonPath = join(projectPath, 'package.json');\n if (!existsSync(pkgJsonPath)) return;\n\n try {\n const pkgContent = readFileSync(pkgJsonPath, 'utf-8');\n const pkg = JSON.parse(pkgContent);\n const devDependencies = pkg.devDependencies ?? {};\n\n let changed = false;\n for (const [name, version] of Object.entries(versionOverrides)) {\n if (typeof devDependencies[name] !== 'string') continue;\n devDependencies[name] = version;\n changed = true;\n }\n\n if (!changed) return;\n\n pkg.devDependencies = devDependencies;\n writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2));\n console.log('✅ Applied compatibility dependency pins for this machine.');\n } catch (err) {\n console.warn('⚠️ Failed to adjust package.json for OS compatibility:', err);\n }\n}\n\nexport function newCmd() {\n const cmd = new Command('new')\n .arguments('<projectName>')\n .description('Scaffold a new CementicTest + Playwright project from scratch')\n .addHelpText('after', `\nExamples:\n $ ct new my-awesome-test-suite\n $ ct new e2e-ts --lang ts\n $ ct new e2e-tests --no-browsers\n`)\n .option('--mode <mode>', 'greenfield|enhance', 'greenfield')\n .option('--lang <lang>', 'Scaffold language (js|ts)', 'js')\n .option('--browser-set <profile>', 'Browser install profile (auto|all|chromium)', 'auto')\n .option('--no-browsers', 'do not run \"npx playwright install\" during setup')\n .action((projectName: string, opts) => {\n const mode = String(opts.mode ?? 'greenfield').trim().toLowerCase();\n if (mode !== 'greenfield') {\n console.error(`❌ Unsupported scaffold mode \"${opts.mode}\". Only \"greenfield\" is currently implemented.`);\n process.exit(1);\n }\n const browserInstallProfile = resolveBrowserInstallProfile(opts.browserSet);\n const bootstrapPlan = resolveBootstrapPlan(browserInstallProfile);\n\n const root = process.cwd();\n const projectPath = join(root, projectName);\n\n console.log(`🚀 Initializing new CementicTest project in ${projectName}...`);\n\n // 1. Create project directory\n if (existsSync(projectPath)) {\n console.error(`❌ Directory ${projectName} already exists.`);\n process.exit(1);\n }\n mkdirSync(projectPath, { recursive: true });\n\n const lang = opts.lang === 'ts' ? 'ts' : 'js';\n const templateDir = lang === 'ts' ? 'student-framework-ts' : 'student-framework';\n const templatePath = resolveTemplatePath(templateDir);\n\n if (!templatePath) {\n console.error(`❌ Could not locate template \"${templateDir}\"`);\n console.error('Please ensure the package is built correctly with templates included.');\n process.exit(1);\n }\n\n console.log(`📦 Copying template from ${templatePath}...`);\n \n // Recursive copy function\n function copyRecursive(src: string, dest: string) {\n if (statSync(src).isDirectory()) {\n mkdirSync(dest, { recursive: true });\n readdirSync(src).forEach(child => {\n copyRecursive(join(src, child), join(dest, child));\n });\n } else {\n cpSync(src, dest);\n }\n }\n\n copyRecursive(templatePath, projectPath);\n\n if (bootstrapPlan.reason) {\n console.log(`🍎 ${bootstrapPlan.reason}`);\n }\n applyPackageVersionOverrides(projectPath, bootstrapPlan.packageVersionOverrides);\n\n // 3. Initialize git\n try {\n execSync('git init', { cwd: projectPath, stdio: 'ignore' });\n // Create .gitignore if not exists (template should have it, but just in case)\n const gitignorePath = join(projectPath, '.gitignore');\n if (!existsSync(gitignorePath)) {\n writeFileSync(gitignorePath, 'node_modules\\n.env\\ntest-results\\nplaywright-report\\n.cementic\\n');\n }\n } catch (e) {\n console.warn('⚠️ Failed to initialize git repository.');\n }\n\n // 4. Install dependencies\n console.log('📦 Installing dependencies...');\n let dependenciesInstalled = false;\n try {\n execSync('npm install', { cwd: projectPath, stdio: 'inherit' });\n dependenciesInstalled = true;\n } catch (e) {\n console.error('❌ Failed to install dependencies. Please run \"npm install\" manually.');\n }\n\n // 5. Install browsers (optional)\n // Commander maps --no-browsers to opts.browsers = false\n if (opts.browsers !== false && dependenciesInstalled) {\n console.log('🌐 Installing Playwright browsers...');\n try {\n const installCommand = `npx ${bootstrapPlan.browserInstallArgs.join(' ')}`;\n if (bootstrapPlan.browserProfile === 'chromium' && bootstrapPlan.isLegacyMacOs) {\n console.log('⚠️ WebKit is not supported on this macOS version. Installing Chromium only...');\n } else if (bootstrapPlan.browserProfile === 'chromium') {\n console.log('ℹ️ Installing Chromium only because --browser-set chromium was requested.');\n }\n execSync(installCommand, { cwd: projectPath, stdio: 'inherit' });\n console.log(\n bootstrapPlan.browserProfile === 'chromium'\n ? '✅ Chromium installed successfully.'\n : '✅ Playwright browsers installed successfully.',\n );\n } catch (e) {\n console.warn('⚠️ Browser installation did not complete. You can finish setup with:');\n console.warn(` npx ${bootstrapPlan.browserInstallArgs.join(' ')}`);\n }\n }\n\n console.log(`\\n✅ Project ${projectName} created successfully!`);\n console.log(`\\nTo get started:\\n`);\n console.log(` cd ${projectName}`);\n console.log(` npx playwright test`);\n console.log(`\\nHappy testing! 🧪`);\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport fg from 'fast-glob';\nimport { readFileSync, mkdirSync, writeFileSync, statSync } from 'node:fs';\nimport { join, basename, resolve } from 'node:path';\n\ntype NormalizedCase = {\n id?: string;\n title: string;\n tags?: string[];\n steps: string[];\n step_hints?: Array<{ selector?: string }>;\n expected: string[];\n assertion_hints?: Array<{ playwright?: string }>;\n needs_review: boolean;\n review_reasons: string[];\n source: string;\n url?: string;\n};\n\n/** Grab @tags from the title line */\nfunction parseTags(title: string): { clean: string; tags: string[] } {\n const tags = Array.from(title.matchAll(/@([\\w-]+)/g)).map((m) => m[1]);\n const clean = title.replace(/@[\\w-]+/g, '').trim();\n return { clean, tags };\n}\n\n/** Try to extract an ID prefix like AUTH-001 from the title */\nfunction parseId(title: string): string | undefined {\n const m = title.match(/\\b([A-Z]+-\\d+)\\b/);\n return m?.[1];\n}\n\nfunction stripIdPrefixFromTitle(title: string, id?: string): string {\n if (!id) return title.trim();\n return title.replace(new RegExp(`^${id}\\\\s*[—\\\\-–:]\\\\s*`), '').trim();\n}\n\n/** Split a markdown file into case blocks by top-level \"# \" headings */\nfunction splitCasesByHeading(fileText: string): Array<{ titleLine: string; body: string }> {\n const lines = fileText.split(/\\r?\\n/);\n const blocks: Array<{ titleLine: string; body: string }> = [];\n let currentTitle: string | null = null;\n let buf: string[] = [];\n\n const flush = () => {\n if (currentTitle !== null) {\n blocks.push({ titleLine: currentTitle, body: buf.join('\\n') });\n }\n buf = [];\n };\n\n for (const line of lines) {\n const h1 = line.match(/^\\s*#\\s+(.+)$/); // \"# Title\"\n if (h1) {\n if (currentTitle !== null) flush();\n currentTitle = h1[1].trim();\n } else {\n buf.push(line);\n }\n }\n if (currentTitle !== null) flush();\n\n // If no H1 at all, treat whole file as one case (first non-empty line is title).\n if (blocks.length === 0) {\n const first = lines.find((l) => l.trim());\n const title = first?.replace(/^#\\s*/, '').trim() || 'Untitled';\n return [{ titleLine: title, body: lines.join('\\n') }];\n }\n return blocks;\n}\n\n/** From a case body, extract Steps and Expected sections */\nfunction extractSections(body: string): {\n steps: string[];\n stepHints: Array<{ selector?: string }>;\n expected: string[];\n assertionHints: Array<{ playwright?: string }>;\n} {\n // Find sections by H2 headings\n // Supports: \"## Steps\", \"## Expected\", \"## Expected Results\"\n const sectionRegex = /^\\s*##\\s*(.+?)\\s*$/gim;\n const sections: Record<string, string> = {};\n let match: RegExpExecArray | null;\n const indices: Array<{ name: string; index: number }> = [];\n\n while ((match = sectionRegex.exec(body))) {\n indices.push({ name: match[1].toLowerCase(), index: match.index });\n }\n\n // Add end sentinel\n indices.push({ name: '__END__', index: body.length });\n\n for (let i = 0; i < indices.length - 1; i++) {\n const name = indices[i].name;\n const slice = body.slice(indices[i].index, indices[i + 1].index);\n sections[name] = slice;\n }\n\n const stepsBlock =\n sections['steps'] ??\n ''; // if absent, we’ll infer from bullets later\n\n const expectedBlock =\n sections['expected'] ??\n sections['expected results'] ??\n sections['then'] ??\n '';\n\n const bullet = /^\\s*(?:\\d+\\.|[-*])\\s+(.+)$/gm;\n\n const parsedSteps = Array.from(stepsBlock.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'selector'));\n const steps = parsedSteps.map((entry) => entry.text);\n const stepHints = parsedSteps.map((entry) => ({ selector: entry.hint }));\n\n // Fallback: if no dedicated steps section, collect bullets until a new H2\n if (steps.length === 0) {\n const alt = Array.from(body.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'selector'));\n // Heuristic: take the first bullet run in the body\n steps.push(...alt.map((entry) => entry.text));\n stepHints.push(...alt.map((entry) => ({ selector: entry.hint })));\n }\n\n const parsedExpected = Array.from(expectedBlock.matchAll(bullet)).map((m) => parseHintedLine(m[1].trim(), 'playwright'));\n const expectedLines = parsedExpected.map((entry) => entry.text);\n const assertionHints = parsedExpected.map((entry) => ({ playwright: entry.hint }));\n\n // Fallback: lines that start with Expected/Then/Verify/Assert in the whole body\n if (expectedLines.length === 0) {\n const exp = Array.from(\n body.matchAll(/^\\s*(?:Expected|Then|Verify|Assert)[^\\n]*:?[\\s-]*(.+)$/gim)\n ).map((m) => parseHintedLine(m[1].trim(), 'playwright'));\n expectedLines.push(...exp.map((entry) => entry.text));\n assertionHints.push(...exp.map((entry) => ({ playwright: entry.hint })));\n }\n\n return { steps, stepHints, expected: expectedLines, assertionHints };\n}\n\nfunction extractUrlMetadata(body: string): string | undefined {\n const match = body.match(/<!--\\s*ct:url\\s+(https?:\\/\\/[^\\s>]+)\\s*-->/i);\n return match?.[1];\n}\n\nfunction stripCtMetadata(body: string): string {\n return body.replace(/^\\s*<!--\\s*ct:url\\s+https?:\\/\\/[^\\s>]+\\s*-->\\s*\\n?/im, '');\n}\n\nfunction parseHintedLine(\n value: string,\n hintType: 'selector' | 'playwright',\n): { text: string; hint?: string } {\n const match = value.match(new RegExp(`^(.*?)\\\\s*<!--\\\\s*${hintType}:\\\\s*([\\\\s\\\\S]*?)\\\\s*-->\\\\s*$`, 'i'));\n if (!match) return { text: value.trim() };\n return {\n text: match[1].trim(),\n hint: match[2].trim() || undefined,\n };\n}\n\nfunction extractUrlFromSteps(steps: string[]): string | undefined {\n for (const step of steps) {\n const match = step.match(/https?:\\/\\/[^\\s'\"]+/i);\n if (match) return match[0];\n }\n return undefined;\n}\n\n/** Build one normalized case from a title line + body */\nfunction normalizeOne(titleLine: string, body: string, source: string): NormalizedCase {\n const { clean, tags } = parseTags(titleLine);\n const id = parseId(clean);\n const metadataUrl = extractUrlMetadata(body);\n const cleanBody = stripCtMetadata(body);\n const { steps, stepHints, expected, assertionHints } = extractSections(cleanBody);\n const reviewReasons: string[] = [];\n\n if (steps.length === 0) reviewReasons.push('No steps section or bullets were parsed');\n if (expected.length === 0) reviewReasons.push('No expected results section or assertions were parsed');\n\n return {\n id,\n title: stripIdPrefixFromTitle(clean, id),\n tags: tags.length ? tags : undefined,\n steps,\n step_hints: stepHints.some(hint => hint.selector) ? stepHints : undefined,\n expected,\n assertion_hints: assertionHints.some(hint => hint.playwright) ? assertionHints : undefined,\n needs_review: reviewReasons.length > 0,\n review_reasons: reviewReasons,\n source,\n url: metadataUrl ?? extractUrlFromSteps(steps),\n };\n}\n\n/** ===== Commander command ===== */\nexport function normalizeCmd() {\n const cmd = new Command('normalize')\n .argument('<path>', 'Input directory or file pattern containing test cases (Markdown, Text, CSV)')\n .description('Convert human-readable test cases into machine-readable JSON format')\n .addHelpText('after', `\nExamples:\n $ ct normalize ./cases\n $ ct normalize \"cases/**/*.md\"\n $ ct normalize ./cases --and-gen --lang ts (Normalize and generate tests in one go)\n`)\n .option('--report', 'Generate a summary report of the normalization process', true)\n .option('--and-gen', 'Automatically run test generation after normalization', false)\n .option('--lang <lang>', 'Target language for generation (ts|js) when using --and-gen', 'ts')\n .action(async (inputPath: string, opts: { report?: boolean; andGen?: boolean; lang?: string }) => {\n // Accept directory OR glob\n let patterns: string[] = [];\n try {\n const abs = resolve(inputPath);\n if (statSync(abs).isDirectory()) {\n const base = inputPath.replace(/\\/$/, '');\n patterns = [`${base}/**/*.{md,markdown,txt,feature,csv,json}`];\n } else {\n patterns = [inputPath];\n }\n } catch {\n patterns = [inputPath];\n }\n\n const files = await fg(patterns, { dot: false, onlyFiles: true });\n if (files.length === 0) {\n console.error(`No files found for: ${inputPath}`);\n process.exit(2);\n }\n\n const outDir = '.cementic/normalized';\n mkdirSync(outDir, { recursive: true });\n\n const index = {\n summary: { total: 0, parsed: 0, withWarnings: 0 },\n cases: [] as Array<{ file: string; normalized: string; status: string }>\n };\n\n for (const f of files) {\n const content = readFileSync(f, 'utf8');\n\n // Split into multiple cases by \"# \"\n const blocks = splitCasesByHeading(content);\n for (const block of blocks) {\n const norm = normalizeOne(block.titleLine, block.body, f);\n\n // filename: <stem>.<ID or sanitized-title>.json\n const stem = basename(f).replace(/\\.[^/.]+$/, '');\n const suffix = (norm.id || norm.title).replace(/[^\\w-]+/g, '-');\n const outFile = join(outDir, `${stem}.${suffix}.json`);\n\n writeFileSync(outFile, JSON.stringify(norm, null, 2));\n\n index.summary.total++;\n index.summary.parsed++;\n if (norm.needs_review) index.summary.withWarnings++;\n index.cases.push({ file: f, normalized: outFile, status: norm.needs_review ? 'warning' : 'ok' });\n }\n }\n\n writeFileSync(join(outDir, '_index.json'), JSON.stringify(index, null, 2));\n\n if (opts.report !== false) {\n const lines = [\n '# Normalize Report',\n '',\n `Total cases: ${index.summary.total} | Parsed: ${index.summary.parsed} | With warnings: ${index.summary.withWarnings}`,\n '',\n '| Source File | Normalized JSON | Status |',\n '|-------------|-----------------|--------|',\n ...index.cases.map(c => `| ${c.file} | ${c.normalized} | ${c.status} |`)\n ];\n mkdirSync('.cementic/reports', { recursive: true });\n writeFileSync('.cementic/reports/normalize-report.md', lines.join('\\n'));\n }\n\n console.log(`✅ Normalized ${index.summary.parsed} case(s). Output → .cementic/normalized/`);\n\n if (opts.andGen) {\n const { gen } = await import('./gen.js');\n await gen({ lang: opts.lang || 'ts', out: 'tests/generated' });\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nexport function testCmd() {\n const cmd = new Command('test')\n .description('Run Playwright tests via \"npx playwright test\"')\n .allowUnknownOption(true)\n .allowExcessArguments(true)\n .argument('[...pwArgs]', 'Arguments to pass through to Playwright')\n .action((pwArgs: string[] = []) => {\n const child = spawn(\n 'npx',\n ['playwright', 'test', ...pwArgs],\n {\n stdio: 'inherit',\n shell: process.platform === 'win32', // needed for Windows\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin as input, stdout as output } from 'node:process';\nimport { inferPrefix } from '../core/prefix.js';\nimport { generateTcMarkdownWithAi } from '../core/llm.js';\nimport { analyseElements } from '../core/analyse.js';\nimport { captureElements, formatCaptureFailure, toPageSummary } from '../core/capture.js';\nimport {\n printCaptureReport,\n saveCaptureJson,\n saveCasesMarkdown,\n saveSpecPreview,\n} from '../core/report.js';\n\nfunction slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'tc'\n );\n}\n\nfunction injectUrlMetadata(markdown: string, url?: string): string {\n if (!url || /<!--\\s*ct:url\\s+/i.test(markdown)) return markdown;\n\n const lines = markdown.split('\\n');\n const output: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n output.push(lines[i]);\n if (/^\\s*#\\s+/.test(lines[i])) {\n output.push(`<!-- ct:url ${url} -->`);\n }\n }\n\n return output.join('\\n');\n}\n\nfunction buildManualCasesMarkdown(opts: {\n prefix: string;\n feature: string;\n url?: string;\n numCases: number;\n startIndex?: number;\n}): string {\n const { prefix, feature, url, numCases } = opts;\n const startIndex = opts.startIndex ?? 1;\n const lines: string[] = [];\n\n for (let i = 0; i < numCases; i++) {\n const idx = startIndex + i;\n const id = `${prefix}-${String(idx).padStart(3, '0')}`;\n\n lines.push(`# ${id} — ${feature} - scenario ${idx} @regression @ui`);\n if (url) lines.push(`<!-- ct:url ${url} -->`);\n lines.push(`## Steps`);\n lines.push(`1. Navigate to ${url ?? '<PAGE_URL>'}`);\n lines.push(`2. Perform the main user action for this scenario`);\n lines.push(`3. Observe the result`);\n lines.push('');\n lines.push(`## Expected Results`);\n lines.push(`- The page responds correctly for this scenario`);\n lines.push(`- UI reflects the expected change`);\n lines.push('');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nasync function promptBasicQuestions(opts: {\n url?: string;\n feature?: string;\n appDescription?: string;\n numCases?: number;\n}) {\n // Non-interactive mode: all required options were passed as flags\n if (opts.feature) {\n const n = Math.min(Math.max(opts.numCases ?? 3, 1), 10);\n return {\n feature: opts.feature,\n appDescription: opts.appDescription ?? '',\n numCases: n,\n url: opts.url,\n };\n }\n\n // Interactive mode\n const rl = createInterface({ input, output });\n\n const feature = (await rl.question('🧩 Feature or page to test: ')).trim();\n const appDescription = (await rl.question('📝 Short app description (optional): ')).trim();\n const numCasesRaw = (await rl.question('🔢 How many test cases? (1–10) [3]: ')).trim();\n\n rl.close();\n\n let numCases = parseInt(numCasesRaw, 10);\n if (isNaN(numCases) || numCases < 1) numCases = 3;\n if (numCases > 10) numCases = 10;\n\n return { feature, appDescription, numCases, url: opts.url };\n}\n\nasync function runTcInteractive(params: {\n url?: string;\n explicitPrefix?: string;\n feature?: string;\n appDescription?: string;\n numCases?: number;\n useAi: boolean;\n headed?: boolean;\n captureOnly?: boolean;\n}) {\n const { feature, appDescription, numCases, url } = await promptBasicQuestions({\n url: params.url,\n feature: params.feature,\n appDescription: params.appDescription,\n numCases: params.numCases,\n });\n\n const prefix = inferPrefix({\n featureText: feature,\n url,\n explicitPrefix: params.explicitPrefix,\n });\n\n mkdirSync('cases', { recursive: true });\n const fileName = `${prefix.toLowerCase()}-${slugify(feature)}.md`;\n const fullPath = join('cases', fileName);\n\n let markdown: string;\n let pageSummary = undefined;\n\n if (params.useAi) {\n if (url) {\n try {\n console.log(`🔍 Capturing page: ${url}`);\n const elementMap = await captureElements(url, {\n headless: !(params.headed ?? false),\n verbose: true,\n });\n printCaptureReport(elementMap);\n\n const jsonPath = saveCaptureJson(elementMap);\n console.log(`📄 Saved capture JSON → ${jsonPath}`);\n pageSummary = toPageSummary(elementMap);\n\n if (params.captureOnly) {\n console.log('Capture-only mode requested. No test cases were generated.');\n return;\n }\n\n const analysis = await analyseElements(elementMap, { verbose: true, feature });\n printCaptureReport(elementMap, analysis);\n\n const previewPath = saveSpecPreview(analysis);\n if (previewPath) {\n console.log(`🧪 Saved preview spec → ${previewPath}`);\n }\n\n const captureFileName = `${prefix.toLowerCase()}-${slugify(feature)}.md`;\n const generatedPath = saveCasesMarkdown(analysis, 'cases', captureFileName);\n console.log(`✅ Capture-based AI generated test cases → ${generatedPath}`);\n console.log('\\nNext steps:');\n console.log(` ct normalize ${generatedPath} --and-gen --lang ts`);\n console.log(' ct test');\n return;\n } catch (e: any) {\n printWarningBlock(formatCaptureFailure(e));\n console.warn('⚠️ Falling back to AI text generation without capture context.');\n if (params.captureOnly) {\n return;\n }\n }\n }\n\n try {\n markdown = await generateTcMarkdownWithAi({\n appDescription: appDescription || undefined,\n feature,\n url,\n pageSummary,\n prefix,\n startIndex: 1,\n numCases,\n });\n markdown = injectUrlMetadata(markdown, url);\n console.log('✅ AI generated test cases.');\n } catch (err: any) {\n printWarningBlock([\n 'AI generation failed.',\n err?.message ?? String(err),\n ]);\n markdown = buildManualCasesMarkdown({ prefix, feature, url, numCases, startIndex: 1 });\n console.log('📝 Generated manual test case templates instead.');\n }\n } else {\n markdown = buildManualCasesMarkdown({ prefix, feature, url, numCases, startIndex: 1 });\n console.log('📝 Generated manual test case templates (pass --ai to use AI).');\n }\n\n writeFileSync(fullPath, markdown);\n\n console.log(`\\n✍️ Wrote ${numCases} case(s) → ${fullPath}`);\n console.log('\\nNext steps:');\n console.log(' ct normalize ./cases --and-gen --lang ts');\n console.log(' ct test');\n}\n\nfunction printWarningBlock(lines: string[]): void {\n if (lines.length === 0) return;\n\n console.warn(`⚠️ ${lines[0]}`);\n for (const line of lines.slice(1)) {\n console.warn(line);\n }\n}\n\n// ─── Shared options factory ───────────────────────────────────────────────────\n\nfunction addSharedOptions(cmd: Command): Command {\n return cmd\n .option('--ai', 'Use AI to generate test cases (requires API key)')\n .option('--prefix <prefix>', 'Explicit ID prefix, e.g. AUTH, DASH, CART')\n .option('--feature <name>', 'Feature name — skips interactive prompt')\n .option('--desc <text>', 'App description — skips interactive prompt')\n .option('--count <n>', 'Number of cases (1–10)', parseInt);\n}\n\nfunction resolveCommanderOpts<T extends Record<string, unknown>>(opts: T | Command): T {\n if (typeof (opts as Command).optsWithGlobals === 'function') {\n return (opts as Command).optsWithGlobals<T>();\n }\n if (typeof (opts as Command).opts === 'function') {\n return (opts as Command).opts<T>();\n }\n return opts as T;\n}\n\n// ─── Command definition ───────────────────────────────────────────────────────\n\nexport function tcCmd() {\n const root = new Command('tc')\n .description('Create CementicTest case files (Markdown) under ./cases')\n .addHelpText('after', `\nExamples:\n $ ct tc --feature \"Login form\" --ai\n $ ct tc --feature \"Checkout\" --count 5 --prefix CHK\n $ ct tc url https://example.com/login --ai --feature \"Auth\"\n`);\n\n addSharedOptions(root).action(\n async (opts: { ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number } | Command) => {\n const resolvedOpts = resolveCommanderOpts<{ ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number }>(opts);\n await runTcInteractive({\n url: undefined,\n explicitPrefix: resolvedOpts.prefix,\n feature: resolvedOpts.feature,\n appDescription: resolvedOpts.desc,\n numCases: resolvedOpts.count,\n useAi: resolvedOpts.ai ?? false,\n });\n }\n );\n\n addSharedOptions(\n root\n .command('url')\n .argument('<url>', 'Page URL to use as live capture and AI context')\n .description('Generate test cases with capture-aware context from a specific live page')\n .option('--headed', 'Show the browser while capturing the page')\n .option('--capture-only', 'Run live page capture and save artifacts without generating cases')\n ).action(\n async (\n url: string,\n opts: { ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number; headed?: boolean; captureOnly?: boolean } | Command,\n command?: Command,\n ) => {\n const resolvedOpts = resolveCommanderOpts<{ ai?: boolean; prefix?: string; feature?: string; desc?: string; count?: number; headed?: boolean; captureOnly?: boolean }>(command ?? opts);\n await runTcInteractive({\n url,\n explicitPrefix: resolvedOpts.prefix,\n feature: resolvedOpts.feature,\n appDescription: resolvedOpts.desc,\n numCases: resolvedOpts.count,\n useAi: resolvedOpts.ai ?? false,\n headed: resolvedOpts.headed ?? false,\n captureOnly: resolvedOpts.captureOnly ?? false,\n });\n }\n );\n\n return root;\n}\n","// src/core/prefix.ts\n\nconst PREFIX_MAP: Array<{ keywords: string[]; prefix: string }> = [\n { keywords: ['login', 'sign in', 'signin', 'auth', 'authentication'], prefix: 'AUTH' },\n { keywords: ['dashboard', 'home'], prefix: 'DASH' },\n { keywords: ['profile', 'account'], prefix: 'PROF' },\n { keywords: ['cart', 'basket'], prefix: 'CART' },\n { keywords: ['checkout', 'payment', 'pay'], prefix: 'CHK' },\n { keywords: ['order', 'orders'], prefix: 'ORD' },\n { keywords: ['settings', 'preferences', 'config'], prefix: 'SET' },\n];\n\nfunction normalizeText(text: string): string {\n return text.toLowerCase().trim();\n}\n\nfunction deriveFromFreeText(text: string): string | undefined {\n const norm = normalizeText(text);\n for (const entry of PREFIX_MAP) {\n if (entry.keywords.some(k => norm.includes(k))) {\n return entry.prefix;\n }\n }\n // fallback: first word, first 4 alphanumerics\n const firstWord = norm.split(/\\s+/).find(w => /[a-z0-9]/.test(w));\n if (!firstWord) return undefined;\n return firstWord.replace(/[^a-z0-9]/gi, '').slice(0, 4).toUpperCase() || undefined;\n}\n\nfunction deriveFromUrl(url: string): string | undefined {\n try {\n const u = new URL(url);\n const segments = u.pathname.split('/').filter(Boolean);\n const last = segments[segments.length - 1] || '';\n if (!last) return undefined;\n return deriveFromFreeText(last);\n } catch {\n return undefined;\n }\n}\n\nexport function inferPrefix(params: {\n featureText?: string;\n url?: string;\n explicitPrefix?: string;\n}): string {\n // 1) explicit flag wins\n if (params.explicitPrefix) {\n return params.explicitPrefix.trim().toUpperCase();\n }\n\n // 2) feature text\n if (params.featureText) {\n const fromFeature = deriveFromFreeText(params.featureText);\n if (fromFeature) return fromFeature;\n }\n\n // 3) url\n if (params.url) {\n const fromUrl = deriveFromUrl(params.url);\n if (fromUrl) return fromUrl;\n }\n\n // 4) last-resort default\n return 'TC';\n}","export type ProviderName = 'deepseek' | 'anthropic' | 'gemini' | 'qwen' | 'kimi' | 'openai';\nexport type ProviderTransport = 'anthropic' | 'openai-compatible';\n\nexport type ProviderConfig = {\n provider: ProviderName;\n displayName: string;\n apiKey: string;\n model: string;\n baseUrl?: string;\n transport: ProviderTransport;\n};\n\nconst PROVIDER_ORDER: ProviderName[] = ['deepseek', 'anthropic', 'gemini', 'qwen', 'kimi', 'openai'];\n\nexport function resolveLlmProvider(env: NodeJS.ProcessEnv = process.env): ProviderConfig {\n const explicitProvider = (env.CT_LLM_PROVIDER ?? '').trim().toLowerCase();\n const providers = buildProviderConfigs(env);\n\n if (explicitProvider) {\n if (!(explicitProvider in providers)) {\n throw new Error(\n `Unsupported CT_LLM_PROVIDER=\"${explicitProvider}\". Use deepseek, anthropic, gemini, qwen, kimi, or openai.`\n );\n }\n\n const selected = providers[explicitProvider as ProviderName];\n if (!selected.apiKey) {\n throw new Error(\n `CT_LLM_PROVIDER=${explicitProvider} is set but the matching API key is missing.\\n${buildProviderSetupHelp()}`\n );\n }\n\n return selected;\n }\n\n for (const providerName of PROVIDER_ORDER) {\n if (providers[providerName].apiKey) return providers[providerName];\n }\n\n throw new Error(`No LLM API key found.\\n${buildProviderSetupHelp()}`);\n}\n\nexport function buildProviderSetupHelp(): string {\n return [\n ' OpenAI: export OPENAI_API_KEY=your-key',\n ' Anthropic: export ANTHROPIC_API_KEY=your-key',\n ' Gemini: export GEMINI_API_KEY=your-key',\n ' DeepSeek: export DEEPSEEK_API_KEY=your-key',\n ' Qwen: export QWEN_API_KEY=your-key',\n ' Kimi: export KIMI_API_KEY=your-key',\n ' Generic: export CT_LLM_API_KEY=your-key',\n ' export CT_LLM_BASE_URL=https://your-openai-compatible-endpoint/v1',\n ].join('\\n');\n}\n\nfunction buildProviderConfigs(env: NodeJS.ProcessEnv): Record<ProviderName, ProviderConfig> {\n return {\n deepseek: {\n provider: 'deepseek',\n displayName: 'DeepSeek',\n apiKey: env.DEEPSEEK_API_KEY ?? env.CT_DEEPSEEK_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.DEEPSEEK_MODEL ?? 'deepseek-chat',\n baseUrl: env.DEEPSEEK_BASE_URL ?? 'https://api.deepseek.com/v1',\n transport: 'openai-compatible',\n },\n anthropic: {\n provider: 'anthropic',\n displayName: 'Claude',\n apiKey: env.ANTHROPIC_API_KEY ?? env.CT_ANTHROPIC_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.ANTHROPIC_MODEL ?? 'claude-sonnet-4-5',\n baseUrl: 'https://api.anthropic.com',\n transport: 'anthropic',\n },\n gemini: {\n provider: 'gemini',\n displayName: 'Gemini',\n apiKey: env.GEMINI_API_KEY ?? env.GOOGLE_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.GEMINI_MODEL ?? 'gemini-2.5-flash',\n baseUrl: env.GEMINI_BASE_URL ?? 'https://generativelanguage.googleapis.com/v1beta/openai',\n transport: 'openai-compatible',\n },\n qwen: {\n provider: 'qwen',\n displayName: 'Qwen',\n apiKey: env.QWEN_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.QWEN_MODEL ?? 'qwen-plus',\n baseUrl: env.QWEN_BASE_URL ?? 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',\n transport: 'openai-compatible',\n },\n kimi: {\n provider: 'kimi',\n displayName: 'Kimi',\n apiKey: env.KIMI_API_KEY ?? env.MOONSHOT_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.KIMI_MODEL ?? 'moonshot-v1-8k',\n baseUrl: env.KIMI_BASE_URL ?? 'https://api.moonshot.ai/v1',\n transport: 'openai-compatible',\n },\n openai: {\n provider: 'openai',\n displayName: env.CT_LLM_API_KEY && env.CT_LLM_BASE_URL ? 'OpenAI-compatible' : 'OpenAI',\n apiKey: env.CT_LLM_API_KEY ?? env.OPENAI_API_KEY ?? '',\n model: env.CT_LLM_MODEL ?? env.OPENAI_MODEL ?? 'gpt-4o-mini',\n baseUrl: env.CT_LLM_BASE_URL ?? 'https://api.openai.com/v1',\n transport: 'openai-compatible',\n },\n };\n}\n","import type { PageSummary } from './capture.js';\nimport { resolveLlmProvider } from './llm-provider.js';\n\nexport type TcAiContext = {\n appDescription?: string;\n feature: string;\n url?: string;\n pageSummary?: PageSummary;\n prefix: string;\n startIndex: number;\n numCases: number;\n};\n\nfunction getAvailableCtVarKeys(): string[] {\n return Object.keys(process.env)\n .filter((key) => /^CT_VAR_[A-Z0-9_]+$/.test(key))\n .sort();\n}\n\nconst RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE = `\nRULE 10 - PLAYWRIGHT KNOWLEDGE BASE\n(sourced from playwright.dev official documentation)\n\nYou are an expert in Playwright TypeScript. Apply this knowledge\nwhen generating test code. Always use web-first assertions that\nauto-wait. Never use manual waits or non-awaited assertions.\n\nLOCATOR PRIORITY (use in this order)\n1. page.getByRole('button', { name: 'Submit' }) <- best\n2. page.getByLabel('Email address')\n3. page.getByPlaceholder('Enter email')\n4. page.getByText('Welcome')\n5. page.getByAltText('logo')\n6. page.getByTitle('Close')\n7. page.getByTestId('submit-btn')\n8. page.locator('#id') or page.locator('.class') <- last resort\n\nChain locators to narrow scope:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' }).click()\n\nLOCATOR ASSERTIONS (always await, always web-first)\nVisibility:\n await expect(locator).toBeVisible()\n await expect(locator).toBeHidden()\n await expect(locator).toBeInViewport()\n\nState:\n await expect(locator).toBeEnabled()\n await expect(locator).toBeDisabled()\n await expect(locator).toBeChecked()\n await expect(locator).not.toBeChecked()\n await expect(locator).toBeFocused()\n await expect(locator).toBeEditable()\n await expect(locator).toBeEmpty()\n await expect(locator).toBeAttached()\n\nText content:\n await expect(locator).toHaveText('exact text')\n await expect(locator).toHaveText(/regex/)\n await expect(locator).toContainText('partial')\n await expect(locator).toContainText(['item1', 'item2'])\n\nValue and attributes:\n await expect(locator).toHaveValue('input value')\n await expect(locator).toHaveValues(['opt1', 'opt2']) // multi-select\n await expect(locator).toHaveAttribute('href', /pattern/)\n await expect(locator).toHaveClass(/active/)\n await expect(locator).toHaveCSS('color', 'rgb(0,0,0)')\n await expect(locator).toHaveId('submit-btn')\n await expect(locator).toHaveAccessibleName('Submit form')\n await expect(locator).toHaveAccessibleDescription('...')\n\nCounting (PREFER toHaveCount over .count() to avoid flakiness):\n await expect(locator).toHaveCount(3)\n await expect(locator).toHaveCount(0) // none exist\n // Only use .count() when you need the actual number:\n const n = await page.getByRole('button').count();\n console.log(\\`Found \\${n} buttons\\`);\n\nPAGE ASSERTIONS\n await expect(page).toHaveTitle(/Playwright/)\n await expect(page).toHaveTitle('Exact Title')\n await expect(page).toHaveURL('https://example.com/dashboard')\n await expect(page).toHaveURL(/\\\\/dashboard/)\n\nACTIONS (Playwright auto-waits before each action)\nNavigation:\n await page.goto('https://example.com')\n await page.goBack()\n await page.goForward()\n await page.reload()\n\nClicking:\n await locator.click()\n await locator.dblclick()\n await locator.click({ button: 'right' })\n await locator.click({ modifiers: ['Shift'] })\n\nForms:\n await locator.fill('text') // clears then types\n await locator.clear()\n await locator.pressSequentially('slow typing', { delay: 50 })\n await locator.selectOption('value')\n await locator.selectOption({ label: 'Blue' })\n await locator.check()\n await locator.uncheck()\n await locator.setInputFiles('path/to/file.pdf')\n\nHover and focus:\n await locator.hover()\n await locator.focus()\n await locator.blur()\n\nKeyboard:\n await page.keyboard.press('Enter')\n await page.keyboard.press('Tab')\n await page.keyboard.press('Escape')\n await page.keyboard.press('Control+A')\n\nScroll:\n await locator.scrollIntoViewIfNeeded()\n await page.mouse.wheel(0, 500)\n\nBEST PRACTICES (from playwright.dev/docs/best-practices)\nDO use web-first assertions:\n await expect(page.getByText('welcome')).toBeVisible()\n\nNEVER use synchronous assertions:\n expect(await page.getByText('welcome').isVisible()).toBe(true)\n\nDO chain locators:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' })\n\nNEVER use fragile CSS/XPath selectors:\n page.locator('button.buttonIcon.episode-actions-later')\n\nDO use role-based locators:\n page.getByRole('button', { name: 'submit' })\n\nINTENT -> PATTERN MAPPING\n\nCOUNTING:\n \"how many X\" / \"count X\" / \"number of X\" / \"return the count\"\n -> const n = await page.getByRole('X').count();\n console.log(\\`Found \\${n} X elements\\`);\n expect(n).toBeGreaterThan(0);\n\n \"there are N X\" / \"exactly N X\"\n -> await expect(page.getByRole('X')).toHaveCount(N);\n\n CRITICAL: Never use getByText(\"how many X\") - count intent\n means call .count() or toHaveCount(), not search for text.\n\nPRESENCE:\n \"X is present/visible/shown/exists\"\n -> await expect(locator).toBeVisible()\n\n \"X is hidden/not present/gone\"\n -> await expect(locator).toBeHidden()\n\nTEXT:\n \"text says X\" / \"shows X\" / \"message is X\"\n -> await expect(locator).toHaveText('X')\n\n \"contains X\" / \"includes X\"\n -> await expect(locator).toContainText('X')\n\n \"page title is X\"\n -> await expect(page).toHaveTitle(/X/i)\n\n \"heading says X\"\n -> await expect(page.getByRole('heading')).toContainText('X')\n\n \"error says X\"\n -> await expect(page.getByRole('alert')).toContainText('X')\n\nSTATE:\n \"X is enabled/disabled\"\n -> await expect(locator).toBeEnabled() / toBeDisabled()\n\n \"X is checked/unchecked\"\n -> await expect(locator).toBeChecked() / not.toBeChecked()\n\n \"X has value Y\"\n -> await expect(locator).toHaveValue('Y')\n\n \"X is active / has class Y\"\n -> await expect(locator).toHaveClass(/Y/)\n\nNAVIGATION:\n \"redirects to X\" / \"goes to X\" / \"URL contains X\"\n -> await expect(page).toHaveURL(/X/)\n\n \"stays on same page\"\n -> await expect(page).toHaveURL(/currentPath/)\n\n \"opens new tab\"\n -> const [newPage] = await Promise.all([\n context.waitForEvent('page'),\n locator.click()\n ]);\n\nFORMS:\n \"form submits successfully\"\n -> fill fields + click submit + assert URL change or success message\n\n \"validation error shown\"\n -> submit empty + await expect(page.getByRole('alert')).toBeVisible()\n\n \"required field X\"\n -> submit without X + assert error message for X visible\n\nAUTH:\n \"login with valid credentials\"\n -> fill(CT_VAR_USERNAME) + fill(CT_VAR_PASSWORD) + click login\n + await expect(page).toHaveURL(/dashboard/) // or the exact target named in the intent, e.g. /secure/\n\n \"login fails / invalid credentials\"\n -> fill bad values + click login\n + await expect(page.getByRole('alert')).toBeVisible()\n\n \"logout works\"\n -> click logout + await expect(page).toHaveURL(/login|home/)\n\nTHEME / VISUAL:\n \"dark mode / theme toggle\"\n -> await locator.click()\n + await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')\n // OR: await expect(page.locator('body')).toHaveClass(/dark/)\n\nTIMING:\n \"X loads / X appears\"\n -> await expect(locator).toBeVisible({ timeout: 10000 })\n\n \"spinner disappears / loader gone\"\n -> await expect(spinner).toBeHidden({ timeout: 10000 })\n\n \"modal closes\"\n -> await expect(modal).toBeHidden()\n\nACCESSIBILITY:\n \"has alt text\"\n -> await expect(page.locator('img')).toHaveAttribute('alt', /.+/)\n\n \"keyboard navigable\"\n -> await page.keyboard.press('Tab')\n + await expect(firstFocusable).toBeFocused()\n\nCRITICAL RULES\n1. NEVER use intent words as locator text.\n \"count buttons\" != getByText(\"count buttons\")\n \"verify heading\" != getByText(\"verify heading\")\n\n2. ALWAYS use web-first assertions (await expect).\n NEVER use: expect(await locator.isVisible()).toBe(true)\n\n3. For counting, prefer toHaveCount() over .count() unless\n you need the actual number for logging.\n\n4. Auto-waiting: Playwright automatically waits for elements\n to be actionable before click/fill/etc. Do not add\n manual waitForTimeout() unless testing timing specifically.\n\n5. Use not. prefix for negative assertions:\n await expect(locator).not.toBeVisible()\n await expect(locator).not.toBeChecked()\n`.trim();\n\nconst ADVANCED_DOC_MAP: Record<string, string> = {\n upload: 'https://playwright.dev/docs/input',\n 'file upload': 'https://playwright.dev/docs/input',\n intercept: 'https://playwright.dev/docs/mock',\n mock: 'https://playwright.dev/docs/mock',\n 'api mock': 'https://playwright.dev/docs/mock',\n accessibility: 'https://playwright.dev/docs/accessibility-testing',\n 'screen reader': 'https://playwright.dev/docs/accessibility-testing',\n visual: 'https://playwright.dev/docs/screenshots',\n screenshot: 'https://playwright.dev/docs/screenshots',\n mobile: 'https://playwright.dev/docs/emulation',\n responsive: 'https://playwright.dev/docs/emulation',\n viewport: 'https://playwright.dev/docs/emulation',\n network: 'https://playwright.dev/docs/network',\n 'api call': 'https://playwright.dev/docs/network',\n iframe: 'https://playwright.dev/docs/frames',\n frame: 'https://playwright.dev/docs/frames',\n auth: 'https://playwright.dev/docs/auth',\n 'sign in': 'https://playwright.dev/docs/auth',\n 'stay logged': 'https://playwright.dev/docs/auth',\n cookie: 'https://playwright.dev/docs/auth',\n storage: 'https://playwright.dev/docs/auth',\n download: 'https://playwright.dev/docs/downloads',\n pdf: 'https://playwright.dev/docs/downloads',\n dialog: 'https://playwright.dev/docs/dialogs',\n alert: 'https://playwright.dev/docs/dialogs',\n confirm: 'https://playwright.dev/docs/dialogs',\n 'new tab': 'https://playwright.dev/docs/pages',\n 'new page': 'https://playwright.dev/docs/pages',\n popup: 'https://playwright.dev/docs/pages',\n};\n\nasync function fetchDocContext(intent: string): Promise<string> {\n const intentLower = intent.toLowerCase();\n const matched = new Set<string>();\n\n for (const [keyword, url] of Object.entries(ADVANCED_DOC_MAP)) {\n if (intentLower.includes(keyword)) {\n matched.add(url);\n }\n }\n\n if (matched.size === 0) return '';\n\n const fetched: string[] = [];\n\n for (const url of matched) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const html = await res.text();\n const text = html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s{3,}/g, '\\n\\n')\n .slice(0, 3000);\n\n fetched.push(`\\n// From ${url}:\\n${text}`);\n } catch {\n // Non-fatal - continue without this doc\n }\n }\n\n if (fetched.length === 0) return '';\n\n return `\\n\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\nADDITIONAL PLAYWRIGHT DOCS (fetched for this intent)\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${fetched.join('\\n')}`;\n}\n\n// ─── Prompt builders ──────────────────────────────────────────────────────────\n\nfunction buildSystemMessage(): string {\n return `\nYou are a senior software test architect with 10 years of Playwright experience.\nYou translate user requirements into precise, minimal, executable test scenarios.\n\nRULE 1 - INTENT IS THE REQUIREMENT\nParse the user's feature description into specific testable claims BEFORE examining page context.\nGenerate scenarios for the user's intent, not for every element on the page.\n\nRULE 2 - GENERATE TESTS FOR THE INTENT, NOT THE PAGE INVENTORY\nOnly generate tests for claims extracted from the intent.\nNever generate tests for page elements that were not requested.\nPage context improves selector quality and wording, but it does not define test scope.\n\nRULE 3 - SELECTOR HIERARCHY\nWhen choosing selectors, prefer:\n1. Exact page-context match when available\n2. getByRole() with text from the intent\n3. getByLabel() for form inputs\n4. getByText() with text from the intent\n5. getByPlaceholder() for inputs\n6. locator('#id') only when the id appears stable\n\nTie-breaker when multiple elements match:\n1. Prefer the highest-confidence page-context match\n2. Prefer visible elements over hidden\n3. Prefer interactive elements over static elements\n4. If still ambiguous, use the first match and note it with a short comment in the step text\n\nRULE 4 - TITLE DISAMBIGUATION\n\"verify title\" means the main visible heading on the page.\nUse a heading assertion first.\nDo NOT treat \"title\" as the browser tab title unless the intent explicitly says \"browser title\", \"tab title\", or \"page title\".\n\nRULE 5 - PRESENCE-ONLY INTENTS\nFor presence-only intents such as \"verify X\", \"check X is present\", or \"X is visible\":\n- Only assert visibility\n- Do NOT click the element\n- Do NOT assert redirects, state changes, or side effects\n\nRULE 6 - NEGATIVE CASES\nGenerate negative scenarios only when the intent implies interaction:\n- Form testing: always include an invalid-input scenario\n- Authentication: always include a wrong-credentials scenario\n- For field-specific auth failures, make the field under test explicitly wrong:\n invalid email -> 'invalid-not-an-email'\n invalid username -> 'nonexistent-user'\n invalid password -> 'wrong-password-123'\n- Presence checks: no negative case needed\n- Button click: negative case only if the button can be disabled\n\nRULE 7 - SETUP DEPENDENCIES\nIf authentication is required to reach the page:\n- Add setup steps using CT_VAR_USERNAME and CT_VAR_PASSWORD\n- Tag the scenario with @requires-auth\n- Mention the dependency in a short step or assertion note when needed\n\nRULE 8 - TEST DATA\nNever use the literal word 'value' as a placeholder.\nWhen filling a field:\n- If the user context lists a matching CT_VAR_* variable, write it exactly as '` + '${CT_VAR_FIELDNAME}' + `'\n- Otherwise use a field-specific fallback such as 'test-username', 'test-email@example.com', 'test-password', or 'test-search'\n- For redirect or stay-on-page assertions, derive the URL regex from the exact intent text or explicit path; do not invent generic alternates like dashboard|success|home\n\nRULE 9 - SCOPE DISCIPLINE\nMatch scenario count to intent complexity:\n- 1 to 2 claims: 1 to 2 scenarios maximum\n- 3 to 5 claims: 3 to 5 scenarios maximum\n- Full flow: 4 to 8 scenarios maximum\nNever exceed 8 scenarios.\n\n${RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE}\n\nCOMMON TESTING VOCABULARY\n\"verify/check X is present/visible\" -> toBeVisible()\n\"verify title/heading\" -> heading is visible\n\"button/link is present\" -> button or link is visible\n\"can click X\" -> click then assert visible outcome\n\"form submits\" -> fill + click + assert success or URL\n\"error shows\" -> trigger error + assert error visible\n\"redirects to X\" -> URL contains or equals X\n\"text says X\" -> text equals or contains X\n\"page loads\" -> main heading or key element is visible\n\nOUTPUT FORMAT - EXACT MARKDOWN SCHEMA\nOutput valid markdown in this exact format. No preamble. No explanation. Just the markdown.\n\n# {PREFIX}-001 - {scenario-slug} - {Human readable title} @tag1 @tag2\n\n## Steps\n1. Navigate to {url}\n2. {action verb} {target description}\n\n## Expected Results\n- {specific observable assertion}\n- {specific observable assertion}\n\n---\n\n# {PREFIX}-002 - {scenario-slug} - {Human readable title} @tag1 @tag2\n\n## Steps\n1. Navigate to {url}\n2. {action verb} {target description}\n\n## Expected Results\n- {specific observable assertion}\n\nRules for the markdown schema:\n- id format: PREFIX-NNN using the provided prefix and numbering\n- slug format: kebab-case, max 5 words, derived from the scenario subject\n- title: human readable and aligned to the user's intent\n- tags: include at least one of @smoke @regression @negative @happy-path plus a relevant domain tag such as @auth @ui @navigation @form @checkout\n- steps: numbered, start with Navigate, then actions, written in plain English\n- assertions: bullet points with observable outcomes only\n- never write \"test passes\" or \"works correctly\"\n- do NOT wrap the output in code fences\n`.trim();\n}\n\nfunction buildUserMessage(ctx: TcAiContext): string {\n const lines: string[] = [];\n const availableCtVarKeys = getAvailableCtVarKeys();\n\n lines.push(`App / product description:`);\n lines.push(ctx.appDescription || 'N/A');\n lines.push('');\n\n lines.push(`Primary test intent:`);\n lines.push(ctx.feature);\n lines.push('');\n\n lines.push(`Interpret the feature text above as the source of truth.`);\n lines.push(`Only generate scenarios for claims that are explicitly implied by that intent.`);\n lines.push('');\n\n if (ctx.url) {\n lines.push(`Page URL: ${ctx.url}`);\n lines.push('');\n }\n\n if (ctx.pageSummary) {\n const s = ctx.pageSummary;\n lines.push(`Live page analysis:`);\n\n if (s.title) lines.push(`- Page title: ${s.title}`);\n\n if (s.headings.length) {\n lines.push(`- Headings: ${s.headings.join(' | ')}`);\n }\n\n if (s.inputs.length) {\n const inputDescs = s.inputs.map(i => {\n const parts = [\n i.label && `label=\"${i.label}\"`,\n i.placeholder && `placeholder=\"${i.placeholder}\"`,\n i.name && `name=\"${i.name}\"`,\n i.type && i.type !== 'text' && `type=\"${i.type}\"`,\n i.testId && `data-testid=\"${i.testId}\"`,\n ].filter(Boolean);\n return parts.join(', ');\n });\n lines.push(`- Form inputs: ${inputDescs.join(' | ')}`);\n }\n\n if (s.buttons.length) {\n lines.push(`- Buttons: ${s.buttons.join(' | ')}`);\n }\n\n if (s.links.length) {\n lines.push(`- Links: ${s.links.slice(0, 20).join(' | ')}`);\n }\n\n lines.push('');\n }\n\n if (availableCtVarKeys.length > 0) {\n lines.push('Available CT_VAR_* test variables:');\n for (const envKey of availableCtVarKeys) {\n lines.push(`- ${envKey}`);\n }\n lines.push('');\n lines.push(`Use a listed variable when it clearly matches a form field, written exactly as '` + '${CT_VAR_NAME}' + `'.`);\n lines.push('');\n }\n\n lines.push(`Test ID prefix: ${ctx.prefix}`);\n lines.push(`Start numbering from: ${String(ctx.startIndex).padStart(3, '0')}`);\n lines.push(`Requested number of test cases: ${ctx.numCases}`);\n lines.push('');\n lines.push(`Use the requested count only when it fits the intent complexity. Prefer fewer scenarios when the request is simple.`);\n lines.push(`Output ONLY the test cases. No explanation, no preamble.`);\n\n return lines.join('\\n');\n}\n\n// ─── Anthropic call ───────────────────────────────────────────────────────────\n\nasync function callAnthropic(\n apiKey: string,\n model: string,\n system: string,\n user: string\n): Promise<string> {\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 4096,\n system,\n messages: [{ role: 'user', content: user }],\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Anthropic API error ${response.status}: ${text}`);\n }\n\n const json: any = await response.json();\n const content = json.content?.[0]?.text?.trim() ?? '';\n if (!content) throw new Error('Anthropic response had no content');\n return content;\n}\n\n// ─── OpenAI-compatible call ───────────────────────────────────────────────────\n\nasync function callOpenAiCompatible(\n apiKey: string,\n model: string,\n baseUrl: string,\n displayName: string,\n system: string,\n user: string\n): Promise<string> {\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n temperature: 0.2,\n messages: [\n { role: 'system', content: system },\n { role: 'user', content: user },\n ],\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`${displayName} API error ${response.status}: ${text}`);\n }\n\n const json: any = await response.json();\n const content = json.choices?.[0]?.message?.content?.trim() ?? '';\n if (!content) throw new Error('OpenAI response had no content');\n return content;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport async function generateTcMarkdownWithAi(ctx: TcAiContext): Promise<string> {\n const providerConfig = resolveLlmProvider();\n\n const docContext = await fetchDocContext(ctx.feature);\n const system = buildSystemMessage() + docContext;\n const user = buildUserMessage(ctx);\n\n console.log(`🤖 Using ${providerConfig.displayName} (${providerConfig.model})`);\n\n if (providerConfig.transport === 'anthropic') {\n return callAnthropic(providerConfig.apiKey, providerConfig.model, system, user);\n }\n\n return callOpenAiCompatible(\n providerConfig.apiKey,\n providerConfig.model,\n providerConfig.baseUrl ?? 'https://api.openai.com/v1',\n providerConfig.displayName,\n system,\n user,\n );\n}\n","import type { CapturedElement, ElementMap } from './capture.js';\nimport { resolveLlmProvider } from './llm-provider.js';\nimport { inferPrefix as inferSuggestedPrefix } from './prefix.js';\n\nexport type AnalysisStep = {\n action: 'navigate' | 'fill' | 'click' | 'select' | 'check' | 'keyboard' | 'hover';\n selector: string;\n value: string;\n human: string;\n};\n\nexport type AnalysisAssertion = {\n type: string;\n selector: string;\n expected: string;\n human: string;\n playwright: string;\n};\n\nexport type AnalysisScenario = {\n id: string;\n title: string;\n tags: string[];\n steps: AnalysisStep[];\n assertions: AnalysisAssertion[];\n narrator: string;\n codeLevel: 'beginner' | 'intermediate' | 'advanced';\n};\n\nexport type AnalysisResult = {\n url: string;\n feature: string;\n suggestedPrefix: string;\n scenarios: AnalysisScenario[];\n analysisNotes?: string;\n audioSummary?: string;\n};\n\ntype AuthElements = {\n usernameInput?: CapturedElement;\n passwordInput?: CapturedElement;\n submitButton?: CapturedElement;\n heading?: CapturedElement;\n};\n\ntype AnalysisOptions = {\n verbose?: boolean;\n feature?: string;\n};\n\ntype IntentMode = 'count' | 'presence' | 'auth' | 'form' | 'flow' | 'generic';\n\ntype IntentProfile = {\n feature: string;\n mode: IntentMode;\n maxScenarios: number;\n wantsHeading: boolean;\n};\n\nfunction escapeForRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\\\/]/g, '\\\\$&');\n}\n\nconst RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE = `\nRULE 10 - PLAYWRIGHT KNOWLEDGE BASE\n(sourced from playwright.dev official documentation)\n\nYou are an expert in Playwright TypeScript. Apply this knowledge\nwhen generating test code. Always use web-first assertions that\nauto-wait. Never use manual waits or non-awaited assertions.\n\nLOCATOR PRIORITY (use in this order)\n1. page.getByRole('button', { name: 'Submit' }) <- best\n2. page.getByLabel('Email address')\n3. page.getByPlaceholder('Enter email')\n4. page.getByText('Welcome')\n5. page.getByAltText('logo')\n6. page.getByTitle('Close')\n7. page.getByTestId('submit-btn')\n8. page.locator('#id') or page.locator('.class') <- last resort\n\nChain locators to narrow scope:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' }).click()\n\nLOCATOR ASSERTIONS (always await, always web-first)\nVisibility:\n await expect(locator).toBeVisible()\n await expect(locator).toBeHidden()\n await expect(locator).toBeInViewport()\n\nState:\n await expect(locator).toBeEnabled()\n await expect(locator).toBeDisabled()\n await expect(locator).toBeChecked()\n await expect(locator).not.toBeChecked()\n await expect(locator).toBeFocused()\n await expect(locator).toBeEditable()\n await expect(locator).toBeEmpty()\n await expect(locator).toBeAttached()\n\nText content:\n await expect(locator).toHaveText('exact text')\n await expect(locator).toHaveText(/regex/)\n await expect(locator).toContainText('partial')\n await expect(locator).toContainText(['item1', 'item2'])\n\nValue and attributes:\n await expect(locator).toHaveValue('input value')\n await expect(locator).toHaveValues(['opt1', 'opt2']) // multi-select\n await expect(locator).toHaveAttribute('href', /pattern/)\n await expect(locator).toHaveClass(/active/)\n await expect(locator).toHaveCSS('color', 'rgb(0,0,0)')\n await expect(locator).toHaveId('submit-btn')\n await expect(locator).toHaveAccessibleName('Submit form')\n await expect(locator).toHaveAccessibleDescription('...')\n\nCounting (PREFER toHaveCount over .count() to avoid flakiness):\n await expect(locator).toHaveCount(3)\n await expect(locator).toHaveCount(0) // none exist\n // Only use .count() when you need the actual number:\n const n = await page.getByRole('button').count();\n console.log(\\`Found \\${n} buttons\\`);\n\nPAGE ASSERTIONS\n await expect(page).toHaveTitle(/Playwright/)\n await expect(page).toHaveTitle('Exact Title')\n await expect(page).toHaveURL('https://example.com/dashboard')\n await expect(page).toHaveURL(/\\\\/dashboard/)\n\nACTIONS (Playwright auto-waits before each action)\nNavigation:\n await page.goto('https://example.com')\n await page.goBack()\n await page.goForward()\n await page.reload()\n\nClicking:\n await locator.click()\n await locator.dblclick()\n await locator.click({ button: 'right' })\n await locator.click({ modifiers: ['Shift'] })\n\nForms:\n await locator.fill('text') // clears then types\n await locator.clear()\n await locator.pressSequentially('slow typing', { delay: 50 })\n await locator.selectOption('value')\n await locator.selectOption({ label: 'Blue' })\n await locator.check()\n await locator.uncheck()\n await locator.setInputFiles('path/to/file.pdf')\n\nHover and focus:\n await locator.hover()\n await locator.focus()\n await locator.blur()\n\nKeyboard:\n await page.keyboard.press('Enter')\n await page.keyboard.press('Tab')\n await page.keyboard.press('Escape')\n await page.keyboard.press('Control+A')\n\nScroll:\n await locator.scrollIntoViewIfNeeded()\n await page.mouse.wheel(0, 500)\n\nBEST PRACTICES (from playwright.dev/docs/best-practices)\nDO use web-first assertions:\n await expect(page.getByText('welcome')).toBeVisible()\n\nNEVER use synchronous assertions:\n expect(await page.getByText('welcome').isVisible()).toBe(true)\n\nDO chain locators:\n page.getByRole('listitem').filter({ hasText: 'Product 2' })\n .getByRole('button', { name: 'Add to cart' })\n\nNEVER use fragile CSS/XPath selectors:\n page.locator('button.buttonIcon.episode-actions-later')\n\nDO use role-based locators:\n page.getByRole('button', { name: 'submit' })\n\nINTENT -> PATTERN MAPPING\n\nCOUNTING:\n \"how many X\" / \"count X\" / \"number of X\" / \"return the count\"\n -> const n = await page.getByRole('X').count();\n console.log(\\`Found \\${n} X elements\\`);\n expect(n).toBeGreaterThan(0);\n\n \"there are N X\" / \"exactly N X\"\n -> await expect(page.getByRole('X')).toHaveCount(N);\n\n CRITICAL: Never use getByText(\"how many X\") - count intent\n means call .count() or toHaveCount(), not search for text.\n\nPRESENCE:\n \"X is present/visible/shown/exists\"\n -> await expect(locator).toBeVisible()\n\n \"X is hidden/not present/gone\"\n -> await expect(locator).toBeHidden()\n\nTEXT:\n \"text says X\" / \"shows X\" / \"message is X\"\n -> await expect(locator).toHaveText('X')\n\n \"contains X\" / \"includes X\"\n -> await expect(locator).toContainText('X')\n\n \"page title is X\"\n -> await expect(page).toHaveTitle(/X/i)\n\n \"heading says X\"\n -> await expect(page.getByRole('heading')).toContainText('X')\n\n \"error says X\"\n -> await expect(page.getByRole('alert')).toContainText('X')\n\nSTATE:\n \"X is enabled/disabled\"\n -> await expect(locator).toBeEnabled() / toBeDisabled()\n\n \"X is checked/unchecked\"\n -> await expect(locator).toBeChecked() / not.toBeChecked()\n\n \"X has value Y\"\n -> await expect(locator).toHaveValue('Y')\n\n \"X is active / has class Y\"\n -> await expect(locator).toHaveClass(/Y/)\n\nNAVIGATION:\n \"redirects to X\" / \"goes to X\" / \"URL contains X\"\n -> await expect(page).toHaveURL(/X/)\n\n \"stays on same page\"\n -> await expect(page).toHaveURL(/currentPath/)\n\n \"opens new tab\"\n -> const [newPage] = await Promise.all([\n context.waitForEvent('page'),\n locator.click()\n ]);\n\nFORMS:\n \"form submits successfully\"\n -> fill fields + click submit + assert URL change or success message\n\n \"validation error shown\"\n -> submit empty + await expect(page.getByRole('alert')).toBeVisible()\n\n \"required field X\"\n -> submit without X + assert error message for X visible\n\nAUTH:\n \"login with valid credentials\"\n -> fill(CT_VAR_USERNAME) + fill(CT_VAR_PASSWORD) + click login\n + await expect(page).toHaveURL(/dashboard/) // or the exact target named in the intent, e.g. /secure/\n\n \"login fails / invalid credentials\"\n -> fill bad values + click login\n + await expect(page.getByRole('alert')).toBeVisible()\n\n \"logout works\"\n -> click logout + await expect(page).toHaveURL(/login|home/)\n\nTHEME / VISUAL:\n \"dark mode / theme toggle\"\n -> await locator.click()\n + await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')\n // OR: await expect(page.locator('body')).toHaveClass(/dark/)\n\nTIMING:\n \"X loads / X appears\"\n -> await expect(locator).toBeVisible({ timeout: 10000 })\n\n \"spinner disappears / loader gone\"\n -> await expect(spinner).toBeHidden({ timeout: 10000 })\n\n \"modal closes\"\n -> await expect(modal).toBeHidden()\n\nACCESSIBILITY:\n \"has alt text\"\n -> await expect(page.locator('img')).toHaveAttribute('alt', /.+/)\n\n \"keyboard navigable\"\n -> await page.keyboard.press('Tab')\n + await expect(firstFocusable).toBeFocused()\n\nCRITICAL RULES\n1. NEVER use intent words as locator text.\n \"count buttons\" != getByText(\"count buttons\")\n \"verify heading\" != getByText(\"verify heading\")\n\n2. ALWAYS use web-first assertions (await expect).\n NEVER use: expect(await locator.isVisible()).toBe(true)\n\n3. For counting, prefer toHaveCount() over .count() unless\n you need the actual number for logging.\n\n4. Auto-waiting: Playwright automatically waits for elements\n to be actionable before click/fill/etc. Do not add\n manual waitForTimeout() unless testing timing specifically.\n\n5. Use not. prefix for negative assertions:\n await expect(locator).not.toBeVisible()\n await expect(locator).not.toBeChecked()\n`.trim();\n\nconst ADVANCED_DOC_MAP: Record<string, string> = {\n upload: 'https://playwright.dev/docs/input',\n 'file upload': 'https://playwright.dev/docs/input',\n intercept: 'https://playwright.dev/docs/mock',\n mock: 'https://playwright.dev/docs/mock',\n 'api mock': 'https://playwright.dev/docs/mock',\n accessibility: 'https://playwright.dev/docs/accessibility-testing',\n 'screen reader': 'https://playwright.dev/docs/accessibility-testing',\n visual: 'https://playwright.dev/docs/screenshots',\n screenshot: 'https://playwright.dev/docs/screenshots',\n mobile: 'https://playwright.dev/docs/emulation',\n responsive: 'https://playwright.dev/docs/emulation',\n viewport: 'https://playwright.dev/docs/emulation',\n network: 'https://playwright.dev/docs/network',\n 'api call': 'https://playwright.dev/docs/network',\n iframe: 'https://playwright.dev/docs/frames',\n frame: 'https://playwright.dev/docs/frames',\n auth: 'https://playwright.dev/docs/auth',\n 'sign in': 'https://playwright.dev/docs/auth',\n 'stay logged': 'https://playwright.dev/docs/auth',\n cookie: 'https://playwright.dev/docs/auth',\n storage: 'https://playwright.dev/docs/auth',\n download: 'https://playwright.dev/docs/downloads',\n pdf: 'https://playwright.dev/docs/downloads',\n dialog: 'https://playwright.dev/docs/dialogs',\n alert: 'https://playwright.dev/docs/dialogs',\n confirm: 'https://playwright.dev/docs/dialogs',\n 'new tab': 'https://playwright.dev/docs/pages',\n 'new page': 'https://playwright.dev/docs/pages',\n popup: 'https://playwright.dev/docs/pages',\n};\n\nasync function fetchDocContext(intent: string): Promise<string> {\n const intentLower = intent.toLowerCase();\n const matched = new Set<string>();\n\n for (const [keyword, url] of Object.entries(ADVANCED_DOC_MAP)) {\n if (intentLower.includes(keyword)) {\n matched.add(url);\n }\n }\n\n if (matched.size === 0) return '';\n\n const fetched: string[] = [];\n\n for (const url of matched) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const html = await res.text();\n const text = html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s{3,}/g, '\\n\\n')\n .slice(0, 3000);\n\n fetched.push(`\\n// From ${url}:\\n${text}`);\n } catch {\n // Non-fatal - continue without this doc\n }\n }\n\n if (fetched.length === 0) return '';\n\n return `\\n\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\nADDITIONAL PLAYWRIGHT DOCS (fetched for this intent)\\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${fetched.join('\\n')}`;\n}\n\nexport async function analyseElements(\n elementMap: ElementMap,\n options: AnalysisOptions = {},\n): Promise<AnalysisResult> {\n const { verbose = false, feature } = options;\n const requestedFeature = normalizeRequestedFeature(feature, elementMap);\n\n let providerConfig;\n try {\n providerConfig = resolveLlmProvider();\n } catch (error: any) {\n log(verbose, `\\n[analyse] ${shortErrorMessage(error)}`);\n log(verbose, '[analyse] Falling back to deterministic capture analysis.');\n return buildDeterministicAnalysis(elementMap, requestedFeature);\n }\n\n log(verbose, `\\n[analyse] Sending capture to ${providerConfig.displayName} (${providerConfig.model})`);\n\n try {\n const docContext = await fetchDocContext(requestedFeature);\n const systemPrompt = buildSystemPrompt() + docContext;\n const userPrompt = buildUserPrompt(elementMap, requestedFeature);\n\n const rawResponse = providerConfig.transport === 'anthropic'\n ? await callAnthropic(providerConfig.apiKey, providerConfig.model, systemPrompt, userPrompt)\n : await callOpenAiCompatible(\n providerConfig.apiKey,\n providerConfig.model,\n providerConfig.baseUrl ?? 'https://api.openai.com/v1',\n providerConfig.displayName,\n systemPrompt,\n userPrompt,\n );\n\n const parsed = parseAnalysisJson(rawResponse);\n return sanitizeAnalysis(parsed, elementMap, requestedFeature);\n } catch (error: any) {\n log(verbose, `[analyse] Remote analysis failed: ${shortErrorMessage(error)}`);\n log(verbose, '[analyse] Falling back to deterministic capture analysis.');\n return buildDeterministicAnalysis(elementMap, requestedFeature);\n }\n}\n\nfunction buildSystemPrompt(): string {\n return `\nYou are a senior QA automation engineer and Playwright expert working on CementicTest.\n\nYour job is to analyse a structured map of interactive elements extracted from a live web page,\nthen produce a complete set of Playwright test scenarios.\n\nRULES:\n1. The user's feature description is the PRIMARY requirement. Generate scenarios that test what the user asked for.\n2. Every assertion must include an exact \"playwright\" field with a complete await expect(...) statement.\n3. Use captured elements as the first selector source. If the intent names text that was not captured, you may fall back to a safe Playwright selector derived from the intent such as getByRole(), getByText(), getByLabel(), getByPlaceholder(), or locator('#id').\n4. Include happy-path and negative scenarios only when the intent implies interaction, and stay evidence-backed.\n5. Output only valid JSON matching the requested schema.\n6. Do not invent redirect targets, success pages, error text, password clearing, or security scenarios unless the capture explicitly supports them.\n7. If no status or alert region was captured, avoid scenarios that depend on unseen server-side validation messages.\n8. Scope must match intent complexity. Simple 1 to 2 claim requests should produce only 1 to 2 scenarios.\n9. For presence-only intents such as \"verify X\" or \"X is present\", only assert visibility. Do not click and do not assert outcomes after clicking.\n${RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE}\n11. For fill steps, never use the literal word \"value\". If matching CT_VAR_* variables are listed in the prompt, use them in human-readable step text and use a realistic non-generic runtime value in the JSON value field. Otherwise use a field-specific fallback such as test-username or test-password.\n12. For field-specific auth failures, make the field under test explicitly wrong: invalid email -> invalid-not-an-email, invalid username -> nonexistent-user, invalid password -> wrong-password-123.\n13. When redirect or stay-on-page assertions are needed, derive the URL regex from the exact intent text or explicit path. Do not invent generic alternates such as dashboard|success|home.\n14. When a CTA could realistically be a button or a link, prefer a resilient selector such as getByRole('button', { name: /Join Now/i }).or(page.getByRole('link', { name: /Join Now/i })).\n15. The \"selector\" field must be a raw selector expression such as locator(\"#username\") or getByRole('button', { name: \"Login\" }). Never wrap selectors in page. or page.locator(\"...\") inside JSON, except inside Locator.or(...) where the alternate locator must be page-scoped.\n16. Tie-breaker for multiple matching elements: prefer highest confidence, then interactive elements, then the first visible-looking candidate.\n17. If a page clearly contains login or auth fields, do not create submit scenarios that only click the button. Include realistic fill steps for captured username/email and password inputs when the intent asks for auth interaction.\n18. \"verify title\" means the main visible heading on the page, not the browser tab title, unless the intent explicitly says browser title, tab title, or page title.\n\nOUTPUT SCHEMA:\n{\n \"url\": string,\n \"feature\": string,\n \"suggestedPrefix\": string,\n \"scenarios\": [\n {\n \"id\": string,\n \"title\": string,\n \"tags\": string[],\n \"steps\": [\n {\n \"action\": \"navigate\"|\"fill\"|\"click\"|\"select\"|\"check\"|\"keyboard\"|\"hover\",\n \"selector\": string,\n \"value\": string,\n \"human\": string\n }\n ],\n \"assertions\": [\n {\n \"type\": string,\n \"selector\": string,\n \"expected\": string,\n \"human\": string,\n \"playwright\": string\n }\n ],\n \"narrator\": string,\n \"codeLevel\": \"beginner\"|\"intermediate\"|\"advanced\"\n }\n ],\n \"analysisNotes\": string,\n \"audioSummary\": string\n}`.trim();\n}\n\nfunction buildUserPrompt(elementMap: ElementMap, feature: string): string {\n const lines: string[] = [];\n const authElements = detectAuthElements(elementMap);\n const availableCtVarKeys = getAvailableCtVarKeys();\n const intentProfile = buildIntentProfile(feature);\n\n lines.push('USER INTENT');\n lines.push(`Feature description: ${feature}`);\n lines.push(`Intent mode: ${intentProfile.mode}`);\n lines.push(`Maximum scenarios for this request: ${intentProfile.maxScenarios}`);\n lines.push('');\n\n lines.push('PAGE INFORMATION');\n lines.push(`URL: ${elementMap.url}`);\n lines.push(`Title: ${elementMap.title}`);\n lines.push(`Captured in: ${elementMap.mode} mode`);\n lines.push('');\n\n for (const category of ['input', 'button', 'link', 'heading', 'status'] as const) {\n const items = elementMap.elements.filter((element) => element.category === category);\n if (items.length === 0) continue;\n\n lines.push(`${category.toUpperCase()}S (${items.length} found):`);\n for (const item of items.slice(0, category === 'link' ? 10 : items.length)) {\n lines.push(` - [${item.confidence}] ${item.selector}`);\n lines.push(` Purpose: ${item.purpose}`);\n if (item.selectorAlt.length > 0) {\n lines.push(` Fallbacks: ${item.selectorAlt.slice(0, 2).join(' | ')}`);\n }\n }\n lines.push('');\n }\n\n if (elementMap.warnings.length > 0) {\n lines.push('CAPTURE WARNINGS:');\n for (const warning of elementMap.warnings) {\n lines.push(` - ${warning}`);\n }\n lines.push('');\n }\n\n if (availableCtVarKeys.length > 0) {\n lines.push('AVAILABLE CT_VAR_* VARIABLES:');\n for (const envKey of availableCtVarKeys) {\n lines.push(` - ${envKey}`);\n }\n lines.push('');\n }\n\n const interactiveCount = elementMap.elements.filter((element) => (\n element.category === 'input' || element.category === 'button' || element.category === 'link'\n )).length;\n const statusCount = elementMap.elements.filter((element) => element.category === 'status').length;\n\n lines.push('EVIDENCE CONSTRAINTS:');\n lines.push(` - Interactive elements captured: ${interactiveCount}`);\n lines.push(` - Status or alert regions captured: ${statusCount}`);\n lines.push(' - If no redirect target is explicitly captured, do not assert a destination path.');\n lines.push(' - If no status region was captured, avoid exact server-side credential error claims.');\n lines.push(' - Generate scenarios only for the requested feature description.');\n if (authElements.usernameInput && authElements.passwordInput && authElements.submitButton) {\n lines.push(' - This page contains a captured auth form. Include fill steps for the username/email and password fields in credential-submission scenarios.');\n lines.push(' - For auth pages without captured post-submit evidence, prefer evidence-backed form-state assertions over invented success redirects.');\n }\n lines.push('');\n lines.push('Generate only the JSON response.');\n\n return lines.join('\\n');\n}\n\nasync function callAnthropic(\n apiKey: string,\n model: string,\n systemPrompt: string,\n userPrompt: string,\n): Promise<string> {\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Anthropic API ${response.status}: ${await response.text()}`);\n }\n\n const json: any = await response.json();\n const content = json.content?.[0]?.text?.trim() ?? '';\n if (!content) throw new Error('Anthropic returned empty content');\n return content;\n}\n\nasync function callOpenAiCompatible(\n apiKey: string,\n model: string,\n baseUrl: string,\n displayName: string,\n systemPrompt: string,\n userPrompt: string,\n): Promise<string> {\n const response = await fetch(`${baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n temperature: 0.1,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`${displayName} API ${response.status}: ${await response.text()}`);\n }\n\n const json: any = await response.json();\n const content = json.choices?.[0]?.message?.content?.trim() ?? '';\n if (!content) throw new Error('OpenAI-compatible provider returned empty content');\n return content;\n}\n\nfunction parseAnalysisJson(raw: string): AnalysisResult {\n const stripped = raw\n .replace(/^```(?:json)?\\s*/m, '')\n .replace(/\\s*```\\s*$/m, '')\n .trim();\n\n try {\n return JSON.parse(stripped);\n } catch (error: any) {\n throw new Error(\n `Failed to parse LLM response as JSON.\\nParse error: ${error?.message ?? error}\\nRaw response:\\n${raw.slice(0, 500)}`\n );\n }\n}\n\nfunction sanitizeAnalysis(\n analysis: AnalysisResult,\n elementMap: ElementMap,\n requestedFeature: string,\n): AnalysisResult {\n const selectors = new Set<string>();\n for (const element of elementMap.elements) {\n selectors.add(element.selector);\n for (const alt of element.selectorAlt) selectors.add(alt);\n }\n\n const rawScenarios = Array.isArray(analysis.scenarios) ? analysis.scenarios : [];\n const intentProfile = buildIntentProfile(requestedFeature);\n const currentUrl = new URL(elementMap.url);\n const authElements = detectAuthElements(elementMap);\n const resolvedFeature = requestedFeature || analysis.feature || inferFeatureName(elementMap);\n const resolvedPrefix = (analysis.suggestedPrefix || inferSuggestedPrefix({\n featureText: resolvedFeature,\n url: elementMap.url,\n })).toUpperCase();\n const knownPaths = new Set([\n currentUrl.pathname,\n ...elementMap.elements\n .filter((element) => element.category === 'link')\n .map((element) => {\n const href = element.attributes?.href;\n if (typeof href !== 'string') return '';\n try {\n return new URL(href, elementMap.url).pathname;\n } catch {\n return href;\n }\n })\n .filter(Boolean),\n ]);\n\n const sanitizedScenarios = rawScenarios\n .map((scenario) => normalizeScenario(scenario, selectors, elementMap.url))\n .filter((scenario) => scenario.steps.length > 0 && scenario.assertions.length > 0)\n .map((scenario) => ({\n ...scenario,\n tags: scenario.tags.map(normalizeTag),\n assertions: scenario.assertions.filter((assertion) => {\n if (assertion.type !== 'url') return true;\n const combined = `${assertion.expected} ${assertion.human} ${assertion.playwright}`;\n const pathMatch = combined.match(/\\/[a-z0-9/_-]+/i);\n if (!pathMatch) return true;\n return knownPaths.has(pathMatch[0]);\n }),\n }))\n .filter((scenario) => scenario.assertions.length > 0);\n\n const intentAlignedScenarios = applyIntentPolicy(\n sanitizedScenarios,\n elementMap,\n intentProfile,\n resolvedPrefix,\n ).slice(0, intentProfile.maxScenarios);\n\n const useAuthFallback = shouldUseAuthFallback(authElements, intentAlignedScenarios, intentProfile);\n const fallbackScenarios = intentProfile.mode === 'presence'\n ? buildPresenceOnlyScenarios(elementMap, requestedFeature, resolvedPrefix)\n : useAuthFallback\n ? buildAuthFallbackScenarios(elementMap, resolvedPrefix, authElements, requestedFeature)\n : buildFallbackScenarios(elementMap, resolvedPrefix, requestedFeature);\n const finalScenarios = useAuthFallback\n ? fallbackScenarios.slice(0, intentProfile.maxScenarios)\n : intentAlignedScenarios.length > 0\n ? intentAlignedScenarios\n : fallbackScenarios.slice(0, intentProfile.maxScenarios);\n\n return {\n ...analysis,\n url: analysis.url || elementMap.url,\n feature: resolvedFeature,\n suggestedPrefix: resolvedPrefix,\n scenarios: finalScenarios,\n analysisNotes: [\n analysis.analysisNotes,\n useAuthFallback ? 'Replaced low-evidence auth scenarios with deterministic evidence-backed auth coverage.' : '',\n `Sanitized to ${finalScenarios.length} evidence-backed scenario(s) from ${rawScenarios.length} raw scenario(s).`,\n ].filter(Boolean).join(' '),\n audioSummary: analysis.audioSummary || buildAudioSummary(resolvedFeature, finalScenarios),\n };\n}\n\nfunction normalizeScenario(candidate: any, selectors: Set<string>, url: string): AnalysisScenario {\n const steps = Array.isArray(candidate?.steps)\n ? candidate.steps\n .map((step: any) => normalizeStep(step, selectors))\n .filter(Boolean) as AnalysisStep[]\n : [];\n\n const assertions = Array.isArray(candidate?.assertions)\n ? candidate.assertions\n .map((assertion: any) => normalizeAssertion(assertion, selectors))\n .filter(Boolean) as AnalysisAssertion[]\n : [];\n\n const normalizedSteps = ensureNavigateStep(steps, url);\n\n return {\n id: candidate?.id ?? 'FLOW-001',\n title: candidate?.title ?? 'Captured page flow',\n tags: Array.isArray(candidate?.tags) ? candidate.tags : [],\n steps: normalizedSteps,\n assertions,\n narrator: candidate?.narrator ?? 'Let us run this captured test flow.',\n codeLevel: candidate?.codeLevel ?? 'beginner',\n };\n}\n\nfunction normalizeStep(candidate: any, selectors: Set<string>): AnalysisStep | null {\n if (!candidate) return null;\n\n const selector = String(candidate.selector ?? '').trim();\n if (!isAllowedSelector(selector, selectors)) return null;\n\n const action = String(candidate.action ?? '').trim() as AnalysisStep['action'];\n if (!['navigate', 'fill', 'click', 'select', 'check', 'keyboard', 'hover'].includes(action)) return null;\n\n const rawValue = String(candidate.value ?? '');\n const value = action === 'fill' || action === 'select'\n ? resolveFieldRuntimeValue(selector, rawValue)\n : rawValue;\n const human = normalizeStepHuman(\n String(candidate.human ?? '').trim() || defaultStepHuman(action, selector, value),\n action,\n selector,\n value,\n );\n\n return {\n action,\n selector,\n value,\n human,\n };\n}\n\nfunction normalizeAssertion(candidate: any, selectors: Set<string>): AnalysisAssertion | null {\n if (!candidate) return null;\n\n const selector = String(candidate.selector ?? '').trim();\n if (!isAllowedSelector(selector, selectors)) return null;\n\n const assertion: AnalysisAssertion = {\n type: String(candidate.type ?? 'visible').trim() || 'visible',\n selector,\n expected: String(candidate.expected ?? '').trim(),\n human: String(candidate.human ?? '').trim() || 'Expected state is verified',\n playwright: String(candidate.playwright ?? '').trim(),\n };\n\n assertion.playwright = normalizePlaywrightAssertion(assertion);\n return assertion;\n}\n\nfunction buildFallbackScenarios(elementMap: ElementMap, prefix: string): AnalysisScenario[] {\n return buildFallbackScenariosForFeature(elementMap, prefix, '');\n}\n\nfunction buildFallbackScenariosForFeature(\n elementMap: ElementMap,\n prefix: string,\n feature: string,\n): AnalysisScenario[] {\n const normalizedFeature = feature.toLowerCase();\n const heading = elementMap.elements.find((element) => element.category === 'heading');\n const emailInput = elementMap.elements.find((element) => (\n element.category === 'input' &&\n (element.attributes.type === 'email' || /email/.test(`${element.name ?? ''} ${String(element.attributes.label ?? '')}`.toLowerCase()))\n ));\n const passwordInput = elementMap.elements.find((element) => (\n element.category === 'input' && element.attributes.type === 'password'\n ));\n const submitButton = elementMap.elements.find((element) => (\n element.category === 'button' && /login|sign in|submit|continue/i.test(element.name ?? '')\n )) ?? elementMap.elements.find((element) => element.category === 'button');\n const alert = findAlertElement(elementMap);\n\n const scenarios: AnalysisScenario[] = [];\n const tag = (value: string) => normalizeTag(value);\n const nextId = (index: number) => `${prefix}-${String(900 + index).padStart(3, '0')}`;\n const wantsHiddenAlertOnLoad =\n /\\b(error|alert|message)\\b/.test(normalizedFeature) &&\n /\\b(not shown|not visible|hidden|not present|gone|absent)\\b/.test(normalizedFeature) &&\n /\\b(first load|first loads|first loads?|page first loads|initial load|on load)\\b/.test(normalizedFeature);\n const wantsVisibleAlert =\n /\\b(error|alert|message|invalid|incorrect|required|validation)\\b/.test(normalizedFeature) &&\n !wantsHiddenAlertOnLoad;\n\n if (wantsHiddenAlertOnLoad && alert) {\n return [{\n id: `${prefix}-001`,\n title: 'Error message is hidden on initial load',\n tags: [tag('negative'), tag('ui')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'hidden',\n selector: alert.selector,\n expected: 'hidden',\n human: `${alert.name || 'Error message'} is not shown when the page first loads`,\n playwright: `await expect(page.${alert.selector}).toBeHidden();`,\n },\n ],\n narrator: 'We verify that the page does not expose an error surface before any user action.',\n codeLevel: 'beginner',\n }];\n }\n\n if (wantsVisibleAlert && alert) {\n return [{\n id: `${prefix}-001`,\n title: 'Page exposes an alert message when requested',\n tags: [tag('negative'), tag('ui')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'text',\n selector: alert.selector,\n expected: alert.name || 'error',\n human: 'An alert message is shown',\n playwright: `await expect(page.${alert.selector}).toContainText(/invalid|error|required/i);`,\n },\n ],\n narrator: 'We validate the alert channel directly when the intent asks about an error message.',\n codeLevel: 'beginner',\n }];\n }\n\n if (heading) {\n scenarios.push({\n id: nextId(scenarios.length + 1),\n title: 'Page loads with expected heading',\n tags: [tag('smoke'), tag('page-load')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n ],\n assertions: [\n {\n type: 'visible',\n selector: heading.selector,\n expected: 'visible',\n human: `${heading.name || 'Primary heading'} is visible`,\n playwright: `await expect(page.${heading.selector}).toBeVisible();`,\n },\n ],\n narrator: 'We will first confirm that the expected page heading is visible.',\n codeLevel: 'beginner',\n });\n }\n\n if (emailInput && passwordInput && submitButton) {\n const emailValue = resolveFieldRuntimeValue(emailInput.selector, '');\n scenarios.push({\n id: nextId(scenarios.length + 1),\n title: 'Submitting without a password keeps the user on the form',\n tags: [tag('validation'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the captured page',\n },\n {\n action: 'fill',\n selector: emailInput.selector,\n value: emailValue,\n human: buildFillHuman('Fill in the email field', emailInput.selector, emailValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the submit button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: new URL(elementMap.url).pathname,\n human: 'User remains on the same page',\n playwright: `await expect(page).toHaveURL('${elementMap.url}');`,\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: 'Password field stays visible for correction',\n playwright: `await expect(page.${passwordInput.selector}).toBeVisible();`,\n },\n ],\n narrator: 'Next we will leave the password blank and confirm the form does not advance.',\n codeLevel: 'beginner',\n });\n }\n\n return scenarios.slice(0, 5);\n}\n\nfunction buildAuthFallbackScenarios(\n elementMap: ElementMap,\n prefix: string,\n authElements: AuthElements,\n feature: string,\n): AnalysisScenario[] {\n const { usernameInput, passwordInput, submitButton, heading } = authElements;\n if (!usernameInput || !passwordInput || !submitButton) {\n return buildFallbackScenariosForFeature(elementMap, prefix, feature);\n }\n\n const normalizedFeature = feature.toLowerCase();\n const scenarios: AnalysisScenario[] = [];\n const tag = (value: string) => normalizeTag(value);\n const nextId = (index: number) => `${prefix}-${String(index).padStart(3, '0')}`;\n const usernameValue = inferAuthValue(usernameInput, 'username');\n const passwordValue = inferAuthValue(passwordInput, 'password');\n const alert = findAlertElement(elementMap);\n const wantsNavigation =\n /\\b(valid credentials|correct credentials|successful login|log in successfully|login succeeds|sign in succeeds)\\b/.test(normalizedFeature) ||\n /\\b(redirect|redirects|redirected|secure area|dashboard|redirected to|goes to|navigates? to)\\b/.test(normalizedFeature);\n const wantsError =\n /\\b(wrong password|wrong credentials|invalid|incorrect|error message|shows an error|alert)\\b/.test(normalizedFeature);\n const invalidAuthTarget = inferInvalidAuthTarget(normalizedFeature);\n const successUrlPattern = deriveSuccessUrlPattern(elementMap, normalizedFeature);\n const invalidUsernameValue =\n invalidAuthTarget === 'email'\n ? 'invalid-not-an-email'\n : invalidAuthTarget === 'username'\n ? 'nonexistent-user'\n : usernameValue;\n const invalidPasswordValue = invalidAuthTarget === 'password' ? 'wrong-password-123' : 'wrong-password-123';\n\n if (wantsNavigation) {\n return [{\n id: `${prefix}-001`,\n title: 'Valid credentials redirect to the authenticated area',\n tags: [tag('auth'), tag('happy-path')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: passwordValue,\n human: buildFillHuman('Fill in the password field', passwordInput.selector, passwordValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: successUrlPattern,\n human: 'User is redirected to the secure area',\n playwright: `await expect(page).toHaveURL(/${successUrlPattern}/);`,\n },\n ],\n narrator: 'We submit valid credentials and confirm that authentication changes the page URL.',\n codeLevel: 'beginner',\n }];\n }\n\n if (wantsError) {\n return [{\n id: `${prefix}-001`,\n title: 'Wrong password shows an authentication error',\n tags: [tag('auth'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: invalidUsernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, invalidUsernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: invalidPasswordValue,\n human: buildFillHuman('Fill in the password field', passwordInput.selector, invalidPasswordValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n alert\n ? {\n type: 'text',\n selector: alert.selector,\n expected: alert.name || 'error',\n human: 'An alert communicates the login failure',\n playwright: `await expect(page.${alert.selector}).toContainText(/invalid|error|required/i);`,\n }\n : {\n type: 'text',\n selector: usernameInput.selector,\n expected: 'error',\n human: 'An authentication error message is shown',\n playwright: `await expect(page.getByRole('alert')).toContainText(/invalid|error|required/i);`,\n },\n ],\n narrator: 'We use an invalid password and confirm the page surfaces an authentication error.',\n codeLevel: 'beginner',\n }];\n }\n\n scenarios.push({\n id: nextId(1),\n title: 'Login form renders expected controls',\n tags: [tag('smoke'), tag('auth')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n ],\n assertions: [\n ...(heading ? [{\n type: 'visible',\n selector: heading.selector,\n expected: 'visible',\n human: `${heading.name || 'Login heading'} is visible`,\n playwright: visibleAssertion(heading.selector),\n }] : []),\n {\n type: 'visible',\n selector: usernameInput.selector,\n expected: 'visible',\n human: `${usernameInput.name || 'Username field'} is visible`,\n playwright: visibleAssertion(usernameInput.selector),\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: `${passwordInput.name || 'Password field'} is visible`,\n playwright: visibleAssertion(passwordInput.selector),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Submit button'} is visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'We first confirm that the captured login form is present and interactive.',\n codeLevel: 'beginner',\n });\n\n scenarios.push({\n id: nextId(2),\n title: 'User can enter credentials before submission',\n tags: [tag('auth'), tag('happy-path')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'fill',\n selector: passwordInput.selector,\n value: passwordValue,\n human: buildFillHuman('Fill in the password field', passwordInput.selector, passwordValue),\n },\n ],\n assertions: [\n {\n type: 'value',\n selector: usernameInput.selector,\n expected: usernameValue,\n human: 'Username input contains the entered value',\n playwright: valueAssertion(usernameInput.selector, usernameValue),\n },\n {\n type: 'value',\n selector: passwordInput.selector,\n expected: passwordValue,\n human: 'Password input contains the entered value',\n playwright: valueAssertion(passwordInput.selector, passwordValue),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Submit button'} remains visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'Next we verify that both credential fields accept input before we submit the form.',\n codeLevel: 'beginner',\n });\n\n scenarios.push({\n id: nextId(3),\n title: 'Submitting without a password keeps the login form visible',\n tags: [tag('auth'), tag('negative')],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: 'Navigate to the login page',\n },\n {\n action: 'fill',\n selector: usernameInput.selector,\n value: usernameValue,\n human: buildFillHuman('Fill in the username field', usernameInput.selector, usernameValue),\n },\n {\n action: 'click',\n selector: submitButton.selector,\n value: '',\n human: 'Click the login button',\n },\n ],\n assertions: [\n {\n type: 'url',\n selector: 'page',\n expected: elementMap.url,\n human: 'User remains on the same login URL',\n playwright: `await expect(page).toHaveURL('${elementMap.url}');`,\n },\n {\n type: 'visible',\n selector: passwordInput.selector,\n expected: 'visible',\n human: 'Password field remains visible for correction',\n playwright: visibleAssertion(passwordInput.selector),\n },\n {\n type: 'visible',\n selector: submitButton.selector,\n expected: 'visible',\n human: `${submitButton.name || 'Login button'} remains visible`,\n playwright: visibleAssertion(submitButton.selector),\n },\n ],\n narrator: 'Finally we submit incomplete credentials and confirm the captured login form remains available for correction.',\n codeLevel: 'beginner',\n });\n\n return scenarios;\n}\n\nfunction normalizeRequestedFeature(feature: string | undefined, elementMap: ElementMap): string {\n return String(feature ?? '').trim() || inferFeatureName(elementMap);\n}\n\nfunction inferFeatureName(elementMap: ElementMap): string {\n const heading = elementMap.elements.find((element) => element.category === 'heading' && element.name);\n return heading?.name || elementMap.title || 'Captured page';\n}\n\nfunction getAvailableCtVarKeys(): string[] {\n return Object.keys(process.env)\n .filter((key) => /^CT_VAR_[A-Z0-9_]+$/.test(key))\n .sort();\n}\n\nfunction buildIntentProfile(feature: string): IntentProfile {\n const normalized = feature.toLowerCase();\n const countIntent = /\\b(?:how many|count|number of|return the count|exactly\\s+\\d+|there (?:is|are)\\s+\\d+)/.test(normalized);\n const wantsHeading = /\\b(?:title|heading)\\b/.test(normalized)\n && !/\\b(?:browser title|tab title|page title)\\b/.test(normalized);\n const presenceOnly = isPresenceOnlyIntent(normalized);\n const authIntent = /\\b(?:login|log in|sign in|auth|credentials?)\\b/.test(normalized) && !presenceOnly;\n const formIntent = /\\b(?:form|submit|field|input|enter|fill|type)\\b/.test(normalized) && !presenceOnly && !authIntent;\n const flowIntent = /\\b(?:flow|journey|checkout|purchase|complete|works?)\\b/.test(normalized) && !presenceOnly && !authIntent && !formIntent;\n const mode: IntentMode = countIntent\n ? 'count'\n : presenceOnly\n ? 'presence'\n : authIntent\n ? 'auth'\n : formIntent\n ? 'form'\n : flowIntent\n ? 'flow'\n : 'generic';\n const claimCount = countIntentClaims(feature);\n\n return {\n feature,\n mode,\n maxScenarios:\n mode === 'count' ? 1\n : mode === 'presence' ? Math.min(Math.max(claimCount, 1), 2)\n : mode === 'auth' || mode === 'form' ? Math.min(Math.max(claimCount, 3), 5)\n : mode === 'flow' ? Math.min(Math.max(claimCount, 4), 6)\n : Math.min(Math.max(claimCount, 1), 3),\n wantsHeading,\n };\n}\n\nfunction countIntentClaims(feature: string): number {\n const quoted = Array.from(feature.matchAll(/[\"“”']([^\"“”']+)[\"“”']/g)).length;\n const segments = feature\n .split(/\\s+(?:and|&)\\s+|,\\s*/i)\n .map((segment) => segment.trim())\n .filter(Boolean);\n return Math.max(quoted, segments.length || 1);\n}\n\nfunction isPresenceOnlyIntent(normalizedFeature: string): boolean {\n const presenceWords = /\\b(?:verify|check|confirm|ensure|present|visible|shown|showing|available|exists?|title|heading)\\b/.test(normalizedFeature);\n const actionWords = /\\b(?:click|submit|fill|type|enter|login|log in|sign in|checkout|purchase|complete|flow|journey|error|invalid|disabled|enabled)\\b/.test(normalizedFeature);\n return presenceWords && !actionWords;\n}\n\nfunction applyIntentPolicy(\n scenarios: AnalysisScenario[],\n elementMap: ElementMap,\n intentProfile: IntentProfile,\n prefix: string,\n): AnalysisScenario[] {\n if (intentProfile.mode === 'count') {\n return buildCountScenarios(elementMap, intentProfile.feature, prefix);\n }\n if (intentProfile.mode !== 'presence') {\n return scenarios.slice(0, intentProfile.maxScenarios);\n }\n return buildPresenceOnlyScenarios(elementMap, intentProfile.feature, prefix);\n}\n\nfunction buildCountScenarios(\n elementMap: ElementMap,\n feature: string,\n prefix: string,\n): AnalysisScenario[] {\n const normalized = feature.toLowerCase();\n const countedElements = pickCountedElements(elementMap, normalized);\n const selector = countSelectorForFeature(normalized, countedElements);\n const count = countedElements.length;\n\n return [{\n id: `${prefix}-${String(1).padStart(3, '0')}`,\n title: feature,\n tags: ['@smoke', '@ui'],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: `Navigate to ${elementMap.url}`,\n },\n ],\n assertions: [{\n type: 'count',\n selector,\n expected: String(count),\n human: `There are exactly ${count} matching elements`,\n playwright: `await expect(page.${selector}).toHaveCount(${count});`,\n }],\n narrator: 'We count only the element type requested by the user.',\n codeLevel: 'beginner',\n }];\n}\n\nfunction buildPresenceOnlyScenarios(\n elementMap: ElementMap,\n feature: string,\n prefix: string,\n): AnalysisScenario[] {\n const claims = extractPresenceClaims(feature, elementMap);\n if (claims.length === 0) return buildFallbackScenarios(elementMap, prefix).slice(0, 1);\n\n return [{\n id: `${prefix}-${String(1).padStart(3, '0')}`,\n title: feature,\n tags: ['@smoke', '@ui'],\n steps: [\n {\n action: 'navigate',\n selector: 'page',\n value: elementMap.url,\n human: `Navigate to ${elementMap.url}`,\n },\n ],\n assertions: claims.map((claim) => ({\n type: 'visible',\n selector: claim.selector,\n expected: 'visible',\n human: claim.human,\n playwright: visibleAssertion(claim.selector),\n })),\n narrator: 'We verify only the elements explicitly requested by the user.',\n codeLevel: 'beginner',\n }];\n}\n\nfunction extractPresenceClaims(\n feature: string,\n elementMap: ElementMap,\n): Array<{ selector: string; human: string }> {\n const segments = feature\n .split(/\\s+(?:and|&)\\s+|,\\s*/i)\n .map((segment) => segment.trim())\n .filter(Boolean);\n const claims: Array<{ selector: string; human: string }> = [];\n\n for (const segment of segments) {\n const normalized = segment.toLowerCase();\n if (/\\b(?:title|heading)\\b/.test(normalized) && !/\\b(?:browser title|tab title|page title)\\b/.test(normalized)) {\n claims.push({\n selector: `getByRole('heading')`,\n human: `${chooseHeadingElement(elementMap)?.name || 'Main page heading'} is visible`,\n });\n continue;\n }\n\n const text = extractIntentLabel(segment);\n if (!text) continue;\n const match = findBestMatchingElement(elementMap, text, normalized);\n const selector = buildIntentSelector(text, normalized, match);\n claims.push({\n selector,\n human: `${text} is visible`,\n });\n }\n\n return claims;\n}\n\nfunction chooseHeadingElement(elementMap: ElementMap): CapturedElement | undefined {\n return rankElements(\n elementMap.elements.filter((element) => element.category === 'heading'),\n )[0];\n}\n\nfunction extractIntentLabel(segment: string): string {\n const unquoted = Array.from(segment.matchAll(/[\"“”']([^\"“”']+)[\"“”']/g)).map((match) => match[1].trim());\n if (unquoted.length > 0) return unquoted[0];\n\n return segment\n .replace(/\\b(?:verify|check|confirm|ensure)\\b/gi, ' ')\n .replace(/\\b(?:the|a|an)\\b/gi, ' ')\n .replace(/\\b(?:is|are|be|should be)\\b/gi, ' ')\n .replace(/\\b(?:present|visible|shown|showing|available|exists?)\\b/gi, ' ')\n .replace(/\\b(?:on|in)\\s+(?:the\\s+)?page\\b/gi, ' ')\n .replace(/\\b(?:button|link|cta|label|text)\\b/gi, ' ')\n .replace(/[.?!,:;]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction findBestMatchingElement(\n elementMap: ElementMap,\n text: string,\n segment: string,\n): CapturedElement | undefined {\n const preferredCategory =\n /\\bbutton\\b/.test(segment) ? 'button'\n : /\\blink\\b/.test(segment) ? 'link'\n : /\\bheading\\b/.test(segment) ? 'heading'\n : undefined;\n const query = text.toLowerCase();\n const candidates = elementMap.elements.filter((element) => {\n const haystack = `${element.name ?? ''} ${element.purpose}`.toLowerCase();\n return haystack.includes(query);\n });\n\n if (!preferredCategory) return rankElements(candidates)[0];\n\n const preferred = candidates.filter((element) => element.category === preferredCategory);\n if (preferred.length > 0) return rankElements(preferred)[0];\n\n if (\n (preferredCategory === 'button' || preferredCategory === 'link')\n && shouldUseAmbiguousCtaSelector(segment, text)\n ) {\n const alternateCategory = preferredCategory === 'button' ? 'link' : 'button';\n const alternates = candidates.filter((element) => element.category === alternateCategory);\n if (alternates.length > 0) return rankElements(alternates)[0];\n }\n\n return rankElements(candidates)[0];\n}\n\nfunction rankElements(elements: CapturedElement[]): CapturedElement[] {\n const confidenceWeight = (confidence: string): number => (\n confidence === 'high' ? 3 : confidence === 'medium' ? 2 : 1\n );\n const interactiveWeight = (category: string): number => (\n category === 'button' || category === 'link' || category === 'input' ? 2 : 1\n );\n\n return [...elements].sort((left, right) => {\n const confidenceDelta = confidenceWeight(right.confidence) - confidenceWeight(left.confidence);\n if (confidenceDelta !== 0) return confidenceDelta;\n const interactiveDelta = interactiveWeight(right.category) - interactiveWeight(left.category);\n if (interactiveDelta !== 0) return interactiveDelta;\n return 0;\n });\n}\n\nfunction buildIntentSelector(\n text: string,\n segment: string,\n match?: CapturedElement,\n): string {\n if (shouldUseAmbiguousCtaSelector(segment, text)) {\n if (/\\blink\\b/.test(segment)) return buildAmbiguousRoleSelector(text, 'link');\n if (/\\bbutton\\b/.test(segment) || match?.category === 'link' || match?.category === 'button') {\n return buildAmbiguousRoleSelector(text, 'button');\n }\n }\n\n return match?.selector ?? buildFallbackSelector(text, segment);\n}\n\nfunction shouldUseAmbiguousCtaSelector(segment: string, text: string): boolean {\n const haystack = `${segment} ${text}`.toLowerCase();\n return /\\b(?:button|link|cta)\\b/.test(haystack)\n && (\n /\\b(?:join|start|get started|sign up|signup|subscribe|buy|purchase|learn more|see how it works|continue)\\b/.test(haystack)\n || /[$€£]/.test(text)\n );\n}\n\nfunction buildAmbiguousRoleSelector(text: string, preferredRole: 'button' | 'link'): string {\n const primary = buildRoleSelector(preferredRole, text);\n const alternate = buildRoleSelector(preferredRole === 'button' ? 'link' : 'button', text);\n return `${primary}.or(page.${alternate})`;\n}\n\nfunction buildRoleSelector(role: 'button' | 'link' | 'heading', text: string): string {\n const safeRegex = text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return `getByRole('${role}', { name: /${safeRegex}/i })`;\n}\n\nfunction buildFallbackSelector(text: string, segment: string): string {\n if (/\\bbutton\\b/.test(segment)) return buildRoleSelector('button', text);\n if (/\\blink\\b/.test(segment)) return buildRoleSelector('link', text);\n if (/\\b(?:title|heading)\\b/.test(segment)) return buildRoleSelector('heading', text);\n return `getByText(${JSON.stringify(text)})`;\n}\n\nfunction buildAudioSummary(feature: string, scenarios: AnalysisScenario[]): string {\n return `We finished validating ${feature || 'the captured page'} with ${scenarios.length} evidence-backed scenario${scenarios.length === 1 ? '' : 's'}.`;\n}\n\nfunction normalizeTag(value: string): string {\n const cleaned = String(value ?? '').trim().replace(/^@+/, '');\n return cleaned ? `@${cleaned}` : '@ui';\n}\n\nfunction detectAuthElements(elementMap: ElementMap): AuthElements {\n const usernameInput = elementMap.elements.find((element) => (\n element.category === 'input' &&\n /user(name)?|email|login/.test(`${element.name ?? ''} ${String(element.attributes.label ?? '')} ${String(element.attributes.name ?? '')}`.toLowerCase())\n ));\n const passwordInput = elementMap.elements.find((element) => (\n element.category === 'input' && String(element.attributes.type ?? '').toLowerCase() === 'password'\n ));\n const submitButton = elementMap.elements.find((element) => (\n element.category === 'button' && /login|log in|sign in|submit|continue/.test((element.name ?? '').toLowerCase())\n )) ?? elementMap.elements.find((element) => element.category === 'button');\n const heading = elementMap.elements.find((element) => (\n element.category === 'heading' && /login|sign in|auth/.test((element.name ?? '').toLowerCase())\n )) ?? elementMap.elements.find((element) => element.category === 'heading');\n\n return { usernameInput, passwordInput, submitButton, heading };\n}\n\nfunction findAlertElement(elementMap: ElementMap): CapturedElement | undefined {\n return elementMap.elements.find((element) => (\n element.role === 'alert' ||\n element.category === 'status' ||\n String(element.attributes.role ?? '').toLowerCase() === 'alert'\n ));\n}\n\nfunction sanitizeUrlIntentPhrase(value: string): string {\n return value\n .replace(/`+/g, ' ')\n .replace(/^\\/+/, ' ')\n .replace(/\\/[dgimsuvy]*$/i, ' ')\n .replace(/[\"']/g, ' ')\n .replace(/\\b(?:the|a|an|user|same|current)\\b/gi, ' ')\n .replace(/\\b(?:page|screen|view|area|section|route|path|url|form)\\b/gi, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction urlPatternFromIntentText(value: string): string | undefined {\n const sanitized = value.replace(/`+/g, '').trim();\n const explicitPath =\n sanitized.match(/\\/[a-z0-9/_-]+/i)?.[0] ??\n sanitized.match(/https?:\\/\\/[^\\s'\"]+/i)?.[0];\n if (explicitPath) {\n const parsed = explicitPath.startsWith('/')\n ? explicitPath\n : (() => {\n try {\n return new URL(explicitPath).pathname;\n } catch {\n return '';\n }\n })();\n if (parsed) {\n return parsed\n .replace(/^\\/+/, '')\n .split('/')\n .map(escapeForRegex)\n .join('\\\\/');\n }\n }\n\n const phraseMatch =\n sanitized.match(/\\b(?:redirect(?:s|ed)?|navigat(?:e|es|ed)|go(?:es|ne)?|route|path|url)\\b(?:\\s+(?:to|on|contains))?\\s+(?:the\\s+)?(.+?)(?:[.?!]|$)/i) ??\n sanitized.match(/\\b(?:remain|remains|stays|stay|still)\\s+(?:on|at)\\s+(?:the\\s+)?(.+?)(?:[.?!]|$)/i);\n const phrase = sanitizeUrlIntentPhrase(phraseMatch?.[1] ?? '');\n if (!phrase) return undefined;\n return phrase.split(/[\\s/-]+/).filter(Boolean).map(escapeForRegex).join('[-_\\\\/]?');\n}\n\nfunction inferInvalidAuthTarget(normalizedFeature: string): 'email' | 'password' | 'username' | undefined {\n if (/\\b(?:invalid|wrong|incorrect|bad|not an email)\\s+(?:e-?mail|email)\\b|\\b(?:e-?mail|email)\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad|not an email)\\b/.test(normalizedFeature)) {\n return 'email';\n }\n if (/\\b(?:invalid|wrong|incorrect|bad|nonexistent)\\s+(?:user(?:name)?|login)\\b|\\b(?:user(?:name)?|login)\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad|nonexistent)\\b/.test(normalizedFeature)) {\n return 'username';\n }\n if (/\\b(?:invalid|wrong|incorrect|bad)\\s+password\\b|\\bpassword\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad)\\b/.test(normalizedFeature)) {\n return 'password';\n }\n return undefined;\n}\n\nfunction deriveSuccessUrlPattern(elementMap: ElementMap, normalizedFeature: string): string {\n const intentPattern = urlPatternFromIntentText(normalizedFeature);\n if (intentPattern) return intentPattern;\n\n const authLink = elementMap.elements.find((element) => {\n if (element.category !== 'link') return false;\n const href = String(element.attributes.href ?? '');\n const label = `${element.name ?? ''} ${href}`.toLowerCase();\n return /\\b(secure|dashboard|home|app)\\b/.test(label);\n });\n\n const href = String(authLink?.attributes.href ?? '');\n if (href.startsWith('/')) {\n return href\n .replace(/^\\/+/, '')\n .split('/')\n .map(escapeForRegex)\n .join('\\\\/');\n }\n\n return 'secure';\n}\n\nfunction buildDeterministicAnalysis(\n elementMap: ElementMap,\n requestedFeature: string,\n): AnalysisResult {\n const intentProfile = buildIntentProfile(requestedFeature);\n const suggestedPrefix = inferSuggestedPrefix({\n featureText: requestedFeature,\n url: elementMap.url,\n }).toUpperCase();\n const authElements = detectAuthElements(elementMap);\n\n let scenarios =\n intentProfile.mode === 'count'\n ? buildCountScenarios(elementMap, requestedFeature, suggestedPrefix)\n : intentProfile.mode === 'presence'\n ? buildPresenceOnlyScenarios(elementMap, requestedFeature, suggestedPrefix)\n : (intentProfile.mode === 'auth' || intentProfile.mode === 'form')\n ? buildAuthFallbackScenarios(elementMap, suggestedPrefix, authElements, requestedFeature)\n : buildFallbackScenariosForFeature(elementMap, suggestedPrefix, requestedFeature);\n\n if (scenarios.length === 0 && (authElements.usernameInput || authElements.passwordInput || authElements.submitButton)) {\n scenarios = buildAuthFallbackScenarios(elementMap, suggestedPrefix, authElements, requestedFeature);\n }\n if (scenarios.length === 0) {\n scenarios = buildFallbackScenariosForFeature(elementMap, suggestedPrefix, requestedFeature);\n }\n\n const finalScenarios = scenarios.slice(0, intentProfile.maxScenarios);\n\n return {\n url: elementMap.url,\n feature: requestedFeature,\n suggestedPrefix,\n scenarios: finalScenarios,\n analysisNotes: 'Generated deterministic capture-backed scenarios because LLM analysis was unavailable.',\n audioSummary: buildAudioSummary(requestedFeature, finalScenarios),\n };\n}\n\nfunction shortErrorMessage(error: unknown): string {\n return String((error as Error | undefined)?.message ?? error ?? 'Unknown error').split('\\n')[0];\n}\n\nfunction shouldUseAuthFallback(\n authElements: AuthElements,\n scenarios: AnalysisScenario[],\n intentProfile: IntentProfile,\n): boolean {\n if (intentProfile.mode !== 'auth' && intentProfile.mode !== 'form') return false;\n if (!authElements.usernameInput || !authElements.passwordInput || !authElements.submitButton) return false;\n if (scenarios.length === 0) return true;\n\n const hasCredentialEntry = scenarios.some((scenario) => {\n const filledSelectors = new Set(\n scenario.steps\n .filter((step) => step.action === 'fill')\n .map((step) => step.selector),\n );\n\n return filledSelectors.has(authElements.usernameInput!.selector) && filledSelectors.has(authElements.passwordInput!.selector);\n });\n\n const hasBrokenLocatorWrapper = scenarios.some((scenario) => (\n scenario.assertions.some((assertion) => /page\\.locator\\((['\"])(getBy|locator\\()/i.test(assertion.playwright))\n ));\n\n return hasBrokenLocatorWrapper || !hasCredentialEntry;\n}\n\nfunction defaultStepHuman(action: AnalysisStep['action'], selector: string, value: string): string {\n if (action === 'navigate') return `Navigate to ${value || 'the page'}`;\n if (action === 'fill') return buildFillHuman(`Fill the field ${selector}`, selector, value);\n if (action === 'click') return `Click ${selector}`;\n if (action === 'select') return `Select ${value} in ${selector}`;\n if (action === 'check') return `Check ${selector}`;\n if (action === 'keyboard') return `Press ${value}`;\n return `Interact with ${selector}`;\n}\n\nfunction normalizeStepHuman(\n human: string,\n action: AnalysisStep['action'],\n selector: string,\n value: string,\n): string {\n if (action !== 'fill' && action !== 'select') return human;\n if (!value) return human;\n const explicitTemplate = /\\$\\{CT_VAR_[A-Z0-9_]+\\}/.test(human);\n const quotedValue = human.match(/\\bwith\\s+['\"`]([^'\"`]+)['\"`]/i)?.[1];\n if (explicitTemplate) return human;\n if (quotedValue && !isGenericFillValue(quotedValue)) return human;\n const rewrittenBase = human.replace(/\\s+with\\s+['\"`][^'\"`]+['\"`]\\s*$/i, '').trim() || human;\n return buildFillHuman(rewrittenBase, selector, value);\n}\n\nfunction pickCountedElements(elementMap: ElementMap, normalizedFeature: string): CapturedElement[] {\n const category =\n /\\bbutton/.test(normalizedFeature) ? 'button'\n : /\\blink/.test(normalizedFeature) ? 'link'\n : /\\bheading|title/.test(normalizedFeature) ? 'heading'\n : /\\binput|field|textbox|text box/.test(normalizedFeature) ? 'input'\n : undefined;\n\n if (category) {\n return elementMap.elements.filter((element) => element.category === category);\n }\n\n return elementMap.elements.filter((element) => (\n element.category === 'button' || element.category === 'link' || element.category === 'input'\n ));\n}\n\nfunction countSelectorForFeature(normalizedFeature: string, elements: CapturedElement[]): string {\n if (/\\bbutton/.test(normalizedFeature)) return `getByRole('button')`;\n if (/\\blink/.test(normalizedFeature)) return `getByRole('link')`;\n if (/\\bheading|title/.test(normalizedFeature)) return `getByRole('heading')`;\n if (/\\binput|field|textbox|text box/.test(normalizedFeature)) return `getByRole('textbox')`;\n return elements[0]?.selector ?? `locator('*')`;\n}\n\nfunction normalizePlaywrightAssertion(assertion: AnalysisAssertion): string {\n const repaired = scopeBareSelectorsInAssertion(unwrapWrappedSelectorAssertion(assertion.playwright));\n if (repaired) return ensureStatement(repaired);\n\n const built = buildPlaywrightAssertion(assertion);\n if (built) return built;\n\n return ensureStatement(assertion.playwright);\n}\n\nfunction unwrapWrappedSelectorAssertion(playwright: string): string {\n const trimmed = String(playwright ?? '').trim();\n if (!trimmed) return '';\n\n return trimmed.replace(\n /page\\.locator\\(([\"'])(getBy(?:Role|Text|Label|Placeholder|TestId)\\((?:\\\\.|(?!\\1).)*?\\)|locator\\((?:\\\\.|(?!\\1).)*?\\))\\1\\)/g,\n 'page.$2',\n );\n}\n\nfunction scopeBareSelectorsInAssertion(playwright: string): string {\n const trimmed = String(playwright ?? '').trim();\n if (!trimmed) return '';\n\n return trimmed.replace(\n /\\bexpect\\((getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\(/g,\n 'expect(page.$1(',\n );\n}\n\nfunction buildPlaywrightAssertion(assertion: AnalysisAssertion): string {\n if (assertion.selector === 'page') {\n if (assertion.type === 'url' && assertion.expected) {\n return `await expect(page).toHaveURL(${JSON.stringify(assertion.expected)});`;\n }\n return '';\n }\n\n const target = selectorTarget(assertion.selector);\n if (!target) return '';\n\n if (assertion.type === 'value' && assertion.expected) {\n return `await expect(${target}).toHaveValue(${JSON.stringify(assertion.expected)});`;\n }\n\n const combined = `${assertion.expected} ${assertion.human} ${assertion.playwright}`.toLowerCase();\n if (/hidden|not visible|no longer visible|disappear/.test(combined)) {\n return `await expect(${target}).not.toBeVisible();`;\n }\n\n return `await expect(${target}).toBeVisible();`;\n}\n\nfunction selectorTarget(selector: string): string {\n const trimmed = String(selector ?? '').trim();\n if (!trimmed || trimmed === 'page') return 'page';\n if (trimmed.startsWith('page.')) return trimmed;\n return `page.${trimmed}`;\n}\n\nfunction visibleAssertion(selector: string): string {\n return `await expect(${selectorTarget(selector)}).toBeVisible();`;\n}\n\nfunction valueAssertion(selector: string, value: string): string {\n return `await expect(${selectorTarget(selector)}).toHaveValue(${JSON.stringify(value)});`;\n}\n\nfunction inferAuthValue(element: CapturedElement, kind: 'username' | 'password'): string {\n if (kind === 'password') return resolveFieldRuntimeValue(element.selector, 'test-password');\n return resolveFieldRuntimeValue(element.selector, '');\n}\n\nfunction buildFillHuman(base: string, selector: string, runtimeValue: string): string {\n const displayValue = resolveFieldDisplayValue(selector, runtimeValue);\n return `${base} with '${displayValue}'`;\n}\n\nfunction resolveFieldRuntimeValue(selector: string, currentValue: string): string {\n if (currentValue && !isGenericFillValue(currentValue) && !extractCtVarTemplate(currentValue)) {\n return currentValue;\n }\n\n const envKey = matchCtVarKey(selector);\n if (envKey && process.env[envKey]) {\n return String(process.env[envKey]);\n }\n\n return fallbackFieldValue(selector);\n}\n\nfunction resolveFieldDisplayValue(selector: string, runtimeValue: string): string {\n const envKey = matchCtVarKey(selector);\n if (envKey) return `\\${${envKey}}`;\n return runtimeValue;\n}\n\nfunction matchCtVarKey(selectorOrText: string): string | undefined {\n const haystack = selectorOrText.toLowerCase();\n const preferred =\n /\\bemail\\b/.test(haystack) ? 'CT_VAR_EMAIL'\n : /\\bpassword\\b/.test(haystack) ? 'CT_VAR_PASSWORD'\n : /\\bsearch\\b/.test(haystack) ? 'CT_VAR_SEARCH'\n : /\\bphone|tel\\b/.test(haystack) ? 'CT_VAR_PHONE'\n : /\\bname\\b/.test(haystack) ? 'CT_VAR_NAME'\n : /\\buser(?:name)?|login\\b/.test(haystack) ? 'CT_VAR_USERNAME'\n : undefined;\n if (preferred && process.env[preferred] !== undefined) return preferred;\n return getAvailableCtVarKeys().find((key) => new RegExp(key.replace(/^CT_VAR_/, '').toLowerCase()).test(haystack));\n}\n\nfunction fallbackFieldValue(selectorOrText: string): string {\n const haystack = selectorOrText.toLowerCase();\n if (/\\bemail\\b/.test(haystack)) return 'test-email@example.com';\n if (/\\bpassword\\b/.test(haystack)) return 'test-password';\n if (/\\bsearch\\b/.test(haystack)) return 'test-search';\n if (/\\bphone|tel\\b/.test(haystack)) return 'test-phone';\n if (/\\bname\\b/.test(haystack) && !/\\buser(?:name)?\\b/.test(haystack)) return 'test-name';\n if (/\\buser(?:name)?|login\\b/.test(haystack)) return 'test-username';\n return 'test-input';\n}\n\nfunction isGenericFillValue(value: string): boolean {\n return /^(?:value|text|input|option|selection|selected value|default)$/i.test(value.trim());\n}\n\nfunction extractCtVarTemplate(value: string): string | undefined {\n return value.match(/^\\$\\{(CT_VAR_[A-Z0-9_]+)\\}$/)?.[1];\n}\n\nfunction isAllowedSelector(selector: string, selectors: Set<string>): boolean {\n if (selector === 'page') return true;\n if (selectors.has(selector)) return true;\n if (/\\.or\\(page\\.(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\(/.test(selector)) {\n const primary = selector.replace(/\\.or\\(page\\.(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|locator)\\([\\s\\S]*\\)\\)\\s*$/, '');\n return isAllowedSelector(primary, selectors);\n }\n\n return /^(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId)\\(/.test(selector)\n || /^locator\\((['\"])(#.+?)\\1\\)$/.test(selector);\n}\n\nfunction ensureStatement(value: string): string {\n const trimmed = String(value ?? '').trim();\n if (!trimmed) return '';\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n}\n\nfunction ensureNavigateStep(steps: AnalysisStep[], url: string): AnalysisStep[] {\n if (!url || steps.length === 0) return steps;\n if (steps.some((step) => step.action === 'navigate')) return steps;\n\n return [\n {\n action: 'navigate',\n selector: 'page',\n value: url,\n human: `Navigate to ${url}`,\n },\n ...steps,\n ];\n}\n\nfunction log(verbose: boolean, message: string): void {\n if (verbose) console.log(message);\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { AnalysisResult } from './analyse.js';\nimport type { ElementMap } from './capture.js';\n\nexport function printCaptureReport(elementMap: ElementMap, analysis?: AnalysisResult | null): void {\n console.log('');\n console.log('='.repeat(60));\n console.log('CementicTest Capture Report');\n console.log('='.repeat(60));\n console.log(`URL: ${elementMap.url}`);\n console.log(`Title: ${elementMap.title}`);\n console.log(`Captured: ${elementMap.timestamp} (${elementMap.mode})`);\n console.log('');\n console.log('Elements:');\n\n for (const [category, count] of Object.entries(elementMap.summary.byCategory)) {\n console.log(` ${category}: ${count}`);\n }\n\n if (elementMap.warnings.length > 0) {\n console.log('');\n console.log('Warnings:');\n for (const warning of elementMap.warnings) {\n console.log(` - ${warning}`);\n }\n }\n\n if (analysis) {\n console.log('');\n console.log(`AI scenarios: ${analysis.scenarios.length}`);\n console.log(`Feature: ${analysis.feature}`);\n console.log(`Prefix: ${analysis.suggestedPrefix}`);\n }\n\n console.log('');\n}\n\nexport function saveCaptureJson(\n elementMap: ElementMap,\n analysis?: AnalysisResult | null,\n outputDir = '.cementic/capture',\n): string {\n mkdirSync(outputDir, { recursive: true });\n\n const fileName = `capture-${slugify(elementMap.url)}-${Date.now()}.json`;\n const filePath = join(outputDir, fileName);\n\n writeFileSync(filePath, JSON.stringify({\n _meta: {\n version: '0.2.17',\n generatedAt: new Date().toISOString(),\n tool: '@cementic/cementic-test',\n },\n elementMap,\n analysis: analysis ?? null,\n }, null, 2));\n\n return filePath;\n}\n\nexport function buildCasesMarkdown(analysis: AnalysisResult): string {\n const lines: string[] = [];\n\n for (const scenario of analysis.scenarios) {\n lines.push(`# ${scenario.id} — ${scenario.title} ${scenario.tags.map(normalizeTag).join(' ')}`.trim());\n lines.push(`<!-- ct:url ${analysis.url} -->`);\n lines.push(`<!-- ct:feature ${analysis.feature} -->`);\n lines.push(`<!-- ct:generated-by capture -->`);\n lines.push(`<!-- narrator: ${sanitizeComment(scenario.narrator)} -->`);\n lines.push(`<!-- code-level: ${scenario.codeLevel} -->`);\n lines.push('');\n lines.push('## Steps');\n\n scenario.steps.forEach((step, index) => {\n const hint = step.selector && step.selector !== 'page'\n ? ` <!-- selector: ${step.selector} -->`\n : '';\n lines.push(`${index + 1}. ${step.human}${hint}`);\n });\n\n lines.push('');\n lines.push('## Expected Results');\n\n scenario.assertions.forEach((assertion) => {\n const hint = assertion.playwright\n ? ` <!-- playwright: ${sanitizeComment(assertion.playwright)} -->`\n : '';\n lines.push(`- ${assertion.human}${hint}`);\n });\n\n lines.push('');\n lines.push('---');\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nexport function saveCasesMarkdown(\n analysis: AnalysisResult,\n outputDir = 'cases',\n fileName?: string,\n): string {\n mkdirSync(outputDir, { recursive: true });\n\n const resolvedFileName = fileName ?? `${slugify(analysis.feature || analysis.url)}.md`;\n const filePath = join(outputDir, resolvedFileName);\n\n writeFileSync(filePath, buildCasesMarkdown(analysis));\n return filePath;\n}\n\nexport function saveSpecPreview(\n analysis: AnalysisResult,\n outputDir = 'tests/preview',\n): string | null {\n if (analysis.scenarios.length === 0) return null;\n\n mkdirSync(outputDir, { recursive: true });\n\n const fileName = `spec-preview-${slugify(analysis.url)}-${Date.now()}.spec.cjs`;\n const filePath = join(outputDir, fileName);\n const lines: string[] = [];\n\n lines.push('/**');\n lines.push(' * CementicTest Capture Preview');\n lines.push(` * Generated from: ${analysis.url}`);\n lines.push(` * Feature: ${analysis.feature}`);\n lines.push(' */');\n lines.push('');\n lines.push(`const { test, expect } = require('@playwright/test');`);\n lines.push('');\n\n for (const scenario of analysis.scenarios) {\n lines.push(`test(${JSON.stringify(`${scenario.id} — ${scenario.title}`)}, async ({ page }) => {`);\n for (const step of scenario.steps) {\n if (step.action === 'navigate') {\n lines.push(` await page.goto(${JSON.stringify(step.value)});`);\n continue;\n }\n\n if (step.selector === 'page') continue;\n const selector = `page.${step.selector}`;\n\n if (step.action === 'fill') lines.push(` await ${selector}.fill(${JSON.stringify(step.value)});`);\n if (step.action === 'click') lines.push(` await ${selector}.click();`);\n if (step.action === 'select') lines.push(` await ${selector}.selectOption(${JSON.stringify(step.value)});`);\n if (step.action === 'check') lines.push(` await ${selector}.check();`);\n if (step.action === 'keyboard') lines.push(` await page.keyboard.press(${JSON.stringify(step.value)});`);\n if (step.action === 'hover') lines.push(` await ${selector}.hover();`);\n }\n\n for (const assertion of scenario.assertions) {\n lines.push(` ${renderPreviewAssertion(assertion.playwright, assertion.human)}`);\n }\n\n lines.push('});');\n lines.push('');\n }\n\n writeFileSync(filePath, lines.join('\\n'));\n return filePath;\n}\n\nfunction slugify(value: string): string {\n return (value || 'capture')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase()\n .slice(0, 60);\n}\n\nfunction normalizeTag(value: string): string {\n const cleaned = String(value ?? '').trim();\n if (!cleaned) return '@ui';\n return cleaned.startsWith('@') ? cleaned : `@${cleaned}`;\n}\n\nfunction sanitizeComment(value: string): string {\n return String(value ?? '').replace(/-->/g, '-- >');\n}\n\nfunction ensureStatement(value: string): string {\n const trimmed = String(value ?? '').trim();\n if (!trimmed) return '// TODO: add assertion';\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n}\n\nfunction renderPreviewAssertion(playwright: string, human?: string): string {\n const statement = ensureStatement(playwright);\n const headingMatch = statement.match(/^await expect\\(page\\.getByRole\\((['\"])heading\\1\\)\\)\\.toBeVisible\\(\\);$/);\n const visibleSubject = String(human ?? '').match(/^(.+?) is visible$/)?.[1]?.trim();\n\n if (headingMatch && visibleSubject && !/main page heading/i.test(visibleSubject)) {\n return `await expect(page.getByRole(\"heading\", { name: ${JSON.stringify(visibleSubject)} })).toBeVisible();`;\n }\n\n return statement;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nexport function reportCmd() {\n const cmd = new Command('report')\n .description('Open the Playwright HTML report')\n .action(() => {\n console.log('📊 Opening Playwright HTML report...');\n \n const child = spawn(\n 'npx',\n ['playwright', 'show-report'],\n {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport function serveCmd() {\n const cmd = new Command('serve')\n .description('Serve the Allure report')\n .action(() => {\n console.log('📊 Serving Allure report...');\n\n // Try to find the local allure binary first (more reliable than global/npx sometimes)\n const localAllureBin = join(process.cwd(), 'node_modules', 'allure-commandline', 'bin', 'allure');\n \n let executable = 'npx';\n let args = ['allure', 'serve', './allure-results'];\n\n // If we can find the direct binary, use it (node node_modules/.../allure)\n // This bypasses the \"require('../')\" issue in the .bin wrapper\n if (existsSync(localAllureBin)) {\n executable = 'node';\n args = [localAllureBin, 'serve', './allure-results'];\n }\n\n console.log(`> ${executable} ${args.join(' ')}`);\n\n const child = spawn(\n executable,\n args,\n {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n }\n );\n\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\n\nfunction runStep(cmd: string, args: string[], stepName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n console.log(`\\n🌊 Flow Step: ${stepName}`);\n console.log(`> ${cmd} ${args.join(' ')}`);\n\n const child = spawn(cmd, args, {\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`${stepName} failed with exit code ${code}`));\n }\n });\n });\n}\n\nexport function flowCmd() {\n const cmd = new Command('flow')\n .description('End-to-end flow: Normalize -> Generate -> Run Tests')\n .argument('[casesDir]', 'Directory containing test cases', './cases')\n .option('--lang <lang>', 'Target language (ts|js)', 'ts')\n .option('--no-run', 'Skip running tests')\n .action(async (casesDir, opts) => {\n const cliBin = resolve(process.argv[1]); // The current CLI executable\n\n try {\n // 1. Normalize\n await runStep(process.execPath, [cliBin, 'normalize', casesDir], 'Normalize Cases');\n\n // 2. Generate\n await runStep(process.execPath, [cliBin, 'gen', '--lang', opts.lang], 'Generate Tests');\n\n // 3. Test (unless skipped)\n if (opts.run) {\n await runStep(process.execPath, [cliBin, 'test'], 'Run Playwright Tests');\n } else {\n console.log('\\n⏭️ Skipping test execution (--no-run)');\n }\n\n console.log('\\n✅ Flow completed successfully!');\n } catch (err: any) {\n console.error(`\\n❌ Flow failed: ${err.message}`);\n process.exit(1);\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { mkdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst WORKFLOW_CONTENT = `name: Playwright Tests\non:\n push:\n branches: [ main, master ]\n pull_request:\n branches: [ main, master ]\njobs:\n test:\n timeout-minutes: 60\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: lts/*\n - name: Install dependencies\n run: npm ci\n - name: Install Playwright Browsers\n run: npx playwright install --with-deps\n - name: Run Playwright tests\n run: npx playwright test\n - uses: actions/upload-artifact@v4\n if: always()\n with:\n name: playwright-report\n path: playwright-report/\n retention-days: 30\n`;\n\nexport function ciCmd() {\n const cmd = new Command('ci')\n .description('Generate GitHub Actions workflow for CI')\n .action(() => {\n const githubDir = join(process.cwd(), '.github');\n const workflowsDir = join(githubDir, 'workflows');\n const workflowFile = join(workflowsDir, 'cementic.yml');\n\n console.log('🤖 Setting up CI/CD workflow...');\n\n if (!existsSync(workflowsDir)) {\n mkdirSync(workflowsDir, { recursive: true });\n console.log(`Created directory: ${workflowsDir}`);\n }\n\n if (existsSync(workflowFile)) {\n console.warn(`⚠️ Workflow file already exists at ${workflowFile}. Skipping.`);\n return;\n }\n\n writeFileSync(workflowFile, WORKFLOW_CONTENT.trim() + '\\n');\n console.log(`✅ CI workflow generated at: ${workflowFile}`);\n console.log('Next steps:');\n console.log('1. Commit and push the new file');\n console.log('2. Check the \"Actions\" tab in your GitHub repository');\n });\n\n return cmd;\n}\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,WAAAA,gBAAe;AACxB,SAAS,qBAAqB;;;ACD9B,SAAS,eAAe;AACxB,SAAS,WAAW,eAAe,YAAY,cAAc,QAAQ,aAAa,gBAAgB;AAClG,SAAS,MAAM,eAAe;AAC9B,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,UAAU,eAAe;AAElC,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AACpC,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,wBAAwB;AAY9B,SAAS,oBAAoB,aAAyC;AACpE,QAAM,aAAa;AAAA,IACjB,QAAQ,WAAW,aAAa,WAAW,EAAE;AAAA,IAC7C,QAAQ,WAAW,gBAAgB,WAAW,EAAE;AAAA,IAChD,QAAQ,WAAW,mBAAmB,WAAW,EAAE;AAAA,IACnD,QAAQ,QAAQ,IAAI,GAAG,aAAa,WAAW,EAAE;AAAA,EACnD;AAEA,SAAO,WAAW,KAAK,eAAa,WAAW,SAAS,CAAC;AAC3D;AAEA,SAAS,gBAAgB,MAAyB,QAAQ,KAAa;AACrE,UAAQ,IAAI,2BAA2B,SAAS,GAAG,KAAK,EAAE,YAAY;AACxE;AAEA,SAAS,eAAe,MAAyB,QAAQ,KAAa;AACpE,UAAQ,IAAI,0BAA0B,QAAQ,GAAG,KAAK;AACxD;AAEA,SAAS,cAAc,MAAyB,QAAQ,KAAc;AACpE,MAAI,gBAAgB,GAAG,MAAM,SAAU,QAAO;AAE9C,QAAM,eAAe,SAAS,eAAe,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE;AACnE,SAAO,OAAO,SAAS,YAAY,KAAK,eAAe;AACzD;AAEA,SAAS,6BAA6B,KAAqC;AACzE,QAAM,UAAU,OAAO,OAAO,MAAM,EAAE,KAAK,EAAE,YAAY;AACzD,MAAI,YAAY,UAAU,YAAY,SAAS,YAAY,WAAY,QAAO;AAE9E,UAAQ,MAAM,+CAA0C,GAAG,sCAAsC;AACjG,UAAQ,KAAK,CAAC;AAChB;AAEA,SAAS,qBACP,gBACA,MAAyB,QAAQ,KAClB;AACf,QAAM,cAAc,cAAc,GAAG;AACrC,QAAM,kBACJ,mBAAmB,SACd,cAAc,aAAa,QAC5B;AAEN,SAAO;AAAA,IACL,oBAAoB,oBAAoB,aAAa,CAAC,cAAc,WAAW,UAAU,IAAI,CAAC,cAAc,SAAS;AAAA,IACrH,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,yBAAyB,cACrB;AAAA,MACE,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,IACvB,IACA,CAAC;AAAA,IACL,QAAQ,cACJ,kHACA;AAAA,EACN;AACF;AAEA,SAAS,6BAA6B,aAAqB,kBAAgD;AACzG,MAAI,OAAO,KAAK,gBAAgB,EAAE,WAAW,EAAG;AAEhD,QAAM,cAAc,KAAK,aAAa,cAAc;AACpD,MAAI,CAAC,WAAW,WAAW,EAAG;AAE9B,MAAI;AACF,UAAM,aAAa,aAAa,aAAa,OAAO;AACpD,UAAM,MAAM,KAAK,MAAM,UAAU;AACjC,UAAM,kBAAkB,IAAI,mBAAmB,CAAC;AAEhD,QAAI,UAAU;AACd,eAAW,CAAC,MAAMC,QAAO,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AAC9D,UAAI,OAAO,gBAAgB,IAAI,MAAM,SAAU;AAC/C,sBAAgB,IAAI,IAAIA;AACxB,gBAAU;AAAA,IACZ;AAEA,QAAI,CAAC,QAAS;AAEd,QAAI,kBAAkB;AACtB,kBAAc,aAAa,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AACvD,YAAQ,IAAI,gEAA2D;AAAA,EACzE,SAAS,KAAK;AACZ,YAAQ,KAAK,oEAA0D,GAAG;AAAA,EAC5E;AACF;AAEO,SAAS,SAAS;AACvB,QAAM,MAAM,IAAI,QAAQ,KAAK,EAC1B,UAAU,eAAe,EACzB,YAAY,+DAA+D,EAC3E,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,CAKzB,EACI,OAAO,iBAAiB,sBAAsB,YAAY,EAC1D,OAAO,iBAAiB,6BAA6B,IAAI,EACzD,OAAO,2BAA2B,+CAA+C,MAAM,EACvF,OAAO,iBAAiB,kDAAkD,EAC1E,OAAO,CAAC,aAAqB,SAAS;AACrC,UAAM,OAAO,OAAO,KAAK,QAAQ,YAAY,EAAE,KAAK,EAAE,YAAY;AAClE,QAAI,SAAS,cAAc;AACzB,cAAQ,MAAM,qCAAgC,KAAK,IAAI,gDAAgD;AACvG,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,wBAAwB,6BAA6B,KAAK,UAAU;AAC1E,UAAM,gBAAgB,qBAAqB,qBAAqB;AAEhE,UAAM,OAAO,QAAQ,IAAI;AACzB,UAAM,cAAc,KAAK,MAAM,WAAW;AAE1C,YAAQ,IAAI,sDAA+C,WAAW,KAAK;AAG3E,QAAI,WAAW,WAAW,GAAG;AAC3B,cAAQ,MAAM,oBAAe,WAAW,kBAAkB;AAC1D,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,cAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAE1C,UAAM,OAAO,KAAK,SAAS,OAAO,OAAO;AACzC,UAAM,cAAc,SAAS,OAAO,yBAAyB;AAC7D,UAAM,eAAe,oBAAoB,WAAW;AAEpD,QAAI,CAAC,cAAc;AACjB,cAAQ,MAAM,qCAAgC,WAAW,GAAG;AAC5D,cAAQ,MAAM,uEAAuE;AACrF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,IAAI,mCAA4B,YAAY,KAAK;AAGzD,aAAS,cAAc,KAAa,MAAc;AAChD,UAAI,SAAS,GAAG,EAAE,YAAY,GAAG;AAC/B,kBAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACnC,oBAAY,GAAG,EAAE,QAAQ,WAAS;AAChC,wBAAc,KAAK,KAAK,KAAK,GAAG,KAAK,MAAM,KAAK,CAAC;AAAA,QACnD,CAAC;AAAA,MACH,OAAO;AACL,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,kBAAc,cAAc,WAAW;AAEvC,QAAI,cAAc,QAAQ;AACxB,cAAQ,IAAI,aAAM,cAAc,MAAM,EAAE;AAAA,IAC1C;AACA,iCAA6B,aAAa,cAAc,uBAAuB;AAG/E,QAAI;AACF,eAAS,YAAY,EAAE,KAAK,aAAa,OAAO,SAAS,CAAC;AAE1D,YAAM,gBAAgB,KAAK,aAAa,YAAY;AACpD,UAAI,CAAC,WAAW,aAAa,GAAG;AAC5B,sBAAc,eAAe,kEAAkE;AAAA,MACnG;AAAA,IACF,SAAS,GAAG;AACV,cAAQ,KAAK,mDAAyC;AAAA,IACxD;AAGA,YAAQ,IAAI,sCAA+B;AAC3C,QAAI,wBAAwB;AAC5B,QAAI;AACF,eAAS,eAAe,EAAE,KAAK,aAAa,OAAO,UAAU,CAAC;AAC9D,8BAAwB;AAAA,IAC1B,SAAS,GAAG;AACV,cAAQ,MAAM,2EAAsE;AAAA,IACtF;AAIA,QAAI,KAAK,aAAa,SAAS,uBAAuB;AACpD,cAAQ,IAAI,6CAAsC;AAClD,UAAI;AACF,cAAM,iBAAiB,OAAO,cAAc,mBAAmB,KAAK,GAAG,CAAC;AACxE,YAAI,cAAc,mBAAmB,cAAc,cAAc,eAAe;AAC9E,kBAAQ,IAAI,yFAA+E;AAAA,QAC7F,WAAW,cAAc,mBAAmB,YAAY;AACtD,kBAAQ,IAAI,qFAA2E;AAAA,QACzF;AACA,iBAAS,gBAAgB,EAAE,KAAK,aAAa,OAAO,UAAU,CAAC;AAC/D,gBAAQ;AAAA,UACN,cAAc,mBAAmB,aAC7B,4CACA;AAAA,QACN;AAAA,MACF,SAAS,GAAG;AACV,gBAAQ,KAAK,gFAAsE;AACnF,gBAAQ,KAAK,SAAS,cAAc,mBAAmB,KAAK,GAAG,CAAC,EAAE;AAAA,MACpE;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,iBAAe,WAAW,wBAAwB;AAC9D,YAAQ,IAAI;AAAA;AAAA,CAAqB;AACjC,YAAQ,IAAI,QAAQ,WAAW,EAAE;AACjC,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI;AAAA,yBAAqB;AAAA,EACnC,CAAC;AAEH,SAAO;AACT;;;ACvOA,SAAS,WAAAC,gBAAe;AACxB,OAAO,QAAQ;AACf,SAAS,gBAAAC,eAAc,aAAAC,YAAW,iBAAAC,gBAAe,YAAAC,iBAAgB;AACjE,SAAS,QAAAC,OAAM,UAAU,WAAAC,gBAAe;AAiBxC,SAAS,UAAU,OAAkD;AACnE,QAAM,OAAO,MAAM,KAAK,MAAM,SAAS,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACrE,QAAM,QAAQ,MAAM,QAAQ,YAAY,EAAE,EAAE,KAAK;AACjD,SAAO,EAAE,OAAO,KAAK;AACvB;AAGA,SAAS,QAAQ,OAAmC;AAClD,QAAM,IAAI,MAAM,MAAM,kBAAkB;AACxC,SAAO,IAAI,CAAC;AACd;AAEA,SAAS,uBAAuB,OAAe,IAAqB;AAClE,MAAI,CAAC,GAAI,QAAO,MAAM,KAAK;AAC3B,SAAO,MAAM,QAAQ,IAAI,OAAO,IAAI,EAAE,4BAAkB,GAAG,EAAE,EAAE,KAAK;AACtE;AAGA,SAAS,oBAAoB,UAA8D;AACzF,QAAM,QAAQ,SAAS,MAAM,OAAO;AACpC,QAAM,SAAqD,CAAC;AAC5D,MAAI,eAA8B;AAClC,MAAI,MAAgB,CAAC;AAErB,QAAM,QAAQ,MAAM;AAClB,QAAI,iBAAiB,MAAM;AACzB,aAAO,KAAK,EAAE,WAAW,cAAc,MAAM,IAAI,KAAK,IAAI,EAAE,CAAC;AAAA,IAC/D;AACA,UAAM,CAAC;AAAA,EACT;AAEA,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAK,KAAK,MAAM,eAAe;AACrC,QAAI,IAAI;AACN,UAAI,iBAAiB,KAAM,OAAM;AACjC,qBAAe,GAAG,CAAC,EAAE,KAAK;AAAA,IAC5B,OAAO;AACL,UAAI,KAAK,IAAI;AAAA,IACf;AAAA,EACF;AACA,MAAI,iBAAiB,KAAM,OAAM;AAGjC,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AACxC,UAAM,QAAQ,OAAO,QAAQ,SAAS,EAAE,EAAE,KAAK,KAAK;AACpD,WAAO,CAAC,EAAE,WAAW,OAAO,MAAM,MAAM,KAAK,IAAI,EAAE,CAAC;AAAA,EACtD;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,MAKvB;AAGA,QAAM,eAAe;AACrB,QAAM,WAAmC,CAAC;AAC1C,MAAI;AACJ,QAAM,UAAkD,CAAC;AAEzD,SAAQ,QAAQ,aAAa,KAAK,IAAI,GAAI;AACxC,YAAQ,KAAK,EAAE,MAAM,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,MAAM,MAAM,CAAC;AAAA,EACnE;AAGA,UAAQ,KAAK,EAAE,MAAM,WAAW,OAAO,KAAK,OAAO,CAAC;AAEpD,WAAS,IAAI,GAAG,IAAI,QAAQ,SAAS,GAAG,KAAK;AAC3C,UAAM,OAAO,QAAQ,CAAC,EAAE;AACxB,UAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,EAAE,OAAO,QAAQ,IAAI,CAAC,EAAE,KAAK;AAC/D,aAAS,IAAI,IAAI;AAAA,EACnB;AAEA,QAAM,aACJ,SAAS,OAAO,KAChB;AAEF,QAAM,gBACJ,SAAS,UAAU,KACnB,SAAS,kBAAkB,KAC3B,SAAS,MAAM,KACf;AAEF,QAAM,SAAS;AAEf,QAAM,cAAc,MAAM,KAAK,WAAW,SAAS,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;AAC/G,QAAM,QAAQ,YAAY,IAAI,CAAC,UAAU,MAAM,IAAI;AACnD,QAAM,YAAY,YAAY,IAAI,CAAC,WAAW,EAAE,UAAU,MAAM,KAAK,EAAE;AAGvE,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,MAAM,MAAM,KAAK,KAAK,SAAS,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;AAEjG,UAAM,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AAC5C,cAAU,KAAK,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,UAAU,MAAM,KAAK,EAAE,CAAC;AAAA,EAClE;AAEA,QAAM,iBAAiB,MAAM,KAAK,cAAc,SAAS,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,EAAE,KAAK,GAAG,YAAY,CAAC;AACvH,QAAM,gBAAgB,eAAe,IAAI,CAAC,UAAU,MAAM,IAAI;AAC9D,QAAM,iBAAiB,eAAe,IAAI,CAAC,WAAW,EAAE,YAAY,MAAM,KAAK,EAAE;AAGjF,MAAI,cAAc,WAAW,GAAG;AAC9B,UAAM,MAAM,MAAM;AAAA,MAChB,KAAK,SAAS,2DAA2D;AAAA,IAC3E,EAAE,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,EAAE,KAAK,GAAG,YAAY,CAAC;AACvD,kBAAc,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACpD,mBAAe,KAAK,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,YAAY,MAAM,KAAK,EAAE,CAAC;AAAA,EACzE;AAEA,SAAO,EAAE,OAAO,WAAW,UAAU,eAAe,eAAe;AACrE;AAEA,SAAS,mBAAmB,MAAkC;AAC5D,QAAM,QAAQ,KAAK,MAAM,6CAA6C;AACtE,SAAO,QAAQ,CAAC;AAClB;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,SAAO,KAAK,QAAQ,wDAAwD,EAAE;AAChF;AAEA,SAAS,gBACP,OACA,UACiC;AACjC,QAAM,QAAQ,MAAM,MAAM,IAAI,OAAO,qBAAqB,QAAQ,iCAAiC,GAAG,CAAC;AACvG,MAAI,CAAC,MAAO,QAAO,EAAE,MAAM,MAAM,KAAK,EAAE;AACxC,SAAO;AAAA,IACL,MAAM,MAAM,CAAC,EAAE,KAAK;AAAA,IACpB,MAAM,MAAM,CAAC,EAAE,KAAK,KAAK;AAAA,EAC3B;AACF;AAEA,SAAS,oBAAoB,OAAqC;AAChE,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,MAAM,sBAAsB;AAC/C,QAAI,MAAO,QAAO,MAAM,CAAC;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,SAAS,aAAa,WAAmB,MAAc,QAAgC;AACrF,QAAM,EAAE,OAAO,KAAK,IAAI,UAAU,SAAS;AAC3C,QAAM,KAAK,QAAQ,KAAK;AACxB,QAAM,cAAc,mBAAmB,IAAI;AAC3C,QAAM,YAAY,gBAAgB,IAAI;AACtC,QAAM,EAAE,OAAO,WAAW,UAAU,eAAe,IAAI,gBAAgB,SAAS;AAChF,QAAM,gBAA0B,CAAC;AAEjC,MAAI,MAAM,WAAW,EAAG,eAAc,KAAK,yCAAyC;AACpF,MAAI,SAAS,WAAW,EAAG,eAAc,KAAK,uDAAuD;AAErG,SAAO;AAAA,IACL;AAAA,IACA,OAAO,uBAAuB,OAAO,EAAE;AAAA,IACvC,MAAM,KAAK,SAAS,OAAO;AAAA,IAC3B;AAAA,IACA,YAAY,UAAU,KAAK,UAAQ,KAAK,QAAQ,IAAI,YAAY;AAAA,IAChE;AAAA,IACA,iBAAiB,eAAe,KAAK,UAAQ,KAAK,UAAU,IAAI,iBAAiB;AAAA,IACjF,cAAc,cAAc,SAAS;AAAA,IACrC,gBAAgB;AAAA,IAChB;AAAA,IACA,KAAK,eAAe,oBAAoB,KAAK;AAAA,EAC/C;AACF;AAGO,SAAS,eAAe;AAC7B,QAAM,MAAM,IAAIN,SAAQ,WAAW,EAChC,SAAS,UAAU,6EAA6E,EAChG,YAAY,qEAAqE,EACjF,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,CAKzB,EACI,OAAO,YAAY,0DAA0D,IAAI,EACjF,OAAO,aAAa,yDAAyD,KAAK,EAClF,OAAO,iBAAiB,+DAA+D,IAAI,EAC3F,OAAO,OAAO,WAAmB,SAAgE;AAEhG,QAAI,WAAqB,CAAC;AAC1B,QAAI;AACF,YAAM,MAAMM,SAAQ,SAAS;AAC7B,UAAIF,UAAS,GAAG,EAAE,YAAY,GAAG;AAC/B,cAAM,OAAO,UAAU,QAAQ,OAAO,EAAE;AACxC,mBAAW,CAAC,GAAG,IAAI,0CAA0C;AAAA,MAC/D,OAAO;AACL,mBAAW,CAAC,SAAS;AAAA,MACvB;AAAA,IACF,QAAQ;AACN,iBAAW,CAAC,SAAS;AAAA,IACvB;AAEA,UAAM,QAAQ,MAAM,GAAG,UAAU,EAAE,KAAK,OAAO,WAAW,KAAK,CAAC;AAChE,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,MAAM,uBAAuB,SAAS,EAAE;AAChD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,SAAS;AACf,IAAAF,WAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAErC,UAAM,QAAQ;AAAA,MACZ,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,cAAc,EAAE;AAAA,MAChD,OAAO,CAAC;AAAA,IACV;AAEA,eAAW,KAAK,OAAO;AACrB,YAAM,UAAUD,cAAa,GAAG,MAAM;AAGtC,YAAM,SAAS,oBAAoB,OAAO;AAC1C,iBAAW,SAAS,QAAQ;AAC1B,cAAM,OAAO,aAAa,MAAM,WAAW,MAAM,MAAM,CAAC;AAGxD,cAAM,OAAO,SAAS,CAAC,EAAE,QAAQ,aAAa,EAAE;AAChD,cAAM,UAAU,KAAK,MAAM,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC9D,cAAM,UAAUI,MAAK,QAAQ,GAAG,IAAI,IAAI,MAAM,OAAO;AAErD,QAAAF,eAAc,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAEpD,cAAM,QAAQ;AACd,cAAM,QAAQ;AACd,YAAI,KAAK,aAAc,OAAM,QAAQ;AACrC,cAAM,MAAM,KAAK,EAAE,MAAM,GAAG,YAAY,SAAS,QAAQ,KAAK,eAAe,YAAY,KAAK,CAAC;AAAA,MACjG;AAAA,IACF;AAEA,IAAAA,eAAcE,MAAK,QAAQ,aAAa,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAEzE,QAAI,KAAK,WAAW,OAAO;AACzB,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,gBAAgB,MAAM,QAAQ,KAAK,cAAc,MAAM,QAAQ,MAAM,qBAAqB,MAAM,QAAQ,YAAY;AAAA,QACpH;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG,MAAM,MAAM,IAAI,OAAK,KAAK,EAAE,IAAI,MAAM,EAAE,UAAU,MAAM,EAAE,MAAM,IAAI;AAAA,MACzE;AACA,MAAAH,WAAU,qBAAqB,EAAE,WAAW,KAAK,CAAC;AAClD,MAAAC,eAAc,yCAAyC,MAAM,KAAK,IAAI,CAAC;AAAA,IACzE;AAEA,YAAQ,IAAI,qBAAgB,MAAM,QAAQ,MAAM,+CAA0C;AAE1F,QAAI,KAAK,QAAQ;AACf,YAAM,EAAE,IAAI,IAAI,MAAM,OAAO,mBAAU;AACvC,YAAM,IAAI,EAAE,MAAM,KAAK,QAAQ,MAAM,KAAK,kBAAkB,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;AC5RA,SAAS,WAAAI,gBAAe;AACxB,SAAS,aAAa;AAEf,SAAS,UAAU;AACxB,QAAM,MAAM,IAAIA,SAAQ,MAAM,EAC3B,YAAY,gDAAgD,EAC5D,mBAAmB,IAAI,EACvB,qBAAqB,IAAI,EACzB,SAAS,eAAe,yCAAyC,EACjE,OAAO,CAAC,SAAmB,CAAC,MAAM;AACjC,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,CAAC,cAAc,QAAQ,GAAG,MAAM;AAAA,MAChC;AAAA,QACE,OAAO;AAAA,QACP,OAAO,QAAQ,aAAa;AAAA;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AAEH,SAAO;AACT;;;ACzBA,SAAS,WAAAC,gBAAe;AACxB,SAAS,aAAAC,YAAW,iBAAAC,sBAAqB;AACzC,SAAS,QAAAC,aAAY;AACrB,SAAS,uBAAuB;AAChC,SAAS,SAAS,OAAO,UAAU,cAAc;;;ACFjD,IAAM,aAA4D;AAAA,EAChE,EAAE,UAAU,CAAC,SAAS,WAAW,UAAU,QAAQ,gBAAgB,GAAG,QAAQ,OAAO;AAAA,EACrF,EAAE,UAAU,CAAC,aAAa,MAAM,GAAG,QAAQ,OAAO;AAAA,EAClD,EAAE,UAAU,CAAC,WAAW,SAAS,GAAG,QAAQ,OAAO;AAAA,EACnD,EAAE,UAAU,CAAC,QAAQ,QAAQ,GAAG,QAAQ,OAAO;AAAA,EAC/C,EAAE,UAAU,CAAC,YAAY,WAAW,KAAK,GAAG,QAAQ,MAAM;AAAA,EAC1D,EAAE,UAAU,CAAC,SAAS,QAAQ,GAAG,QAAQ,MAAM;AAAA,EAC/C,EAAE,UAAU,CAAC,YAAY,eAAe,QAAQ,GAAG,QAAQ,MAAM;AACnE;AAEA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KAAK,YAAY,EAAE,KAAK;AACjC;AAEA,SAAS,mBAAmB,MAAkC;AAC5D,QAAM,OAAO,cAAc,IAAI;AAC/B,aAAW,SAAS,YAAY;AAC9B,QAAI,MAAM,SAAS,KAAK,OAAK,KAAK,SAAS,CAAC,CAAC,GAAG;AAC9C,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,QAAM,YAAY,KAAK,MAAM,KAAK,EAAE,KAAK,OAAK,WAAW,KAAK,CAAC,CAAC;AAChE,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,UAAU,QAAQ,eAAe,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,YAAY,KAAK;AAC3E;AAEA,SAAS,cAAc,KAAiC;AACtD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD,UAAM,OAAO,SAAS,SAAS,SAAS,CAAC,KAAK;AAC9C,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,mBAAmB,IAAI;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YAAY,QAIjB;AAET,MAAI,OAAO,gBAAgB;AACzB,WAAO,OAAO,eAAe,KAAK,EAAE,YAAY;AAAA,EAClD;AAGA,MAAI,OAAO,aAAa;AACtB,UAAM,cAAc,mBAAmB,OAAO,WAAW;AACzD,QAAI,YAAa,QAAO;AAAA,EAC1B;AAGA,MAAI,OAAO,KAAK;AACd,UAAM,UAAU,cAAc,OAAO,GAAG;AACxC,QAAI,QAAS,QAAO;AAAA,EACtB;AAGA,SAAO;AACT;;;ACrDA,IAAM,iBAAiC,CAAC,YAAY,aAAa,UAAU,QAAQ,QAAQ,QAAQ;AAE5F,SAAS,mBAAmB,MAAyB,QAAQ,KAAqB;AACvF,QAAM,oBAAoB,IAAI,mBAAmB,IAAI,KAAK,EAAE,YAAY;AACxE,QAAM,YAAY,qBAAqB,GAAG;AAE1C,MAAI,kBAAkB;AACpB,QAAI,EAAE,oBAAoB,YAAY;AACpC,YAAM,IAAI;AAAA,QACR,gCAAgC,gBAAgB;AAAA,MAClD;AAAA,IACF;AAEA,UAAM,WAAW,UAAU,gBAAgC;AAC3D,QAAI,CAAC,SAAS,QAAQ;AACpB,YAAM,IAAI;AAAA,QACR,mBAAmB,gBAAgB;AAAA,EAAiD,uBAAuB,CAAC;AAAA,MAC9G;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,aAAW,gBAAgB,gBAAgB;AACzC,QAAI,UAAU,YAAY,EAAE,OAAQ,QAAO,UAAU,YAAY;AAAA,EACnE;AAEA,QAAM,IAAI,MAAM;AAAA,EAA0B,uBAAuB,CAAC,EAAE;AACtE;AAEO,SAAS,yBAAiC;AAC/C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,qBAAqB,KAA8D;AAC1F,SAAO;AAAA,IACL,UAAU;AAAA,MACR,UAAU;AAAA,MACV,aAAa;AAAA,MACb,QAAQ,IAAI,oBAAoB,IAAI,uBAAuB;AAAA,MAC3D,OAAO,IAAI,gBAAgB,IAAI,kBAAkB;AAAA,MACjD,SAAS,IAAI,qBAAqB;AAAA,MAClC,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,MACb,QAAQ,IAAI,qBAAqB,IAAI,wBAAwB;AAAA,MAC7D,OAAO,IAAI,gBAAgB,IAAI,mBAAmB;AAAA,MAClD,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,MACb,QAAQ,IAAI,kBAAkB,IAAI,kBAAkB;AAAA,MACpD,OAAO,IAAI,gBAAgB,IAAI,gBAAgB;AAAA,MAC/C,SAAS,IAAI,mBAAmB;AAAA,MAChC,WAAW;AAAA,IACb;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,aAAa;AAAA,MACb,QAAQ,IAAI,gBAAgB;AAAA,MAC5B,OAAO,IAAI,gBAAgB,IAAI,cAAc;AAAA,MAC7C,SAAS,IAAI,iBAAiB;AAAA,MAC9B,WAAW;AAAA,IACb;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,aAAa;AAAA,MACb,QAAQ,IAAI,gBAAgB,IAAI,oBAAoB;AAAA,MACpD,OAAO,IAAI,gBAAgB,IAAI,cAAc;AAAA,MAC7C,SAAS,IAAI,iBAAiB;AAAA,MAC9B,WAAW;AAAA,IACb;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,aAAa,IAAI,kBAAkB,IAAI,kBAAkB,sBAAsB;AAAA,MAC/E,QAAQ,IAAI,kBAAkB,IAAI,kBAAkB;AAAA,MACpD,OAAO,IAAI,gBAAgB,IAAI,gBAAgB;AAAA,MAC/C,SAAS,IAAI,mBAAmB;AAAA,MAChC,WAAW;AAAA,IACb;AAAA,EACF;AACF;;;AC7FA,SAAS,wBAAkC;AACzC,SAAO,OAAO,KAAK,QAAQ,GAAG,EAC3B,OAAO,CAAC,QAAQ,sBAAsB,KAAK,GAAG,CAAC,EAC/C,KAAK;AACV;AAEA,IAAM,oCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyPxC,KAAK;AAEP,IAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,WAAW;AAAA,EACX,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,OAAO;AACT;AAEA,eAAe,gBAAgB,QAAiC;AAC9D,QAAM,cAAc,OAAO,YAAY;AACvC,QAAM,UAAU,oBAAI,IAAY;AAEhC,aAAW,CAAC,SAAS,GAAG,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AAC7D,QAAI,YAAY,SAAS,OAAO,GAAG;AACjC,cAAQ,IAAI,GAAG;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,QAAM,UAAoB,CAAC;AAE3B,aAAW,OAAO,SAAS;AACzB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC;AAClE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAM,OAAO,KACV,QAAQ,qCAAqC,EAAE,EAC/C,QAAQ,mCAAmC,EAAE,EAC7C,QAAQ,YAAY,GAAG,EACvB,QAAQ,WAAW,MAAM,EACzB,MAAM,GAAG,GAAI;AAEhB,cAAQ,KAAK;AAAA,UAAa,GAAG;AAAA,EAAM,IAAI,EAAE;AAAA,IAC3C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO;AAAA;AAAA;AAAA;AAAA,sOAA2I,QAAQ,KAAK,IAAI,CAAC;AACtK;AAIA,SAAS,qBAA6B;AACpC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uGA2DkG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWzG,iCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8CjC,KAAK;AACP;AAEA,SAAS,iBAAiB,KAA0B;AAClD,QAAM,QAAkB,CAAC;AACzB,QAAM,qBAAqB,sBAAsB;AAEjD,QAAM,KAAK,4BAA4B;AACvC,QAAM,KAAK,IAAI,kBAAkB,KAAK;AACtC,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,sBAAsB;AACjC,QAAM,KAAK,IAAI,OAAO;AACtB,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,0DAA0D;AACrE,QAAM,KAAK,gFAAgF;AAC3F,QAAM,KAAK,EAAE;AAEb,MAAI,IAAI,KAAK;AACX,UAAM,KAAK,aAAa,IAAI,GAAG,EAAE;AACjC,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,IAAI,aAAa;AACnB,UAAM,IAAI,IAAI;AACd,UAAM,KAAK,qBAAqB;AAEhC,QAAI,EAAE,MAAO,OAAM,KAAK,iBAAiB,EAAE,KAAK,EAAE;AAElD,QAAI,EAAE,SAAS,QAAQ;AACrB,YAAM,KAAK,eAAe,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE;AAAA,IACpD;AAEA,QAAI,EAAE,OAAO,QAAQ;AACnB,YAAM,aAAa,EAAE,OAAO,IAAI,OAAK;AACnC,cAAM,QAAQ;AAAA,UACZ,EAAE,SAAS,UAAU,EAAE,KAAK;AAAA,UAC5B,EAAE,eAAe,gBAAgB,EAAE,WAAW;AAAA,UAC9C,EAAE,QAAQ,SAAS,EAAE,IAAI;AAAA,UACzB,EAAE,QAAQ,EAAE,SAAS,UAAU,SAAS,EAAE,IAAI;AAAA,UAC9C,EAAE,UAAU,gBAAgB,EAAE,MAAM;AAAA,QACtC,EAAE,OAAO,OAAO;AAChB,eAAO,MAAM,KAAK,IAAI;AAAA,MACxB,CAAC;AACD,YAAM,KAAK,kBAAkB,WAAW,KAAK,KAAK,CAAC,EAAE;AAAA,IACvD;AAEA,QAAI,EAAE,QAAQ,QAAQ;AACpB,YAAM,KAAK,cAAc,EAAE,QAAQ,KAAK,KAAK,CAAC,EAAE;AAAA,IAClD;AAEA,QAAI,EAAE,MAAM,QAAQ;AAClB,YAAM,KAAK,YAAY,EAAE,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,KAAK,CAAC,EAAE;AAAA,IAC3D;AAEA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,mBAAmB,SAAS,GAAG;AACjC,UAAM,KAAK,oCAAoC;AAC/C,eAAW,UAAU,oBAAoB;AACvC,YAAM,KAAK,KAAK,MAAM,EAAE;AAAA,IAC1B;AACA,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,mGAA4G;AACvH,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,mBAAmB,IAAI,MAAM,EAAE;AAC1C,QAAM,KAAK,yBAAyB,OAAO,IAAI,UAAU,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE;AAC7E,QAAM,KAAK,mCAAmC,IAAI,QAAQ,EAAE;AAC5D,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,qHAAqH;AAChI,QAAM,KAAK,0DAA0D;AAErE,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,eAAe,cACb,QACA,OACA,QACA,MACiB;AACjB,QAAM,WAAW,MAAM,MAAM,yCAAyC;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,aAAa;AAAA,MACb,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,IAC5C,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,EACnE;AAEA,QAAM,OAAY,MAAM,SAAS,KAAK;AACtC,QAAM,UAAU,KAAK,UAAU,CAAC,GAAG,MAAM,KAAK,KAAK;AACnD,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mCAAmC;AACjE,SAAO;AACT;AAIA,eAAe,qBACb,QACA,OACA,SACA,aACA,QACA,MACiB;AACjB,QAAM,WAAW,MAAM,MAAM,GAAG,OAAO,qBAAqB;AAAA,IAC1D,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,MAAM;AAAA,MAC/B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,aAAa;AAAA,MACb,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,QAClC,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,IAAI,MAAM,GAAG,WAAW,cAAc,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,EACxE;AAEA,QAAM,OAAY,MAAM,SAAS,KAAK;AACtC,QAAM,UAAU,KAAK,UAAU,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AAC/D,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC;AAC9D,SAAO;AACT;AAIA,eAAsB,yBAAyB,KAAmC;AAChF,QAAM,iBAAiB,mBAAmB;AAE1C,QAAM,aAAa,MAAM,gBAAgB,IAAI,OAAO;AACpD,QAAM,SAAS,mBAAmB,IAAI;AACtC,QAAM,OAAS,iBAAiB,GAAG;AAEnC,UAAQ,IAAI,mBAAY,eAAe,WAAW,KAAK,eAAe,KAAK,GAAG;AAE9E,MAAI,eAAe,cAAc,aAAa;AAC5C,WAAO,cAAc,eAAe,QAAQ,eAAe,OAAO,QAAQ,IAAI;AAAA,EAChF;AAEA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe,WAAW;AAAA,IAC1B,eAAe;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;;;AC3jBA,SAAS,eAAe,OAAuB;AAC7C,SAAO,MAAM,QAAQ,yBAAyB,MAAM;AACtD;AAEA,IAAMC,qCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyPxC,KAAK;AAEP,IAAMC,oBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,WAAW;AAAA,EACX,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,OAAO;AACT;AAEA,eAAeC,iBAAgB,QAAiC;AAC9D,QAAM,cAAc,OAAO,YAAY;AACvC,QAAM,UAAU,oBAAI,IAAY;AAEhC,aAAW,CAAC,SAAS,GAAG,KAAK,OAAO,QAAQD,iBAAgB,GAAG;AAC7D,QAAI,YAAY,SAAS,OAAO,GAAG;AACjC,cAAQ,IAAI,GAAG;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,QAAM,UAAoB,CAAC;AAE3B,aAAW,OAAO,SAAS;AACzB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC;AAClE,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAM,OAAO,KACV,QAAQ,qCAAqC,EAAE,EAC/C,QAAQ,mCAAmC,EAAE,EAC7C,QAAQ,YAAY,GAAG,EACvB,QAAQ,WAAW,MAAM,EACzB,MAAM,GAAG,GAAI;AAEhB,cAAQ,KAAK;AAAA,UAAa,GAAG;AAAA,EAAM,IAAI,EAAE;AAAA,IAC3C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO;AAAA;AAAA;AAAA;AAAA,sOAA2I,QAAQ,KAAK,IAAI,CAAC;AACtK;AAEA,eAAsB,gBACpB,YACA,UAA2B,CAAC,GACH;AACzB,QAAM,EAAE,UAAU,OAAO,QAAQ,IAAI;AACrC,QAAM,mBAAmB,0BAA0B,SAAS,UAAU;AAEtE,MAAI;AACJ,MAAI;AACF,qBAAiB,mBAAmB;AAAA,EACtC,SAAS,OAAY;AACnB,QAAI,SAAS;AAAA,YAAe,kBAAkB,KAAK,CAAC,EAAE;AACtD,QAAI,SAAS,2DAA2D;AACxE,WAAO,2BAA2B,YAAY,gBAAgB;AAAA,EAChE;AAEA,MAAI,SAAS;AAAA,+BAAkC,eAAe,WAAW,KAAK,eAAe,KAAK,GAAG;AAErG,MAAI;AACF,UAAM,aAAa,MAAMC,iBAAgB,gBAAgB;AACzD,UAAM,eAAe,kBAAkB,IAAI;AAC3C,UAAM,aAAa,gBAAgB,YAAY,gBAAgB;AAE/D,UAAM,cAAc,eAAe,cAAc,cAC7C,MAAMC,eAAc,eAAe,QAAQ,eAAe,OAAO,cAAc,UAAU,IACzF,MAAMC;AAAA,MACJ,eAAe;AAAA,MACf,eAAe;AAAA,MACf,eAAe,WAAW;AAAA,MAC1B,eAAe;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAEJ,UAAM,SAAS,kBAAkB,WAAW;AAC5C,WAAO,iBAAiB,QAAQ,YAAY,gBAAgB;AAAA,EAC9D,SAAS,OAAY;AACnB,QAAI,SAAS,qCAAqC,kBAAkB,KAAK,CAAC,EAAE;AAC5E,QAAI,SAAS,2DAA2D;AACxE,WAAO,2BAA2B,YAAY,gBAAgB;AAAA,EAChE;AACF;AAEA,SAAS,oBAA4B;AACnC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBPJ,kCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA2ChC,KAAK;AACR;AAEA,SAAS,gBAAgB,YAAwB,SAAyB;AACxE,QAAM,QAAkB,CAAC;AACzB,QAAM,eAAe,mBAAmB,UAAU;AAClD,QAAM,qBAAqBK,uBAAsB;AACjD,QAAM,gBAAgB,mBAAmB,OAAO;AAEhD,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,wBAAwB,OAAO,EAAE;AAC5C,QAAM,KAAK,gBAAgB,cAAc,IAAI,EAAE;AAC/C,QAAM,KAAK,uCAAuC,cAAc,YAAY,EAAE;AAC9E,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,kBAAkB;AAC7B,QAAM,KAAK,QAAQ,WAAW,GAAG,EAAE;AACnC,QAAM,KAAK,UAAU,WAAW,KAAK,EAAE;AACvC,QAAM,KAAK,gBAAgB,WAAW,IAAI,OAAO;AACjD,QAAM,KAAK,EAAE;AAEb,aAAW,YAAY,CAAC,SAAS,UAAU,QAAQ,WAAW,QAAQ,GAAY;AAChF,UAAM,QAAQ,WAAW,SAAS,OAAO,CAAC,YAAY,QAAQ,aAAa,QAAQ;AACnF,QAAI,MAAM,WAAW,EAAG;AAExB,UAAM,KAAK,GAAG,SAAS,YAAY,CAAC,MAAM,MAAM,MAAM,UAAU;AAChE,eAAW,QAAQ,MAAM,MAAM,GAAG,aAAa,SAAS,KAAK,MAAM,MAAM,GAAG;AAC1E,YAAM,KAAK,QAAQ,KAAK,UAAU,KAAK,KAAK,QAAQ,EAAE;AACtD,YAAM,KAAK,gBAAgB,KAAK,OAAO,EAAE;AACzC,UAAI,KAAK,YAAY,SAAS,GAAG;AAC/B,cAAM,KAAK,kBAAkB,KAAK,YAAY,MAAM,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE;AAAA,MACzE;AAAA,IACF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,WAAW,SAAS,SAAS,GAAG;AAClC,UAAM,KAAK,mBAAmB;AAC9B,eAAW,WAAW,WAAW,UAAU;AACzC,YAAM,KAAK,OAAO,OAAO,EAAE;AAAA,IAC7B;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,mBAAmB,SAAS,GAAG;AACjC,UAAM,KAAK,+BAA+B;AAC1C,eAAW,UAAU,oBAAoB;AACvC,YAAM,KAAK,OAAO,MAAM,EAAE;AAAA,IAC5B;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,mBAAmB,WAAW,SAAS,OAAO,CAAC,YACnD,QAAQ,aAAa,WAAW,QAAQ,aAAa,YAAY,QAAQ,aAAa,MACvF,EAAE;AACH,QAAM,cAAc,WAAW,SAAS,OAAO,CAAC,YAAY,QAAQ,aAAa,QAAQ,EAAE;AAE3F,QAAM,KAAK,uBAAuB;AAClC,QAAM,KAAK,sCAAsC,gBAAgB,EAAE;AACnE,QAAM,KAAK,yCAAyC,WAAW,EAAE;AACjE,QAAM,KAAK,qFAAqF;AAChG,QAAM,KAAK,wFAAwF;AACnG,QAAM,KAAK,oEAAoE;AAC/E,MAAI,aAAa,iBAAiB,aAAa,iBAAiB,aAAa,cAAc;AACzF,UAAM,KAAK,gJAAgJ;AAC3J,UAAM,KAAK,yIAAyI;AAAA,EACtJ;AACA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kCAAkC;AAE7C,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAeF,eACb,QACA,OACA,cACA,YACiB;AACjB,QAAM,WAAW,MAAM,MAAM,yCAAyC;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,aAAa;AAAA,MACb,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,WAAW,CAAC;AAAA,IAClD,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,iBAAiB,SAAS,MAAM,KAAK,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,EAC9E;AAEA,QAAM,OAAY,MAAM,SAAS,KAAK;AACtC,QAAM,UAAU,KAAK,UAAU,CAAC,GAAG,MAAM,KAAK,KAAK;AACnD,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,kCAAkC;AAChE,SAAO;AACT;AAEA,eAAeC,sBACb,QACA,OACA,SACA,aACA,cACA,YACiB;AACjB,QAAM,WAAW,MAAM,MAAM,GAAG,OAAO,qBAAqB;AAAA,IAC1D,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,MAAM;AAAA,MAC/B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,aAAa;AAAA,MACb,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,aAAa;AAAA,QACxC,EAAE,MAAM,QAAQ,SAAS,WAAW;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,GAAG,WAAW,QAAQ,SAAS,MAAM,KAAK,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,EACnF;AAEA,QAAM,OAAY,MAAM,SAAS,KAAK;AACtC,QAAM,UAAU,KAAK,UAAU,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AAC/D,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mDAAmD;AACjF,SAAO;AACT;AAEA,SAAS,kBAAkB,KAA6B;AACtD,QAAM,WAAW,IACd,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,eAAe,EAAE,EACzB,KAAK;AAER,MAAI;AACF,WAAO,KAAK,MAAM,QAAQ;AAAA,EAC5B,SAAS,OAAY;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,eAAuD,OAAO,WAAW,KAAK;AAAA;AAAA,EAAoB,IAAI,MAAM,GAAG,GAAG,CAAC;AAAA,IACrH;AAAA,EACF;AACF;AAEA,SAAS,iBACP,UACA,YACA,kBACgB;AAChB,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,WAAW,WAAW,UAAU;AACzC,cAAU,IAAI,QAAQ,QAAQ;AAC9B,eAAW,OAAO,QAAQ,YAAa,WAAU,IAAI,GAAG;AAAA,EAC1D;AAEA,QAAM,eAAe,MAAM,QAAQ,SAAS,SAAS,IAAI,SAAS,YAAY,CAAC;AAC/E,QAAM,gBAAgB,mBAAmB,gBAAgB;AACzD,QAAM,aAAa,IAAI,IAAI,WAAW,GAAG;AACzC,QAAM,eAAe,mBAAmB,UAAU;AAClD,QAAM,kBAAkB,oBAAoB,SAAS,WAAW,iBAAiB,UAAU;AAC3F,QAAM,kBAAkB,SAAS,mBAAmB,YAAqB;AAAA,IACvE,aAAa;AAAA,IACb,KAAK,WAAW;AAAA,EAClB,CAAC,GAAG,YAAY;AAChB,QAAM,aAAa,oBAAI,IAAI;AAAA,IACzB,WAAW;AAAA,IACX,GAAG,WAAW,SACX,OAAO,CAAC,YAAY,QAAQ,aAAa,MAAM,EAC/C,IAAI,CAAC,YAAY;AAChB,YAAM,OAAO,QAAQ,YAAY;AACjC,UAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAI;AACF,eAAO,IAAI,IAAI,MAAM,WAAW,GAAG,EAAE;AAAA,MACvC,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,CAAC,EACA,OAAO,OAAO;AAAA,EACnB,CAAC;AAED,QAAM,qBAAqB,aACxB,IAAI,CAAC,aAAa,kBAAkB,UAAU,WAAW,WAAW,GAAG,CAAC,EACxE,OAAO,CAAC,aAAa,SAAS,MAAM,SAAS,KAAK,SAAS,WAAW,SAAS,CAAC,EAChF,IAAI,CAAC,cAAc;AAAA,IAClB,GAAG;AAAA,IACH,MAAM,SAAS,KAAK,IAAI,YAAY;AAAA,IACpC,YAAY,SAAS,WAAW,OAAO,CAAC,cAAc;AACpD,UAAI,UAAU,SAAS,MAAO,QAAO;AACrC,YAAM,WAAW,GAAG,UAAU,QAAQ,IAAI,UAAU,KAAK,IAAI,UAAU,UAAU;AACjF,YAAM,YAAY,SAAS,MAAM,iBAAiB;AAClD,UAAI,CAAC,UAAW,QAAO;AACvB,aAAO,WAAW,IAAI,UAAU,CAAC,CAAC;AAAA,IACpC,CAAC;AAAA,EACH,EAAE,EACD,OAAO,CAAC,aAAa,SAAS,WAAW,SAAS,CAAC;AAEtD,QAAM,yBAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,MAAM,GAAG,cAAc,YAAY;AAErC,QAAM,kBAAkB,sBAAsB,cAAc,wBAAwB,aAAa;AACjG,QAAM,oBAAoB,cAAc,SAAS,aAC7C,2BAA2B,YAAY,kBAAkB,cAAc,IACvE,kBACE,2BAA2B,YAAY,gBAAgB,cAAc,gBAAgB,IACrF,uBAAuB,YAAY,gBAAgB,gBAAgB;AACzE,QAAM,iBAAiB,kBACnB,kBAAkB,MAAM,GAAG,cAAc,YAAY,IACrD,uBAAuB,SAAS,IAChC,yBACA,kBAAkB,MAAM,GAAG,cAAc,YAAY;AAEzD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,KAAK,SAAS,OAAO,WAAW;AAAA,IAChC,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,eAAe;AAAA,MACb,SAAS;AAAA,MACT,kBAAkB,2FAA2F;AAAA,MAC7G,gBAAgB,eAAe,MAAM,qCAAqC,aAAa,MAAM;AAAA,IAC/F,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC1B,cAAc,SAAS,gBAAgB,kBAAkB,iBAAiB,cAAc;AAAA,EAC1F;AACF;AAEA,SAAS,kBAAkB,WAAgB,WAAwB,KAA+B;AAChG,QAAM,QAAQ,MAAM,QAAQ,WAAW,KAAK,IACxC,UAAU,MACP,IAAI,CAAC,SAAc,cAAc,MAAM,SAAS,CAAC,EACjD,OAAO,OAAO,IACjB,CAAC;AAEL,QAAM,aAAa,MAAM,QAAQ,WAAW,UAAU,IAClD,UAAU,WACP,IAAI,CAAC,cAAmB,mBAAmB,WAAW,SAAS,CAAC,EAChE,OAAO,OAAO,IACjB,CAAC;AAEL,QAAM,kBAAkB,mBAAmB,OAAO,GAAG;AAErD,SAAO;AAAA,IACL,IAAI,WAAW,MAAM;AAAA,IACrB,OAAO,WAAW,SAAS;AAAA,IAC3B,MAAM,MAAM,QAAQ,WAAW,IAAI,IAAI,UAAU,OAAO,CAAC;AAAA,IACzD,OAAO;AAAA,IACP;AAAA,IACA,UAAU,WAAW,YAAY;AAAA,IACjC,WAAW,WAAW,aAAa;AAAA,EACrC;AACF;AAEA,SAAS,cAAc,WAAgB,WAA6C;AAClF,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,WAAW,OAAO,UAAU,YAAY,EAAE,EAAE,KAAK;AACvD,MAAI,CAAC,kBAAkB,UAAU,SAAS,EAAG,QAAO;AAEpD,QAAM,SAAS,OAAO,UAAU,UAAU,EAAE,EAAE,KAAK;AACnD,MAAI,CAAC,CAAC,YAAY,QAAQ,SAAS,UAAU,SAAS,YAAY,OAAO,EAAE,SAAS,MAAM,EAAG,QAAO;AAEpG,QAAM,WAAW,OAAO,UAAU,SAAS,EAAE;AAC7C,QAAM,QAAQ,WAAW,UAAU,WAAW,WAC1C,yBAAyB,UAAU,QAAQ,IAC3C;AACJ,QAAM,QAAQ;AAAA,IACZ,OAAO,UAAU,SAAS,EAAE,EAAE,KAAK,KAAK,iBAAiB,QAAQ,UAAU,KAAK;AAAA,IAChF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,WAAgB,WAAkD;AAC5F,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,WAAW,OAAO,UAAU,YAAY,EAAE,EAAE,KAAK;AACvD,MAAI,CAAC,kBAAkB,UAAU,SAAS,EAAG,QAAO;AAEpD,QAAM,YAA+B;AAAA,IACnC,MAAM,OAAO,UAAU,QAAQ,SAAS,EAAE,KAAK,KAAK;AAAA,IACpD;AAAA,IACA,UAAU,OAAO,UAAU,YAAY,EAAE,EAAE,KAAK;AAAA,IAChD,OAAO,OAAO,UAAU,SAAS,EAAE,EAAE,KAAK,KAAK;AAAA,IAC/C,YAAY,OAAO,UAAU,cAAc,EAAE,EAAE,KAAK;AAAA,EACtD;AAEA,YAAU,aAAa,6BAA6B,SAAS;AAC7D,SAAO;AACT;AAEA,SAAS,uBAAuB,YAAwB,QAAoC;AAC1F,SAAO,iCAAiC,YAAY,QAAQ,EAAE;AAChE;AAEA,SAAS,iCACP,YACA,QACA,SACoB;AACpB,QAAM,oBAAoB,QAAQ,YAAY;AAC9C,QAAM,UAAU,WAAW,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,SAAS;AACpF,QAAM,aAAa,WAAW,SAAS,KAAK,CAAC,YAC3C,QAAQ,aAAa,YACpB,QAAQ,WAAW,SAAS,WAAW,QAAQ,KAAK,GAAG,QAAQ,QAAQ,EAAE,IAAI,OAAO,QAAQ,WAAW,SAAS,EAAE,CAAC,GAAG,YAAY,CAAC,EACrI;AACD,QAAM,gBAAgB,WAAW,SAAS,KAAK,CAAC,YAC9C,QAAQ,aAAa,WAAW,QAAQ,WAAW,SAAS,UAC7D;AACD,QAAM,eAAe,WAAW,SAAS,KAAK,CAAC,YAC7C,QAAQ,aAAa,YAAY,iCAAiC,KAAK,QAAQ,QAAQ,EAAE,CAC1F,KAAK,WAAW,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,QAAQ;AACzE,QAAM,QAAQ,iBAAiB,UAAU;AAEzC,QAAM,YAAgC,CAAC;AACvC,QAAM,MAAM,CAAC,UAAkB,aAAa,KAAK;AACjD,QAAM,SAAS,CAAC,UAAkB,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,EAAE,SAAS,GAAG,GAAG,CAAC;AACnF,QAAM,yBACJ,4BAA4B,KAAK,iBAAiB,KAClD,6DAA6D,KAAK,iBAAiB,KACnF,kFAAkF,KAAK,iBAAiB;AAC1G,QAAM,oBACJ,kEAAkE,KAAK,iBAAiB,KACxF,CAAC;AAEH,MAAI,0BAA0B,OAAO;AACnC,WAAO,CAAC;AAAA,MACN,IAAI,GAAG,MAAM;AAAA,MACb,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,UAAU,GAAG,IAAI,IAAI,CAAC;AAAA,MACjC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,UAAU,MAAM;AAAA,UAChB,UAAU;AAAA,UACV,OAAO,GAAG,MAAM,QAAQ,eAAe;AAAA,UACvC,YAAY,qBAAqB,MAAM,QAAQ;AAAA,QACjD;AAAA,MACF;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,qBAAqB,OAAO;AAC9B,WAAO,CAAC;AAAA,MACN,IAAI,GAAG,MAAM;AAAA,MACb,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,UAAU,GAAG,IAAI,IAAI,CAAC;AAAA,MACjC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,UAAU,MAAM;AAAA,UAChB,UAAU,MAAM,QAAQ;AAAA,UACxB,OAAO;AAAA,UACP,YAAY,qBAAqB,MAAM,QAAQ;AAAA,QACjD;AAAA,MACF;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,SAAS;AACX,cAAU,KAAK;AAAA,MACb,IAAI,OAAO,UAAU,SAAS,CAAC;AAAA,MAC/B,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,OAAO,GAAG,IAAI,WAAW,CAAC;AAAA,MACrC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,UAAU,QAAQ;AAAA,UAClB,UAAU;AAAA,UACV,OAAO,GAAG,QAAQ,QAAQ,iBAAiB;AAAA,UAC3C,YAAY,qBAAqB,QAAQ,QAAQ;AAAA,QACnD;AAAA,MACF;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,cAAc,iBAAiB,cAAc;AAC/C,UAAM,aAAa,yBAAyB,WAAW,UAAU,EAAE;AACnE,cAAU,KAAK;AAAA,MACb,IAAI,OAAO,UAAU,SAAS,CAAC;AAAA,MAC/B,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,YAAY,GAAG,IAAI,UAAU,CAAC;AAAA,MACzC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,WAAW;AAAA,UACrB,OAAO;AAAA,UACP,OAAO,eAAe,2BAA2B,WAAW,UAAU,UAAU;AAAA,QAClF;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,aAAa;AAAA,UACvB,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,UAAU;AAAA,UACV,UAAU,IAAI,IAAI,WAAW,GAAG,EAAE;AAAA,UAClC,OAAO;AAAA,UACP,YAAY,iCAAiC,WAAW,GAAG;AAAA,QAC7D;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,UAAU;AAAA,UACV,OAAO;AAAA,UACP,YAAY,qBAAqB,cAAc,QAAQ;AAAA,QACzD;AAAA,MACF;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,UAAU,MAAM,GAAG,CAAC;AAC7B;AAEA,SAAS,2BACP,YACA,QACA,cACA,SACoB;AACpB,QAAM,EAAE,eAAe,eAAe,cAAc,QAAQ,IAAI;AAChE,MAAI,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,cAAc;AACrD,WAAO,iCAAiC,YAAY,QAAQ,OAAO;AAAA,EACrE;AAEA,QAAM,oBAAoB,QAAQ,YAAY;AAC9C,QAAM,YAAgC,CAAC;AACvC,QAAM,MAAM,CAAC,UAAkB,aAAa,KAAK;AACjD,QAAM,SAAS,CAAC,UAAkB,GAAG,MAAM,IAAI,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG,CAAC;AAC7E,QAAM,gBAAgB,eAAe,eAAe,UAAU;AAC9D,QAAM,gBAAgB,eAAe,eAAe,UAAU;AAC9D,QAAM,QAAQ,iBAAiB,UAAU;AACzC,QAAM,kBACJ,mHAAmH,KAAK,iBAAiB,KACzI,gGAAgG,KAAK,iBAAiB;AACxH,QAAM,aACJ,8FAA8F,KAAK,iBAAiB;AACtH,QAAM,oBAAoB,uBAAuB,iBAAiB;AAClE,QAAM,oBAAoB,wBAAwB,YAAY,iBAAiB;AAC/E,QAAM,uBACJ,sBAAsB,UAClB,yBACA,sBAAsB,aACpB,qBACA;AACR,QAAM,uBAAuB,sBAAsB,aAAa,uBAAuB;AAEvF,MAAI,iBAAiB;AACnB,WAAO,CAAC;AAAA,MACN,IAAI,GAAG,MAAM;AAAA,MACb,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,MAAM,GAAG,IAAI,YAAY,CAAC;AAAA,MACrC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,aAAa;AAAA,QAC3F;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,aAAa;AAAA,QAC3F;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,aAAa;AAAA,UACvB,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV;AAAA,UACE,MAAM;AAAA,UACN,UAAU;AAAA,UACV,UAAU;AAAA,UACV,OAAO;AAAA,UACP,YAAY,iCAAiC,iBAAiB;AAAA,QAChE;AAAA,MACF;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,YAAY;AACd,WAAO,CAAC;AAAA,MACN,IAAI,GAAG,MAAM;AAAA,MACb,OAAO;AAAA,MACP,MAAM,CAAC,IAAI,MAAM,GAAG,IAAI,UAAU,CAAC;AAAA,MACnC,OAAO;AAAA,QACL;AAAA,UACE,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,WAAW;AAAA,UAClB,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,oBAAoB;AAAA,QAClG;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,cAAc;AAAA,UACxB,OAAO;AAAA,UACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,oBAAoB;AAAA,QAClG;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,UAAU,aAAa;AAAA,UACvB,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV,QACI;AAAA,UACE,MAAM;AAAA,UACN,UAAU,MAAM;AAAA,UAChB,UAAU,MAAM,QAAQ;AAAA,UACxB,OAAO;AAAA,UACP,YAAY,qBAAqB,MAAM,QAAQ;AAAA,QACjD,IACA;AAAA,UACE,MAAM;AAAA,UACN,UAAU,cAAc;AAAA,UACxB,UAAU;AAAA,UACV,OAAO;AAAA,UACP,YAAY;AAAA,QACd;AAAA,MACN;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,YAAU,KAAK;AAAA,IACb,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO;AAAA,IACP,MAAM,CAAC,IAAI,OAAO,GAAG,IAAI,MAAM,CAAC;AAAA,IAChC,OAAO;AAAA,MACL;AAAA,QACE,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,WAAW;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,GAAI,UAAU,CAAC;AAAA,QACb,MAAM;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,UAAU;AAAA,QACV,OAAO,GAAG,QAAQ,QAAQ,eAAe;AAAA,QACzC,YAAY,iBAAiB,QAAQ,QAAQ;AAAA,MAC/C,CAAC,IAAI,CAAC;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,UAAU,cAAc;AAAA,QACxB,UAAU;AAAA,QACV,OAAO,GAAG,cAAc,QAAQ,gBAAgB;AAAA,QAChD,YAAY,iBAAiB,cAAc,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,cAAc;AAAA,QACxB,UAAU;AAAA,QACV,OAAO,GAAG,cAAc,QAAQ,gBAAgB;AAAA,QAChD,YAAY,iBAAiB,cAAc,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,aAAa;AAAA,QACvB,UAAU;AAAA,QACV,OAAO,GAAG,aAAa,QAAQ,eAAe;AAAA,QAC9C,YAAY,iBAAiB,aAAa,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AAED,YAAU,KAAK;AAAA,IACb,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO;AAAA,IACP,MAAM,CAAC,IAAI,MAAM,GAAG,IAAI,YAAY,CAAC;AAAA,IACrC,OAAO;AAAA,MACL;AAAA,QACE,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,WAAW;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,UAAU,cAAc;AAAA,QACxB,OAAO;AAAA,QACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,aAAa;AAAA,MAC3F;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,UAAU,cAAc;AAAA,QACxB,OAAO;AAAA,QACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,aAAa;AAAA,MAC3F;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV;AAAA,QACE,MAAM;AAAA,QACN,UAAU,cAAc;AAAA,QACxB,UAAU;AAAA,QACV,OAAO;AAAA,QACP,YAAY,eAAe,cAAc,UAAU,aAAa;AAAA,MAClE;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,cAAc;AAAA,QACxB,UAAU;AAAA,QACV,OAAO;AAAA,QACP,YAAY,eAAe,cAAc,UAAU,aAAa;AAAA,MAClE;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,aAAa;AAAA,QACvB,UAAU;AAAA,QACV,OAAO,GAAG,aAAa,QAAQ,eAAe;AAAA,QAC9C,YAAY,iBAAiB,aAAa,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AAED,YAAU,KAAK;AAAA,IACb,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO;AAAA,IACP,MAAM,CAAC,IAAI,MAAM,GAAG,IAAI,UAAU,CAAC;AAAA,IACnC,OAAO;AAAA,MACL;AAAA,QACE,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,WAAW;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,UAAU,cAAc;AAAA,QACxB,OAAO;AAAA,QACP,OAAO,eAAe,8BAA8B,cAAc,UAAU,aAAa;AAAA,MAC3F;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,UAAU,aAAa;AAAA,QACvB,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV;AAAA,QACE,MAAM;AAAA,QACN,UAAU;AAAA,QACV,UAAU,WAAW;AAAA,QACrB,OAAO;AAAA,QACP,YAAY,iCAAiC,WAAW,GAAG;AAAA,MAC7D;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,cAAc;AAAA,QACxB,UAAU;AAAA,QACV,OAAO;AAAA,QACP,YAAY,iBAAiB,cAAc,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU,aAAa;AAAA,QACvB,UAAU;AAAA,QACV,OAAO,GAAG,aAAa,QAAQ,cAAc;AAAA,QAC7C,YAAY,iBAAiB,aAAa,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AAED,SAAO;AACT;AAEA,SAAS,0BAA0B,SAA6B,YAAgC;AAC9F,SAAO,OAAO,WAAW,EAAE,EAAE,KAAK,KAAK,iBAAiB,UAAU;AACpE;AAEA,SAAS,iBAAiB,YAAgC;AACxD,QAAM,UAAU,WAAW,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,aAAa,QAAQ,IAAI;AACpG,SAAO,SAAS,QAAQ,WAAW,SAAS;AAC9C;AAEA,SAASC,yBAAkC;AACzC,SAAO,OAAO,KAAK,QAAQ,GAAG,EAC3B,OAAO,CAAC,QAAQ,sBAAsB,KAAK,GAAG,CAAC,EAC/C,KAAK;AACV;AAEA,SAAS,mBAAmB,SAAgC;AAC1D,QAAM,aAAa,QAAQ,YAAY;AACvC,QAAM,cAAc,uFAAuF,KAAK,UAAU;AAC1H,QAAM,eAAe,wBAAwB,KAAK,UAAU,KACvD,CAAC,6CAA6C,KAAK,UAAU;AAClE,QAAM,eAAe,qBAAqB,UAAU;AACpD,QAAM,aAAa,iDAAiD,KAAK,UAAU,KAAK,CAAC;AACzF,QAAM,aAAa,kDAAkD,KAAK,UAAU,KAAK,CAAC,gBAAgB,CAAC;AAC3G,QAAM,aAAa,yDAAyD,KAAK,UAAU,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC;AACjI,QAAM,OAAmB,cACrB,UACA,eACE,aACF,aACE,SACA,aACE,SACA,aACE,SACA;AACV,QAAM,aAAa,kBAAkB,OAAO;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,cACE,SAAS,UAAU,IACjB,SAAS,aAAa,KAAK,IAAI,KAAK,IAAI,YAAY,CAAC,GAAG,CAAC,IACzD,SAAS,UAAU,SAAS,SAAS,KAAK,IAAI,KAAK,IAAI,YAAY,CAAC,GAAG,CAAC,IACxE,SAAS,SAAS,KAAK,IAAI,KAAK,IAAI,YAAY,CAAC,GAAG,CAAC,IACrD,KAAK,IAAI,KAAK,IAAI,YAAY,CAAC,GAAG,CAAC;AAAA,IACvC;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,SAAyB;AAClD,QAAM,SAAS,MAAM,KAAK,QAAQ,SAAS,yBAAyB,CAAC,EAAE;AACvE,QAAM,WAAW,QACd,MAAM,uBAAuB,EAC7B,IAAI,CAAC,YAAY,QAAQ,KAAK,CAAC,EAC/B,OAAO,OAAO;AACjB,SAAO,KAAK,IAAI,QAAQ,SAAS,UAAU,CAAC;AAC9C;AAEA,SAAS,qBAAqB,mBAAoC;AAChE,QAAM,gBAAgB,oGAAoG,KAAK,iBAAiB;AAChJ,QAAM,cAAc,mIAAmI,KAAK,iBAAiB;AAC7K,SAAO,iBAAiB,CAAC;AAC3B;AAEA,SAAS,kBACP,WACA,YACA,eACA,QACoB;AACpB,MAAI,cAAc,SAAS,SAAS;AAClC,WAAO,oBAAoB,YAAY,cAAc,SAAS,MAAM;AAAA,EACtE;AACA,MAAI,cAAc,SAAS,YAAY;AACrC,WAAO,UAAU,MAAM,GAAG,cAAc,YAAY;AAAA,EACtD;AACA,SAAO,2BAA2B,YAAY,cAAc,SAAS,MAAM;AAC7E;AAEA,SAAS,oBACP,YACA,SACA,QACoB;AACpB,QAAM,aAAa,QAAQ,YAAY;AACvC,QAAM,kBAAkB,oBAAoB,YAAY,UAAU;AAClE,QAAM,WAAW,wBAAwB,YAAY,eAAe;AACpE,QAAM,QAAQ,gBAAgB;AAE9B,SAAO,CAAC;AAAA,IACN,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,IAC3C,OAAO;AAAA,IACP,MAAM,CAAC,UAAU,KAAK;AAAA,IACtB,OAAO;AAAA,MACL;AAAA,QACE,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,WAAW;AAAA,QAClB,OAAO,eAAe,WAAW,GAAG;AAAA,MACtC;AAAA,IACF;AAAA,IACA,YAAY,CAAC;AAAA,MACX,MAAM;AAAA,MACN;AAAA,MACA,UAAU,OAAO,KAAK;AAAA,MACtB,OAAO,qBAAqB,KAAK;AAAA,MACjC,YAAY,qBAAqB,QAAQ,iBAAiB,KAAK;AAAA,IACjE,CAAC;AAAA,IACD,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,2BACP,YACA,SACA,QACoB;AACpB,QAAM,SAAS,sBAAsB,SAAS,UAAU;AACxD,MAAI,OAAO,WAAW,EAAG,QAAO,uBAAuB,YAAY,MAAM,EAAE,MAAM,GAAG,CAAC;AAErF,SAAO,CAAC;AAAA,IACN,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,IAC3C,OAAO;AAAA,IACP,MAAM,CAAC,UAAU,KAAK;AAAA,IACtB,OAAO;AAAA,MACL;AAAA,QACE,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,WAAW;AAAA,QAClB,OAAO,eAAe,WAAW,GAAG;AAAA,MACtC;AAAA,IACF;AAAA,IACA,YAAY,OAAO,IAAI,CAAC,WAAW;AAAA,MACjC,MAAM;AAAA,MACN,UAAU,MAAM;AAAA,MAChB,UAAU;AAAA,MACV,OAAO,MAAM;AAAA,MACb,YAAY,iBAAiB,MAAM,QAAQ;AAAA,IAC7C,EAAE;AAAA,IACF,UAAU;AAAA,IACV,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,sBACP,SACA,YAC4C;AAC5C,QAAM,WAAW,QACd,MAAM,uBAAuB,EAC7B,IAAI,CAAC,YAAY,QAAQ,KAAK,CAAC,EAC/B,OAAO,OAAO;AACjB,QAAM,SAAqD,CAAC;AAE5D,aAAW,WAAW,UAAU;AAC9B,UAAM,aAAa,QAAQ,YAAY;AACvC,QAAI,wBAAwB,KAAK,UAAU,KAAK,CAAC,6CAA6C,KAAK,UAAU,GAAG;AAC9G,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,OAAO,GAAG,qBAAqB,UAAU,GAAG,QAAQ,mBAAmB;AAAA,MACzE,CAAC;AACD;AAAA,IACF;AAEA,UAAM,OAAO,mBAAmB,OAAO;AACvC,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,wBAAwB,YAAY,MAAM,UAAU;AAClE,UAAM,WAAW,oBAAoB,MAAM,YAAY,KAAK;AAC5D,WAAO,KAAK;AAAA,MACV;AAAA,MACA,OAAO,GAAG,IAAI;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,qBAAqB,YAAqD;AACjF,SAAO;AAAA,IACL,WAAW,SAAS,OAAO,CAAC,YAAY,QAAQ,aAAa,SAAS;AAAA,EACxE,EAAE,CAAC;AACL;AAEA,SAAS,mBAAmB,SAAyB;AACnD,QAAM,WAAW,MAAM,KAAK,QAAQ,SAAS,yBAAyB,CAAC,EAAE,IAAI,CAAC,UAAU,MAAM,CAAC,EAAE,KAAK,CAAC;AACvG,MAAI,SAAS,SAAS,EAAG,QAAO,SAAS,CAAC;AAE1C,SAAO,QACJ,QAAQ,yCAAyC,GAAG,EACpD,QAAQ,sBAAsB,GAAG,EACjC,QAAQ,iCAAiC,GAAG,EAC5C,QAAQ,6DAA6D,GAAG,EACxE,QAAQ,qCAAqC,GAAG,EAChD,QAAQ,wCAAwC,GAAG,EACnD,QAAQ,cAAc,GAAG,EACzB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,wBACP,YACA,MACA,SAC6B;AAC7B,QAAM,oBACJ,aAAa,KAAK,OAAO,IAAI,WAC3B,WAAW,KAAK,OAAO,IAAI,SAC3B,cAAc,KAAK,OAAO,IAAI,YAC9B;AACJ,QAAM,QAAQ,KAAK,YAAY;AAC/B,QAAM,aAAa,WAAW,SAAS,OAAO,CAAC,YAAY;AACzD,UAAM,WAAW,GAAG,QAAQ,QAAQ,EAAE,IAAI,QAAQ,OAAO,GAAG,YAAY;AACxE,WAAO,SAAS,SAAS,KAAK;AAAA,EAChC,CAAC;AAED,MAAI,CAAC,kBAAmB,QAAO,aAAa,UAAU,EAAE,CAAC;AAEzD,QAAM,YAAY,WAAW,OAAO,CAAC,YAAY,QAAQ,aAAa,iBAAiB;AACvF,MAAI,UAAU,SAAS,EAAG,QAAO,aAAa,SAAS,EAAE,CAAC;AAE1D,OACG,sBAAsB,YAAY,sBAAsB,WACtD,8BAA8B,SAAS,IAAI,GAC9C;AACA,UAAM,oBAAoB,sBAAsB,WAAW,SAAS;AACpE,UAAM,aAAa,WAAW,OAAO,CAAC,YAAY,QAAQ,aAAa,iBAAiB;AACxF,QAAI,WAAW,SAAS,EAAG,QAAO,aAAa,UAAU,EAAE,CAAC;AAAA,EAC9D;AAEA,SAAO,aAAa,UAAU,EAAE,CAAC;AACnC;AAEA,SAAS,aAAa,UAAgD;AACpE,QAAM,mBAAmB,CAAC,eACxB,eAAe,SAAS,IAAI,eAAe,WAAW,IAAI;AAE5D,QAAM,oBAAoB,CAAC,aACzB,aAAa,YAAY,aAAa,UAAU,aAAa,UAAU,IAAI;AAG7E,SAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,MAAM,UAAU;AACzC,UAAM,kBAAkB,iBAAiB,MAAM,UAAU,IAAI,iBAAiB,KAAK,UAAU;AAC7F,QAAI,oBAAoB,EAAG,QAAO;AAClC,UAAM,mBAAmB,kBAAkB,MAAM,QAAQ,IAAI,kBAAkB,KAAK,QAAQ;AAC5F,QAAI,qBAAqB,EAAG,QAAO;AACnC,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,oBACP,MACA,SACA,OACQ;AACR,MAAI,8BAA8B,SAAS,IAAI,GAAG;AAChD,QAAI,WAAW,KAAK,OAAO,EAAG,QAAO,2BAA2B,MAAM,MAAM;AAC5E,QAAI,aAAa,KAAK,OAAO,KAAK,OAAO,aAAa,UAAU,OAAO,aAAa,UAAU;AAC5F,aAAO,2BAA2B,MAAM,QAAQ;AAAA,IAClD;AAAA,EACF;AAEA,SAAO,OAAO,YAAY,sBAAsB,MAAM,OAAO;AAC/D;AAEA,SAAS,8BAA8B,SAAiB,MAAuB;AAC7E,QAAM,WAAW,GAAG,OAAO,IAAI,IAAI,GAAG,YAAY;AAClD,SAAO,0BAA0B,KAAK,QAAQ,MAE1C,4GAA4G,KAAK,QAAQ,KACtH,QAAQ,KAAK,IAAI;AAE1B;AAEA,SAAS,2BAA2B,MAAc,eAA0C;AAC1F,QAAM,UAAU,kBAAkB,eAAe,IAAI;AACrD,QAAM,YAAY,kBAAkB,kBAAkB,WAAW,SAAS,UAAU,IAAI;AACxF,SAAO,GAAG,OAAO,YAAY,SAAS;AACxC;AAEA,SAAS,kBAAkB,MAAqC,MAAsB;AACpF,QAAM,YAAY,KAAK,QAAQ,uBAAuB,MAAM;AAC5D,SAAO,cAAc,IAAI,eAAe,SAAS;AACnD;AAEA,SAAS,sBAAsB,MAAc,SAAyB;AACpE,MAAI,aAAa,KAAK,OAAO,EAAG,QAAO,kBAAkB,UAAU,IAAI;AACvE,MAAI,WAAW,KAAK,OAAO,EAAG,QAAO,kBAAkB,QAAQ,IAAI;AACnE,MAAI,wBAAwB,KAAK,OAAO,EAAG,QAAO,kBAAkB,WAAW,IAAI;AACnF,SAAO,aAAa,KAAK,UAAU,IAAI,CAAC;AAC1C;AAEA,SAAS,kBAAkB,SAAiB,WAAuC;AACjF,SAAO,0BAA0B,WAAW,mBAAmB,SAAS,UAAU,MAAM,4BAA4B,UAAU,WAAW,IAAI,KAAK,GAAG;AACvJ;AAEA,SAAS,aAAa,OAAuB;AAC3C,QAAM,UAAU,OAAO,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,OAAO,EAAE;AAC5D,SAAO,UAAU,IAAI,OAAO,KAAK;AACnC;AAEA,SAAS,mBAAmB,YAAsC;AAChE,QAAM,gBAAgB,WAAW,SAAS,KAAK,CAAC,YAC9C,QAAQ,aAAa,WACrB,0BAA0B,KAAK,GAAG,QAAQ,QAAQ,EAAE,IAAI,OAAO,QAAQ,WAAW,SAAS,EAAE,CAAC,IAAI,OAAO,QAAQ,WAAW,QAAQ,EAAE,CAAC,GAAG,YAAY,CAAC,CACxJ;AACD,QAAM,gBAAgB,WAAW,SAAS,KAAK,CAAC,YAC9C,QAAQ,aAAa,WAAW,OAAO,QAAQ,WAAW,QAAQ,EAAE,EAAE,YAAY,MAAM,UACzF;AACD,QAAM,eAAe,WAAW,SAAS,KAAK,CAAC,YAC7C,QAAQ,aAAa,YAAY,uCAAuC,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,CAChH,KAAK,WAAW,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,QAAQ;AACzE,QAAM,UAAU,WAAW,SAAS,KAAK,CAAC,YACxC,QAAQ,aAAa,aAAa,qBAAqB,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,CAC/F,KAAK,WAAW,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,SAAS;AAE1E,SAAO,EAAE,eAAe,eAAe,cAAc,QAAQ;AAC/D;AAEA,SAAS,iBAAiB,YAAqD;AAC7E,SAAO,WAAW,SAAS,KAAK,CAAC,YAC/B,QAAQ,SAAS,WACjB,QAAQ,aAAa,YACrB,OAAO,QAAQ,WAAW,QAAQ,EAAE,EAAE,YAAY,MAAM,OACzD;AACH;AAEA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,MACJ,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,SAAS,GAAG,EACpB,QAAQ,wCAAwC,GAAG,EACnD,QAAQ,+DAA+D,GAAG,EAC1E,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,yBAAyB,OAAmC;AACnE,QAAM,YAAY,MAAM,QAAQ,OAAO,EAAE,EAAE,KAAK;AAChD,QAAM,eACJ,UAAU,MAAM,iBAAiB,IAAI,CAAC,KACtC,UAAU,MAAM,sBAAsB,IAAI,CAAC;AAC7C,MAAI,cAAc;AAChB,UAAM,SAAS,aAAa,WAAW,GAAG,IACtC,gBACC,MAAM;AACL,UAAI;AACF,eAAO,IAAI,IAAI,YAAY,EAAE;AAAA,MAC/B,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG;AACP,QAAI,QAAQ;AACV,aAAO,OACJ,QAAQ,QAAQ,EAAE,EAClB,MAAM,GAAG,EACT,IAAI,cAAc,EAClB,KAAK,KAAK;AAAA,IACf;AAAA,EACF;AAEA,QAAM,cACJ,UAAU,MAAM,mIAAmI,KACnJ,UAAU,MAAM,kFAAkF;AACpG,QAAM,SAAS,wBAAwB,cAAc,CAAC,KAAK,EAAE;AAC7D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OAAO,MAAM,SAAS,EAAE,OAAO,OAAO,EAAE,IAAI,cAAc,EAAE,KAAK,UAAU;AACpF;AAEA,SAAS,uBAAuB,mBAA0E;AACxG,MAAI,oJAAoJ,KAAK,iBAAiB,GAAG;AAC/K,WAAO;AAAA,EACT;AACA,MAAI,8JAA8J,KAAK,iBAAiB,GAAG;AACzL,WAAO;AAAA,EACT;AACA,MAAI,wGAAwG,KAAK,iBAAiB,GAAG;AACnI,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,YAAwB,mBAAmC;AAC1F,QAAM,gBAAgB,yBAAyB,iBAAiB;AAChE,MAAI,cAAe,QAAO;AAE1B,QAAM,WAAW,WAAW,SAAS,KAAK,CAAC,YAAY;AACrD,QAAI,QAAQ,aAAa,OAAQ,QAAO;AACxC,UAAMC,QAAO,OAAO,QAAQ,WAAW,QAAQ,EAAE;AACjD,UAAM,QAAQ,GAAG,QAAQ,QAAQ,EAAE,IAAIA,KAAI,GAAG,YAAY;AAC1D,WAAO,kCAAkC,KAAK,KAAK;AAAA,EACrD,CAAC;AAED,QAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,EAAE;AACnD,MAAI,KAAK,WAAW,GAAG,GAAG;AACxB,WAAO,KACJ,QAAQ,QAAQ,EAAE,EAClB,MAAM,GAAG,EACT,IAAI,cAAc,EAClB,KAAK,KAAK;AAAA,EACf;AAEA,SAAO;AACT;AAEA,SAAS,2BACP,YACA,kBACgB;AAChB,QAAM,gBAAgB,mBAAmB,gBAAgB;AACzD,QAAM,kBAAkB,YAAqB;AAAA,IAC3C,aAAa;AAAA,IACb,KAAK,WAAW;AAAA,EAClB,CAAC,EAAE,YAAY;AACf,QAAM,eAAe,mBAAmB,UAAU;AAElD,MAAI,YACF,cAAc,SAAS,UACnB,oBAAoB,YAAY,kBAAkB,eAAe,IACjE,cAAc,SAAS,aACrB,2BAA2B,YAAY,kBAAkB,eAAe,IACvE,cAAc,SAAS,UAAU,cAAc,SAAS,SACvD,2BAA2B,YAAY,iBAAiB,cAAc,gBAAgB,IACtF,iCAAiC,YAAY,iBAAiB,gBAAgB;AAExF,MAAI,UAAU,WAAW,MAAM,aAAa,iBAAiB,aAAa,iBAAiB,aAAa,eAAe;AACrH,gBAAY,2BAA2B,YAAY,iBAAiB,cAAc,gBAAgB;AAAA,EACpG;AACA,MAAI,UAAU,WAAW,GAAG;AAC1B,gBAAY,iCAAiC,YAAY,iBAAiB,gBAAgB;AAAA,EAC5F;AAEA,QAAM,iBAAiB,UAAU,MAAM,GAAG,cAAc,YAAY;AAEpE,SAAO;AAAA,IACL,KAAK,WAAW;AAAA,IAChB,SAAS;AAAA,IACT;AAAA,IACA,WAAW;AAAA,IACX,eAAe;AAAA,IACf,cAAc,kBAAkB,kBAAkB,cAAc;AAAA,EAClE;AACF;AAEA,SAAS,kBAAkB,OAAwB;AACjD,SAAO,OAAQ,OAA6B,WAAW,SAAS,eAAe,EAAE,MAAM,IAAI,EAAE,CAAC;AAChG;AAEA,SAAS,sBACP,cACA,WACA,eACS;AACT,MAAI,cAAc,SAAS,UAAU,cAAc,SAAS,OAAQ,QAAO;AAC3E,MAAI,CAAC,aAAa,iBAAiB,CAAC,aAAa,iBAAiB,CAAC,aAAa,aAAc,QAAO;AACrG,MAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,QAAM,qBAAqB,UAAU,KAAK,CAAC,aAAa;AACtD,UAAM,kBAAkB,IAAI;AAAA,MAC1B,SAAS,MACN,OAAO,CAAC,SAAS,KAAK,WAAW,MAAM,EACvC,IAAI,CAAC,SAAS,KAAK,QAAQ;AAAA,IAChC;AAEA,WAAO,gBAAgB,IAAI,aAAa,cAAe,QAAQ,KAAK,gBAAgB,IAAI,aAAa,cAAe,QAAQ;AAAA,EAC9H,CAAC;AAED,QAAM,0BAA0B,UAAU,KAAK,CAAC,aAC9C,SAAS,WAAW,KAAK,CAAC,cAAc,0CAA0C,KAAK,UAAU,UAAU,CAAC,CAC7G;AAED,SAAO,2BAA2B,CAAC;AACrC;AAEA,SAAS,iBAAiB,QAAgC,UAAkB,OAAuB;AACjG,MAAI,WAAW,WAAY,QAAO,eAAe,SAAS,UAAU;AACpE,MAAI,WAAW,OAAQ,QAAO,eAAe,kBAAkB,QAAQ,IAAI,UAAU,KAAK;AAC1F,MAAI,WAAW,QAAS,QAAO,SAAS,QAAQ;AAChD,MAAI,WAAW,SAAU,QAAO,UAAU,KAAK,OAAO,QAAQ;AAC9D,MAAI,WAAW,QAAS,QAAO,SAAS,QAAQ;AAChD,MAAI,WAAW,WAAY,QAAO,SAAS,KAAK;AAChD,SAAO,iBAAiB,QAAQ;AAClC;AAEA,SAAS,mBACP,OACA,QACA,UACA,OACQ;AACR,MAAI,WAAW,UAAU,WAAW,SAAU,QAAO;AACrD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,mBAAmB,0BAA0B,KAAK,KAAK;AAC7D,QAAM,cAAc,MAAM,MAAM,+BAA+B,IAAI,CAAC;AACpE,MAAI,iBAAkB,QAAO;AAC7B,MAAI,eAAe,CAAC,mBAAmB,WAAW,EAAG,QAAO;AAC5D,QAAM,gBAAgB,MAAM,QAAQ,oCAAoC,EAAE,EAAE,KAAK,KAAK;AACtF,SAAO,eAAe,eAAe,UAAU,KAAK;AACtD;AAEA,SAAS,oBAAoB,YAAwB,mBAA8C;AACjG,QAAM,WACJ,WAAW,KAAK,iBAAiB,IAAI,WACnC,SAAS,KAAK,iBAAiB,IAAI,SACnC,kBAAkB,KAAK,iBAAiB,IAAI,YAC5C,iCAAiC,KAAK,iBAAiB,IAAI,UAC3D;AAEJ,MAAI,UAAU;AACZ,WAAO,WAAW,SAAS,OAAO,CAAC,YAAY,QAAQ,aAAa,QAAQ;AAAA,EAC9E;AAEA,SAAO,WAAW,SAAS,OAAO,CAAC,YACjC,QAAQ,aAAa,YAAY,QAAQ,aAAa,UAAU,QAAQ,aAAa,OACtF;AACH;AAEA,SAAS,wBAAwB,mBAA2B,UAAqC;AAC/F,MAAI,WAAW,KAAK,iBAAiB,EAAG,QAAO;AAC/C,MAAI,SAAS,KAAK,iBAAiB,EAAG,QAAO;AAC7C,MAAI,kBAAkB,KAAK,iBAAiB,EAAG,QAAO;AACtD,MAAI,iCAAiC,KAAK,iBAAiB,EAAG,QAAO;AACrE,SAAO,SAAS,CAAC,GAAG,YAAY;AAClC;AAEA,SAAS,6BAA6B,WAAsC;AAC1E,QAAM,WAAW,8BAA8B,+BAA+B,UAAU,UAAU,CAAC;AACnG,MAAI,SAAU,QAAO,gBAAgB,QAAQ;AAE7C,QAAM,QAAQ,yBAAyB,SAAS;AAChD,MAAI,MAAO,QAAO;AAElB,SAAO,gBAAgB,UAAU,UAAU;AAC7C;AAEA,SAAS,+BAA+B,YAA4B;AAClE,QAAM,UAAU,OAAO,cAAc,EAAE,EAAE,KAAK;AAC9C,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,8BAA8B,YAA4B;AACjE,QAAM,UAAU,OAAO,cAAc,EAAE,EAAE,KAAK;AAC9C,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,WAAsC;AACtE,MAAI,UAAU,aAAa,QAAQ;AACjC,QAAI,UAAU,SAAS,SAAS,UAAU,UAAU;AAClD,aAAO,gCAAgC,KAAK,UAAU,UAAU,QAAQ,CAAC;AAAA,IAC3E;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,eAAe,UAAU,QAAQ;AAChD,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,UAAU,SAAS,WAAW,UAAU,UAAU;AACpD,WAAO,gBAAgB,MAAM,iBAAiB,KAAK,UAAU,UAAU,QAAQ,CAAC;AAAA,EAClF;AAEA,QAAM,WAAW,GAAG,UAAU,QAAQ,IAAI,UAAU,KAAK,IAAI,UAAU,UAAU,GAAG,YAAY;AAChG,MAAI,iDAAiD,KAAK,QAAQ,GAAG;AACnE,WAAO,gBAAgB,MAAM;AAAA,EAC/B;AAEA,SAAO,gBAAgB,MAAM;AAC/B;AAEA,SAAS,eAAe,UAA0B;AAChD,QAAM,UAAU,OAAO,YAAY,EAAE,EAAE,KAAK;AAC5C,MAAI,CAAC,WAAW,YAAY,OAAQ,QAAO;AAC3C,MAAI,QAAQ,WAAW,OAAO,EAAG,QAAO;AACxC,SAAO,QAAQ,OAAO;AACxB;AAEA,SAAS,iBAAiB,UAA0B;AAClD,SAAO,gBAAgB,eAAe,QAAQ,CAAC;AACjD;AAEA,SAAS,eAAe,UAAkB,OAAuB;AAC/D,SAAO,gBAAgB,eAAe,QAAQ,CAAC,iBAAiB,KAAK,UAAU,KAAK,CAAC;AACvF;AAEA,SAAS,eAAe,SAA0B,MAAuC;AACvF,MAAI,SAAS,WAAY,QAAO,yBAAyB,QAAQ,UAAU,eAAe;AAC1F,SAAO,yBAAyB,QAAQ,UAAU,EAAE;AACtD;AAEA,SAAS,eAAe,MAAc,UAAkB,cAA8B;AACpF,QAAM,eAAe,yBAAyB,UAAU,YAAY;AACpE,SAAO,GAAG,IAAI,UAAU,YAAY;AACtC;AAEA,SAAS,yBAAyB,UAAkB,cAA8B;AAChF,MAAI,gBAAgB,CAAC,mBAAmB,YAAY,KAAK,CAAC,qBAAqB,YAAY,GAAG;AAC5F,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,cAAc,QAAQ;AACrC,MAAI,UAAU,QAAQ,IAAI,MAAM,GAAG;AACjC,WAAO,OAAO,QAAQ,IAAI,MAAM,CAAC;AAAA,EACnC;AAEA,SAAO,mBAAmB,QAAQ;AACpC;AAEA,SAAS,yBAAyB,UAAkB,cAA8B;AAChF,QAAM,SAAS,cAAc,QAAQ;AACrC,MAAI,OAAQ,QAAO,MAAM,MAAM;AAC/B,SAAO;AACT;AAEA,SAAS,cAAc,gBAA4C;AACjE,QAAM,WAAW,eAAe,YAAY;AAC5C,QAAM,YACJ,YAAY,KAAK,QAAQ,IAAI,iBAC3B,eAAe,KAAK,QAAQ,IAAI,oBAChC,aAAa,KAAK,QAAQ,IAAI,kBAC9B,gBAAgB,KAAK,QAAQ,IAAI,iBACjC,WAAW,KAAK,QAAQ,IAAI,gBAC5B,0BAA0B,KAAK,QAAQ,IAAI,oBAC3C;AACJ,MAAI,aAAa,QAAQ,IAAI,SAAS,MAAM,OAAW,QAAO;AAC9D,SAAOD,uBAAsB,EAAE,KAAK,CAAC,QAAQ,IAAI,OAAO,IAAI,QAAQ,YAAY,EAAE,EAAE,YAAY,CAAC,EAAE,KAAK,QAAQ,CAAC;AACnH;AAEA,SAAS,mBAAmB,gBAAgC;AAC1D,QAAM,WAAW,eAAe,YAAY;AAC5C,MAAI,YAAY,KAAK,QAAQ,EAAG,QAAO;AACvC,MAAI,eAAe,KAAK,QAAQ,EAAG,QAAO;AAC1C,MAAI,aAAa,KAAK,QAAQ,EAAG,QAAO;AACxC,MAAI,gBAAgB,KAAK,QAAQ,EAAG,QAAO;AAC3C,MAAI,WAAW,KAAK,QAAQ,KAAK,CAAC,oBAAoB,KAAK,QAAQ,EAAG,QAAO;AAC7E,MAAI,0BAA0B,KAAK,QAAQ,EAAG,QAAO;AACrD,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAwB;AAClD,SAAO,kEAAkE,KAAK,MAAM,KAAK,CAAC;AAC5F;AAEA,SAAS,qBAAqB,OAAmC;AAC/D,SAAO,MAAM,MAAM,6BAA6B,IAAI,CAAC;AACvD;AAEA,SAAS,kBAAkB,UAAkB,WAAiC;AAC5E,MAAI,aAAa,OAAQ,QAAO;AAChC,MAAI,UAAU,IAAI,QAAQ,EAAG,QAAO;AACpC,MAAI,wFAAwF,KAAK,QAAQ,GAAG;AAC1G,UAAM,UAAU,SAAS,QAAQ,wGAAwG,EAAE;AAC3I,WAAO,kBAAkB,SAAS,SAAS;AAAA,EAC7C;AAEA,SAAO,qEAAqE,KAAK,QAAQ,KACpF,8BAA8B,KAAK,QAAQ;AAClD;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,QAAM,UAAU,OAAO,SAAS,EAAE,EAAE,KAAK;AACzC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,SAAS,GAAG,IAAI,UAAU,GAAG,OAAO;AACrD;AAEA,SAAS,mBAAmB,OAAuB,KAA6B;AAC9E,MAAI,CAAC,OAAO,MAAM,WAAW,EAAG,QAAO;AACvC,MAAI,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,UAAU,EAAG,QAAO;AAE7D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO,eAAe,GAAG;AAAA,IAC3B;AAAA,IACA,GAAG;AAAA,EACL;AACF;AAEA,SAAS,IAAI,SAAkB,SAAuB;AACpD,MAAI,QAAS,SAAQ,IAAI,OAAO;AAClC;;;ACh5DA,SAAS,aAAAE,YAAW,iBAAAC,sBAAqB;AACzC,SAAS,QAAAC,aAAY;AAId,SAAS,mBAAmB,YAAwB,UAAwC;AACjG,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAC1B,UAAQ,IAAI,6BAA6B;AACzC,UAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAC1B,UAAQ,IAAI,QAAQ,WAAW,GAAG,EAAE;AACpC,UAAQ,IAAI,UAAU,WAAW,KAAK,EAAE;AACxC,UAAQ,IAAI,aAAa,WAAW,SAAS,KAAK,WAAW,IAAI,GAAG;AACpE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,WAAW;AAEvB,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,WAAW,QAAQ,UAAU,GAAG;AAC7E,YAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE;AAAA,EACvC;AAEA,MAAI,WAAW,SAAS,SAAS,GAAG;AAClC,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,WAAW;AACvB,eAAW,WAAW,WAAW,UAAU;AACzC,cAAQ,IAAI,OAAO,OAAO,EAAE;AAAA,IAC9B;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,iBAAiB,SAAS,UAAU,MAAM,EAAE;AACxD,YAAQ,IAAI,YAAY,SAAS,OAAO,EAAE;AAC1C,YAAQ,IAAI,WAAW,SAAS,eAAe,EAAE;AAAA,EACnD;AAEA,UAAQ,IAAI,EAAE;AAChB;AAEO,SAAS,gBACd,YACA,UACA,YAAY,qBACJ;AACR,EAAAF,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAExC,QAAM,WAAW,WAAW,QAAQ,WAAW,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC;AACjE,QAAM,WAAWE,MAAK,WAAW,QAAQ;AAEzC,EAAAD,eAAc,UAAU,KAAK,UAAU;AAAA,IACrC,OAAO;AAAA,MACL,SAAS;AAAA,MACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA,UAAU,YAAY;AAAA,EACxB,GAAG,MAAM,CAAC,CAAC;AAEX,SAAO;AACT;AAEO,SAAS,mBAAmB,UAAkC;AACnE,QAAM,QAAkB,CAAC;AAEzB,aAAW,YAAY,SAAS,WAAW;AACzC,UAAM,KAAK,KAAK,SAAS,EAAE,WAAM,SAAS,KAAK,IAAI,SAAS,KAAK,IAAIE,aAAY,EAAE,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC;AACrG,UAAM,KAAK,eAAe,SAAS,GAAG,MAAM;AAC5C,UAAM,KAAK,mBAAmB,SAAS,OAAO,MAAM;AACpD,UAAM,KAAK,kCAAkC;AAC7C,UAAM,KAAK,kBAAkB,gBAAgB,SAAS,QAAQ,CAAC,MAAM;AACrE,UAAM,KAAK,oBAAoB,SAAS,SAAS,MAAM;AACvD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,UAAU;AAErB,aAAS,MAAM,QAAQ,CAAC,MAAM,UAAU;AACtC,YAAM,OAAO,KAAK,YAAY,KAAK,aAAa,SAC5C,mBAAmB,KAAK,QAAQ,SAChC;AACJ,YAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI,EAAE;AAAA,IACjD,CAAC;AAED,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,qBAAqB;AAEhC,aAAS,WAAW,QAAQ,CAAC,cAAc;AACzC,YAAM,OAAO,UAAU,aACnB,qBAAqB,gBAAgB,UAAU,UAAU,CAAC,SAC1D;AACJ,YAAM,KAAK,KAAK,UAAU,KAAK,GAAG,IAAI,EAAE;AAAA,IAC1C,CAAC;AAED,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,kBACd,UACA,YAAY,SACZ,UACQ;AACR,EAAAH,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAExC,QAAM,mBAAmB,YAAY,GAAG,QAAQ,SAAS,WAAW,SAAS,GAAG,CAAC;AACjF,QAAM,WAAWE,MAAK,WAAW,gBAAgB;AAEjD,EAAAD,eAAc,UAAU,mBAAmB,QAAQ,CAAC;AACpD,SAAO;AACT;AAEO,SAAS,gBACd,UACA,YAAY,iBACG;AACf,MAAI,SAAS,UAAU,WAAW,EAAG,QAAO;AAE5C,EAAAD,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAExC,QAAM,WAAW,gBAAgB,QAAQ,SAAS,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC;AACpE,QAAM,WAAWE,MAAK,WAAW,QAAQ;AACzC,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,sBAAsB,SAAS,GAAG,EAAE;AAC/C,QAAM,KAAK,eAAe,SAAS,OAAO,EAAE;AAC5C,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,uDAAuD;AAClE,QAAM,KAAK,EAAE;AAEb,aAAW,YAAY,SAAS,WAAW;AACzC,UAAM,KAAK,QAAQ,KAAK,UAAU,GAAG,SAAS,EAAE,WAAM,SAAS,KAAK,EAAE,CAAC,yBAAyB;AAChG,eAAW,QAAQ,SAAS,OAAO;AACjC,UAAI,KAAK,WAAW,YAAY;AAC9B,cAAM,KAAK,qBAAqB,KAAK,UAAU,KAAK,KAAK,CAAC,IAAI;AAC9D;AAAA,MACF;AAEA,UAAI,KAAK,aAAa,OAAQ;AAC9B,YAAM,WAAW,QAAQ,KAAK,QAAQ;AAEtC,UAAI,KAAK,WAAW,OAAQ,OAAM,KAAK,WAAW,QAAQ,SAAS,KAAK,UAAU,KAAK,KAAK,CAAC,IAAI;AACjG,UAAI,KAAK,WAAW,QAAS,OAAM,KAAK,WAAW,QAAQ,WAAW;AACtE,UAAI,KAAK,WAAW,SAAU,OAAM,KAAK,WAAW,QAAQ,iBAAiB,KAAK,UAAU,KAAK,KAAK,CAAC,IAAI;AAC3G,UAAI,KAAK,WAAW,QAAS,OAAM,KAAK,WAAW,QAAQ,WAAW;AACtE,UAAI,KAAK,WAAW,WAAY,OAAM,KAAK,+BAA+B,KAAK,UAAU,KAAK,KAAK,CAAC,IAAI;AACxG,UAAI,KAAK,WAAW,QAAS,OAAM,KAAK,WAAW,QAAQ,WAAW;AAAA,IACxE;AAEA,eAAW,aAAa,SAAS,YAAY;AAC3C,YAAM,KAAK,KAAK,uBAAuB,UAAU,YAAY,UAAU,KAAK,CAAC,EAAE;AAAA,IACjF;AAEA,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,EAAAD,eAAc,UAAU,MAAM,KAAK,IAAI,CAAC;AACxC,SAAO;AACT;AAEA,SAAS,QAAQ,OAAuB;AACtC,UAAQ,SAAS,WACd,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,UAAU,EAAE,EACpB,YAAY,EACZ,MAAM,GAAG,EAAE;AAChB;AAEA,SAASE,cAAa,OAAuB;AAC3C,QAAM,UAAU,OAAO,SAAS,EAAE,EAAE,KAAK;AACzC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,WAAW,GAAG,IAAI,UAAU,IAAI,OAAO;AACxD;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,OAAO,SAAS,EAAE,EAAE,QAAQ,QAAQ,MAAM;AACnD;AAEA,SAASC,iBAAgB,OAAuB;AAC9C,QAAM,UAAU,OAAO,SAAS,EAAE,EAAE,KAAK;AACzC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,SAAS,GAAG,IAAI,UAAU,GAAG,OAAO;AACrD;AAEA,SAAS,uBAAuB,YAAoB,OAAwB;AAC1E,QAAM,YAAYA,iBAAgB,UAAU;AAC5C,QAAM,eAAe,UAAU,MAAM,wEAAwE;AAC7G,QAAM,iBAAiB,OAAO,SAAS,EAAE,EAAE,MAAM,oBAAoB,IAAI,CAAC,GAAG,KAAK;AAElF,MAAI,gBAAgB,kBAAkB,CAAC,qBAAqB,KAAK,cAAc,GAAG;AAChF,WAAO,kDAAkD,KAAK,UAAU,cAAc,CAAC;AAAA,EACzF;AAEA,SAAO;AACT;;;ALxLA,SAASC,SAAQ,MAAsB;AACrC,SACE,KACG,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE,KAAK;AAElC;AAEA,SAAS,kBAAkB,UAAkB,KAAsB;AACjE,MAAI,CAAC,OAAO,oBAAoB,KAAK,QAAQ,EAAG,QAAO;AAEvD,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,QAAMC,UAAmB,CAAC;AAE1B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,IAAAA,QAAO,KAAK,MAAM,CAAC,CAAC;AACpB,QAAI,WAAW,KAAK,MAAM,CAAC,CAAC,GAAG;AAC7B,MAAAA,QAAO,KAAK,eAAe,GAAG,MAAM;AAAA,IACtC;AAAA,EACF;AAEA,SAAOA,QAAO,KAAK,IAAI;AACzB;AAEA,SAAS,yBAAyB,MAMvB;AACT,QAAM,EAAE,QAAQ,SAAS,KAAK,SAAS,IAAI;AAC3C,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,QAAkB,CAAC;AAEzB,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,UAAM,MAAM,aAAa;AACzB,UAAM,KAAM,GAAG,MAAM,IAAI,OAAO,GAAG,EAAE,SAAS,GAAG,GAAG,CAAC;AAErD,UAAM,KAAK,KAAK,EAAE,WAAM,OAAO,eAAe,GAAG,kBAAkB;AACnE,QAAI,IAAK,OAAM,KAAK,eAAe,GAAG,MAAM;AAC5C,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,kBAAkB,OAAO,YAAY,EAAE;AAClD,UAAM,KAAK,mDAAmD;AAC9D,UAAM,KAAK,uBAAuB;AAClC,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,qBAAqB;AAChC,UAAM,KAAK,iDAAiD;AAC5D,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAe,qBAAqB,MAKjC;AAED,MAAI,KAAK,SAAS;AAChB,UAAM,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE;AACtD,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,gBAAgB,KAAK,kBAAkB;AAAA,MACvC,UAAU;AAAA,MACV,KAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAGA,QAAM,KAAK,gBAAgB,EAAE,OAAO,OAAO,CAAC;AAE5C,QAAM,WAAkB,MAAM,GAAG,SAAS,qCAA8B,GAAG,KAAK;AAChF,QAAM,kBAAkB,MAAM,GAAG,SAAS,8CAAuC,GAAG,KAAK;AACzF,QAAM,eAAkB,MAAM,GAAG,SAAS,kDAAsC,GAAG,KAAK;AAExF,KAAG,MAAM;AAET,MAAI,WAAW,SAAS,aAAa,EAAE;AACvC,MAAI,MAAM,QAAQ,KAAK,WAAW,EAAG,YAAW;AAChD,MAAI,WAAW,GAAI,YAAW;AAE9B,SAAO,EAAE,SAAS,gBAAgB,UAAU,KAAK,KAAK,IAAI;AAC5D;AAEA,eAAe,iBAAiB,QAS7B;AACD,QAAM,EAAE,SAAS,gBAAgB,UAAU,IAAI,IAAI,MAAM,qBAAqB;AAAA,IAC5E,KAAgB,OAAO;AAAA,IACvB,SAAgB,OAAO;AAAA,IACvB,gBAAgB,OAAO;AAAA,IACvB,UAAgB,OAAO;AAAA,EACzB,CAAC;AAED,QAAM,SAAS,YAAY;AAAA,IACzB,aAAgB;AAAA,IAChB;AAAA,IACA,gBAAgB,OAAO;AAAA,EACzB,CAAC;AAED,EAAAC,WAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACtC,QAAM,WAAW,GAAG,OAAO,YAAY,CAAC,IAAIF,SAAQ,OAAO,CAAC;AAC5D,QAAM,WAAWG,MAAK,SAAS,QAAQ;AAEvC,MAAI;AACJ,MAAI,cAAc;AAElB,MAAI,OAAO,OAAO;AAChB,QAAI,KAAK;AACP,UAAI;AACF,gBAAQ,IAAI,6BAAsB,GAAG,EAAE;AACvC,cAAM,aAAa,MAAM,gBAAgB,KAAK;AAAA,UAC5C,UAAU,EAAE,OAAO,UAAU;AAAA,UAC7B,SAAS;AAAA,QACX,CAAC;AACD,2BAAmB,UAAU;AAE7B,cAAM,WAAW,gBAAgB,UAAU;AAC3C,gBAAQ,IAAI,uCAA2B,QAAQ,EAAE;AACjD,sBAAc,cAAc,UAAU;AAEtC,YAAI,OAAO,aAAa;AACtB,kBAAQ,IAAI,4DAA4D;AACxE;AAAA,QACF;AAEA,cAAM,WAAW,MAAM,gBAAgB,YAAY,EAAE,SAAS,MAAM,QAAQ,CAAC;AAC7E,2BAAmB,YAAY,QAAQ;AAEvC,cAAM,cAAc,gBAAgB,QAAQ;AAC5C,YAAI,aAAa;AACf,kBAAQ,IAAI,uCAA2B,WAAW,EAAE;AAAA,QACtD;AAEA,cAAM,kBAAkB,GAAG,OAAO,YAAY,CAAC,IAAIH,SAAQ,OAAO,CAAC;AACnE,cAAM,gBAAgB,kBAAkB,UAAU,SAAS,eAAe;AAC1E,gBAAQ,IAAI,uDAA6C,aAAa,EAAE;AACxE,gBAAQ,IAAI,eAAe;AAC3B,gBAAQ,IAAI,kBAAkB,aAAa,sBAAsB;AACjE,gBAAQ,IAAI,WAAW;AACvB;AAAA,MACF,SAAS,GAAQ;AACf,0BAAkB,qBAAqB,CAAC,CAAC;AACzC,gBAAQ,KAAK,0EAAgE;AAC7E,YAAI,OAAO,aAAa;AACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,iBAAW,MAAM,yBAAyB;AAAA,QACxC,gBAAgB,kBAAkB;AAAA,QAClC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AACD,iBAAW,kBAAkB,UAAU,GAAG;AAC1C,cAAQ,IAAI,iCAA4B;AAAA,IAC1C,SAAS,KAAU;AACjB,wBAAkB;AAAA,QAChB;AAAA,QACA,KAAK,WAAW,OAAO,GAAG;AAAA,MAC5B,CAAC;AACD,iBAAW,yBAAyB,EAAE,QAAQ,SAAS,KAAK,UAAU,YAAY,EAAE,CAAC;AACrF,cAAQ,IAAI,yDAAkD;AAAA,IAChE;AAAA,EACF,OAAO;AACL,eAAW,yBAAyB,EAAE,QAAQ,SAAS,KAAK,UAAU,YAAY,EAAE,CAAC;AACrF,YAAQ,IAAI,uEAAgE;AAAA,EAC9E;AAEA,EAAAI,eAAc,UAAU,QAAQ;AAEhC,UAAQ,IAAI;AAAA,sBAAe,QAAQ,mBAAc,QAAQ,EAAE;AAC3D,UAAQ,IAAI,eAAe;AAC3B,UAAQ,IAAI,4CAA4C;AACxD,UAAQ,IAAI,WAAW;AACzB;AAEA,SAAS,kBAAkB,OAAuB;AAChD,MAAI,MAAM,WAAW,EAAG;AAExB,UAAQ,KAAK,gBAAM,MAAM,CAAC,CAAC,EAAE;AAC7B,aAAW,QAAQ,MAAM,MAAM,CAAC,GAAG;AACjC,YAAQ,KAAK,IAAI;AAAA,EACnB;AACF;AAIA,SAAS,iBAAiB,KAAuB;AAC/C,SAAO,IACJ,OAAO,QAAqB,kDAAkD,EAC9E,OAAO,qBAAqB,2CAA2C,EACvE,OAAO,oBAAqB,8CAAyC,EACrE,OAAO,iBAAqB,iDAA4C,EACxE,OAAO,eAAqB,+BAA0B,QAAQ;AACnE;AAEA,SAAS,qBAAwD,MAAsB;AACrF,MAAI,OAAQ,KAAiB,oBAAoB,YAAY;AAC3D,WAAQ,KAAiB,gBAAmB;AAAA,EAC9C;AACA,MAAI,OAAQ,KAAiB,SAAS,YAAY;AAChD,WAAQ,KAAiB,KAAQ;AAAA,EACnC;AACA,SAAO;AACT;AAIO,SAAS,QAAQ;AACtB,QAAM,OAAO,IAAIC,SAAQ,IAAI,EAC1B,YAAY,yDAAyD,EACrE,YAAY,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,CAKzB;AAEC,mBAAiB,IAAI,EAAE;AAAA,IACrB,OAAO,SAAuG;AAC5G,YAAM,eAAe,qBAAyG,IAAI;AAClI,YAAM,iBAAiB;AAAA,QACrB,KAAgB;AAAA,QAChB,gBAAgB,aAAa;AAAA,QAC7B,SAAgB,aAAa;AAAA,QAC7B,gBAAgB,aAAa;AAAA,QAC7B,UAAgB,aAAa;AAAA,QAC7B,OAAgB,aAAa,MAAM;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AAEA;AAAA,IACE,KACG,QAAQ,KAAK,EACb,SAAS,SAAS,gDAAgD,EAClE,YAAY,0EAA0E,EACtF,OAAO,YAAY,2CAA2C,EAC9D,OAAO,kBAAkB,mEAAmE;AAAA,EACjG,EAAE;AAAA,IACA,OACE,KACA,MACA,YACG;AACH,YAAM,eAAe,qBAAkJ,WAAW,IAAI;AACtL,YAAM,iBAAiB;AAAA,QACrB;AAAA,QACA,gBAAgB,aAAa;AAAA,QAC7B,SAAgB,aAAa;AAAA,QAC7B,gBAAgB,aAAa;AAAA,QAC7B,UAAgB,aAAa;AAAA,QAC7B,OAAgB,aAAa,MAAM;AAAA,QACnC,QAAgB,aAAa,UAAU;AAAA,QACvC,aAAgB,aAAa,eAAe;AAAA,MAC9C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AMxSA,SAAS,WAAAC,gBAAe;AACxB,SAAS,SAAAC,cAAa;AAEf,SAAS,YAAY;AAC1B,QAAM,MAAM,IAAID,SAAQ,QAAQ,EAC7B,YAAY,iCAAiC,EAC7C,OAAO,MAAM;AACZ,YAAQ,IAAI,6CAAsC;AAElD,UAAM,QAAQC;AAAA,MACZ;AAAA,MACA,CAAC,cAAc,aAAa;AAAA,MAC5B;AAAA,QACE,OAAO;AAAA,QACP,OAAO,QAAQ,aAAa;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AAEH,SAAO;AACT;;;ACxBA,SAAS,WAAAC,gBAAe;AACxB,SAAS,SAAAC,cAAa;AACtB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAEd,SAAS,WAAW;AACzB,QAAM,MAAM,IAAIH,SAAQ,OAAO,EAC5B,YAAY,yBAAyB,EACrC,OAAO,MAAM;AACZ,YAAQ,IAAI,oCAA6B;AAGzC,UAAM,iBAAiBG,MAAK,QAAQ,IAAI,GAAG,gBAAgB,sBAAsB,OAAO,QAAQ;AAEhG,QAAI,aAAa;AACjB,QAAI,OAAO,CAAC,UAAU,SAAS,kBAAkB;AAIjD,QAAID,YAAW,cAAc,GAAG;AAC7B,mBAAa;AACb,aAAO,CAAC,gBAAgB,SAAS,kBAAkB;AAAA,IACtD;AAEA,YAAQ,IAAI,KAAK,UAAU,IAAI,KAAK,KAAK,GAAG,CAAC,EAAE;AAE/C,UAAM,QAAQD;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO,QAAQ,aAAa;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB,CAAC;AAAA,EACH,CAAC;AAEH,SAAO;AACT;;;ACzCA,SAAS,WAAAG,gBAAe;AACxB,SAAS,SAAAC,cAAa;AACtB,SAAS,WAAAC,gBAAe;AAExB,SAAS,QAAQ,KAAa,MAAgB,UAAiC;AAC7E,SAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAQ,IAAI;AAAA,uBAAmB,QAAQ,EAAE;AACzC,YAAQ,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC,EAAE;AAExC,UAAM,QAAQD,OAAM,KAAK,MAAM;AAAA,MAC7B,OAAO;AAAA,MACP,OAAO,QAAQ,aAAa;AAAA,IAC9B,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,SAAS,GAAG;AACd,QAAAC,SAAQ;AAAA,MACV,OAAO;AACL,eAAO,IAAI,MAAM,GAAG,QAAQ,0BAA0B,IAAI,EAAE,CAAC;AAAA,MAC/D;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEO,SAAS,UAAU;AACxB,QAAM,MAAM,IAAIF,SAAQ,MAAM,EAC3B,YAAY,qDAAqD,EACjE,SAAS,cAAc,mCAAmC,SAAS,EACnE,OAAO,iBAAiB,2BAA2B,IAAI,EACvD,OAAO,YAAY,oBAAoB,EACvC,OAAO,OAAO,UAAU,SAAS;AAChC,UAAM,SAASE,SAAQ,QAAQ,KAAK,CAAC,CAAC;AAEtC,QAAI;AAEF,YAAM,QAAQ,QAAQ,UAAU,CAAC,QAAQ,aAAa,QAAQ,GAAG,iBAAiB;AAGlF,YAAM,QAAQ,QAAQ,UAAU,CAAC,QAAQ,OAAO,UAAU,KAAK,IAAI,GAAG,gBAAgB;AAGtF,UAAI,KAAK,KAAK;AACX,cAAM,QAAQ,QAAQ,UAAU,CAAC,QAAQ,MAAM,GAAG,sBAAsB;AAAA,MAC3E,OAAO;AACL,gBAAQ,IAAI,oDAA0C;AAAA,MACxD;AAEA,cAAQ,IAAI,uCAAkC;AAAA,IAChD,SAAS,KAAU;AACjB,cAAQ,MAAM;AAAA,sBAAoB,IAAI,OAAO,EAAE;AAC/C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;ACvDA,SAAS,WAAAC,gBAAe;AACxB,SAAS,aAAAC,YAAW,iBAAAC,gBAAe,cAAAC,mBAAkB;AACrD,SAAS,QAAAC,aAAY;AAErB,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BlB,SAAS,QAAQ;AACtB,QAAM,MAAM,IAAIJ,SAAQ,IAAI,EACzB,YAAY,yCAAyC,EACrD,OAAO,MAAM;AACZ,UAAM,YAAYI,MAAK,QAAQ,IAAI,GAAG,SAAS;AAC/C,UAAM,eAAeA,MAAK,WAAW,WAAW;AAChD,UAAM,eAAeA,MAAK,cAAc,cAAc;AAEtD,YAAQ,IAAI,wCAAiC;AAE7C,QAAI,CAACD,YAAW,YAAY,GAAG;AAC7B,MAAAF,WAAU,cAAc,EAAE,WAAW,KAAK,CAAC;AAC3C,cAAQ,IAAI,sBAAsB,YAAY,EAAE;AAAA,IAClD;AAEA,QAAIE,YAAW,YAAY,GAAG;AAC5B,cAAQ,KAAK,iDAAuC,YAAY,aAAa;AAC7E;AAAA,IACF;AAEA,IAAAD,eAAc,cAAc,iBAAiB,KAAK,IAAI,IAAI;AAC1D,YAAQ,IAAI,oCAA+B,YAAY,EAAE;AACzD,YAAQ,IAAI,aAAa;AACzB,YAAQ,IAAI,iCAAiC;AAC7C,YAAQ,IAAI,sDAAsD;AAAA,EACpE,CAAC;AAEH,SAAO;AACT;;;AbjDA,IAAMG,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,EAAE,QAAQ,IAAIA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAIC,SAAQ;AAC5B,QACG,KAAK,IAAI,EACT,YAAY,8EAA+D,EAC3E,QAAQ,OAAO;AAElB,QAAQ,WAAW,OAAO,CAAC;AAC3B,QAAQ,WAAW,aAAa,CAAC;AACjC,QAAQ,WAAW,OAAO,CAAC;AAC3B,QAAQ,WAAW,QAAQ,CAAC;AAC5B,QAAQ,WAAW,MAAM,CAAC;AAC1B,QAAQ,WAAW,UAAU,CAAC;AAC9B,QAAQ,WAAW,SAAS,CAAC;AAC7B,QAAQ,WAAW,QAAQ,CAAC;AAC5B,QAAQ,WAAW,MAAM,CAAC;AAE1B,QAAQ,WAAW,QAAQ,IAAI;","names":["Command","version","Command","readFileSync","mkdirSync","writeFileSync","statSync","join","resolve","Command","Command","mkdirSync","writeFileSync","join","RULE_10_PLAYWRIGHT_KNOWLEDGE_BASE","ADVANCED_DOC_MAP","fetchDocContext","callAnthropic","callOpenAiCompatible","getAvailableCtVarKeys","href","mkdirSync","writeFileSync","join","normalizeTag","ensureStatement","slugify","output","mkdirSync","join","writeFileSync","Command","Command","spawn","Command","spawn","existsSync","join","Command","spawn","resolve","Command","mkdirSync","writeFileSync","existsSync","join","require","Command"]}