assuremind 1.0.0
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/CONTRIBUTING.md +254 -0
- package/LICENSE +21 -0
- package/README.md +367 -0
- package/dist/cli/index.js +14933 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.mts +2950 -0
- package/dist/index.d.ts +2950 -0
- package/dist/index.js +1628 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1525 -0
- package/dist/index.mjs.map +1 -0
- package/docs/CLI-REFERENCE.md +312 -0
- package/docs/GETTING-STARTED.md +378 -0
- package/docs/STUDIO.md +390 -0
- package/package.json +118 -0
- package/templates/AUTOMIND.md +275 -0
- package/templates/autotest.config.ts +25 -0
- package/templates/docs/CLI-REFERENCE.md +413 -0
- package/templates/docs/GETTING-STARTED.md +417 -0
- package/templates/docs/STUDIO.md +625 -0
- package/templates/env.example +112 -0
- package/templates/env.minimal +103 -0
- package/templates/gitignore +17 -0
- package/templates/global-variables.json +5 -0
- package/ui/dist/assets/index-CdtAorWT.js +819 -0
- package/ui/dist/assets/index-KjpMCzao.css +1 -0
- package/ui/dist/favicon.svg +36 -0
- package/ui/dist/index.html +15 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../node_modules/tsup/assets/cjs_shims.js","../../src/cli/ui.ts","../../src/types/config.ts","../../src/cli/init.ts","../../src/utils/errors.ts","../../src/utils/env.ts","../../src/utils/logger.ts","../../src/storage/utils.ts","../../src/storage/config-store.ts","../../src/server/types.ts","../../src/server/websocket.ts","../../src/server/static.ts","../../src/server/utils.ts","../../src/server/routes/config.ts","../../src/types/suite.ts","../../src/utils/sanitize.ts","../../src/storage/suite-store.ts","../../src/server/routes/suites.ts","../../src/engine/step-type-detector.ts","../../src/storage/case-store.ts","../../src/server/routes/cases.ts","../../src/types/variable.ts","../../src/storage/variable-store.ts","../../src/ai/template-engine.ts","../../src/utils/hash.ts","../../src/ai/code-cache.ts","../../src/ai/complexity-classifier.ts","../../src/ai/batch-processor.ts","../../src/ai/smart-router.ts","../../src/ai/types.ts","../../src/ai/prompts/step-to-code.ts","../../src/ai/prompts/story-to-suite.ts","../../src/ai/prompts/self-heal.ts","../../src/ai/prompts/batch-generate.ts","../../src/ai/providers/base.ts","../../src/ai/providers/anthropic.ts","../../src/ai/providers/openai.ts","../../src/ai/providers/google.ts","../../src/ai/providers/azure-openai.ts","../../src/ai/providers/bedrock.ts","../../src/ai/providers/openai-compatible.ts","../../src/ai/providers/deepseek.ts","../../src/ai/providers/groq.ts","../../src/ai/providers/together.ts","../../src/ai/providers/qwen.ts","../../src/ai/providers/perplexity.ts","../../src/ai/providers/ollama.ts","../../src/ai/providers/custom.ts","../../src/ai/router.ts","../../src/server/routes/steps.ts","../../src/storage/hooks-store.ts","../../src/server/routes/hooks.ts","../../src/server/routes/variables.ts","../../src/types/healing.ts","../../src/storage/healing-store.ts","../../src/server/routes/healing.ts","../../src/types/run.ts","../../src/storage/result-store.ts","../../src/engine/browser-manager.ts","../../src/engine/healing-budget.ts","../../src/engine/healing-report.ts","../../src/engine/allure-reporter.ts","../../src/engine/allure-generator.ts","../../src/utils/faker.ts","../../src/engine/variable-interpolator.ts","../../src/engine/code-runner.ts","../../src/engine/context-extractor.ts","../../src/engine/som-annotator.ts","../../src/engine/self-healing.ts","../../src/engine/executor.ts","../../src/engine/highlighter.ts","../../src/engine/data-loader.ts","../../node_modules/escape-string-regexp/index.js","../../node_modules/ms/index.js","../../node_modules/debug/src/common.js","../../node_modules/debug/src/browser.js","../../node_modules/has-flag/index.js","../../node_modules/supports-color/index.js","../../node_modules/debug/src/node.js","../../node_modules/debug/src/index.js","../../node_modules/marky/lib/marky.es.js","../../node_modules/lighthouse-logger/index.js","../../node_modules/chrome-launcher/node_modules/is-docker/index.js","../../node_modules/chrome-launcher/node_modules/is-wsl/index.js","../../node_modules/chrome-launcher/src/utils.ts","../../node_modules/chrome-launcher/src/chrome-finder.ts","../../node_modules/chrome-launcher/src/random-port.ts","../../node_modules/chrome-launcher/src/flags.ts","../../node_modules/chrome-launcher/src/chrome-launcher.ts","../../node_modules/chrome-launcher/src/index.ts","../../src/engine/runner.ts","../../src/server/routes/run.ts","../../src/ai/swagger-parser.ts","../../src/server/routes/story.ts","../../src/server/routes/report.ts","../../src/storage/baseline-store.ts","../../src/server/routes/media.ts","../../src/xray/client.ts","../../src/types/xray.ts","../../src/storage/xray-store.ts","../../src/xray/service.ts","../../src/server/routes/xray.ts","../../src/git/service.ts","../../src/git/ai.ts","../../src/server/routes/git.ts","../../src/server/routes/data-files.ts","../../src/server/routes/search.ts","../../src/server/routes/ci-config.ts","../../src/server/routes/templates.ts","../../src/server/routes/flakiness.ts","../../src/storage/step-library-store.ts","../../src/server/routes/step-library.ts","../../src/server/index.ts","../../src/cli/studio.ts","../../src/cli/run.ts","../../src/cli/generate.ts","../../src/cli/validate.ts","../../src/cli/doctor.ts","../../src/cli/apply-healing.ts","../../src/cli/index.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import chalk from 'chalk';\r\nimport ora from 'ora';\r\n\r\nexport const colors = {\r\n success: chalk.green,\r\n error: chalk.red,\r\n warn: chalk.yellow,\r\n info: chalk.cyan,\r\n dim: chalk.dim,\r\n bold: chalk.bold,\r\n accent: chalk.hex('#00adf7'),\r\n};\r\n\r\nexport function printSuccess(msg: string): void {\r\n process.stdout.write(`${colors.success('✓')} ${msg}\\n`);\r\n}\r\n\r\nexport function printError(msg: string): void {\r\n process.stderr.write(`${colors.error('✗')} ${msg}\\n`);\r\n}\r\n\r\nexport function printWarn(msg: string): void {\r\n process.stdout.write(`${colors.warn('⚠')} ${msg}\\n`);\r\n}\r\n\r\nexport function printInfo(msg: string): void {\r\n process.stdout.write(`${colors.info('ℹ')} ${msg}\\n`);\r\n}\r\n\r\nexport function printSkipped(msg: string): void {\r\n process.stdout.write(`${colors.dim('–')} ${colors.dim(msg)}\\n`);\r\n}\r\n\r\nexport function printBox(lines: string[]): void {\r\n const width = Math.max(...lines.map((l) => l.length)) + 4;\r\n const border = colors.accent('─'.repeat(width));\r\n process.stdout.write(`\\n${border}\\n`);\r\n for (const line of lines) {\r\n process.stdout.write(` ${line}\\n`);\r\n }\r\n process.stdout.write(`${border}\\n\\n`);\r\n}\r\n\r\nexport function createSpinner(text: string): ReturnType<typeof ora> {\r\n return ora({ text, color: 'cyan' });\r\n}\r\n\r\nexport function handleFatalError(err: unknown): never {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n printError(msg);\r\n process.exit(1);\r\n}\r\n","import { z } from 'zod';\r\n\r\nexport const ScreenshotModeSchema = z.enum(['off', 'on', 'only-on-failure']);\r\nexport const VideoModeSchema = z.enum(['off', 'on', 'on-first-retry', 'retain-on-failure']);\r\nexport const TraceModeSchema = z.enum(['off', 'on', 'on-first-retry', 'retain-on-failure']);\r\nexport const BrowserNameSchema = z.enum(['chromium', 'firefox', 'webkit']);\r\n\r\n/**\r\n * Page-load wait strategy applied after every navigation / action.\r\n * commit — wait only until the first network response (fastest)\r\n * domcontentloaded — wait until DOMContentLoaded fires (recommended default)\r\n * load — wait until the load event fires\r\n * networkidle — wait until no network activity for 500 ms (slowest, most stable)\r\n */\r\nexport const PageLoadStrategySchema = z.enum(['commit', 'domcontentloaded', 'load', 'networkidle']);\r\nexport const EnvironmentSchema = z.enum(['dev', 'stage', 'test', 'prod']);\r\nexport type Environment = z.infer<typeof EnvironmentSchema>;\r\n\r\nexport const EnvironmentUrlsSchema = z.object({\r\n dev: z.string().url().or(z.literal('')).default(''),\r\n stage: z.string().url().or(z.literal('')).default(''),\r\n test: z.string().url().or(z.literal('')).default(''),\r\n prod: z.string().url().or(z.literal('')).default(''),\r\n});\r\nexport type EnvironmentUrls = z.infer<typeof EnvironmentUrlsSchema>;\r\n\r\nexport type ScreenshotMode = z.infer<typeof ScreenshotModeSchema>;\r\nexport type VideoMode = z.infer<typeof VideoModeSchema>;\r\nexport type TraceMode = z.infer<typeof TraceModeSchema>;\r\nexport type BrowserName = z.infer<typeof BrowserNameSchema>;\r\nexport type PageLoadStrategy = z.infer<typeof PageLoadStrategySchema>;\r\n\r\nexport const HealingConfigSchema = z.object({\r\n enabled: z.boolean(),\r\n maxLevel: z.number().int().min(1).max(6),\r\n dailyBudget: z.number().positive(),\r\n autoPR: z.boolean(),\r\n});\r\n\r\nexport const ReportingConfigSchema = z.object({\r\n allure: z.boolean(),\r\n html: z.boolean(),\r\n json: z.boolean(),\r\n});\r\n\r\nexport const ViewportSchema = z.object({\r\n width: z.number().int().positive(),\r\n height: z.number().int().positive(),\r\n});\r\nexport type Viewport = z.infer<typeof ViewportSchema>;\r\n\r\nexport const EnvironmentProfileSchema = z.object({\r\n name: z.string().min(1),\r\n environment: EnvironmentSchema,\r\n baseUrl: z.string().url(),\r\n browsers: z.array(BrowserNameSchema).min(1),\r\n headless: z.boolean().optional(),\r\n});\r\n\r\nexport type EnvironmentProfile = z.infer<typeof EnvironmentProfileSchema>;\r\n\r\nexport const AutotestConfigSchema = z.object({\r\n baseUrl: z.string().url(),\r\n environment: EnvironmentSchema.default('stage'),\r\n environmentUrls: EnvironmentUrlsSchema.default({\r\n dev: '',\r\n stage: '',\r\n test: '',\r\n prod: '',\r\n }),\r\n browsers: z.array(BrowserNameSchema).min(1),\r\n headless: z.boolean(),\r\n viewport: ViewportSchema.default({ width: 1280, height: 720 }),\r\n timeout: z.number().int().positive(),\r\n retries: z.number().int().min(0),\r\n parallel: z.number().int().positive(),\r\n pageLoad: PageLoadStrategySchema.default('domcontentloaded'),\r\n screenshot: ScreenshotModeSchema,\r\n video: VideoModeSchema,\r\n trace: TraceModeSchema,\r\n healing: HealingConfigSchema,\r\n reporting: ReportingConfigSchema,\r\n studioPort: z.number().int().min(1024).max(65535),\r\n profiles: z.array(EnvironmentProfileSchema).default([]),\r\n activeProfile: z.string().optional(),\r\n /** Playwright device descriptor name for emulation (e.g. 'iPhone 15 Pro'). */\r\n device: z.string().optional(),\r\n});\r\n\r\nexport type HealingConfig = z.infer<typeof HealingConfigSchema>;\r\nexport type ReportingConfig = z.infer<typeof ReportingConfigSchema>;\r\nexport type AutotestConfig = z.infer<typeof AutotestConfigSchema>;\r\n\r\nexport const DEFAULT_CONFIG: AutotestConfig = {\r\n baseUrl: 'http://localhost:3000',\r\n environment: 'stage',\r\n environmentUrls: {\r\n dev: '',\r\n stage: 'http://localhost:3000',\r\n test: '',\r\n prod: '',\r\n },\r\n browsers: ['chromium'],\r\n headless: true,\r\n viewport: { width: 1280, height: 720 },\r\n timeout: 30000,\r\n retries: 1,\r\n parallel: 1,\r\n pageLoad: 'domcontentloaded',\r\n screenshot: 'only-on-failure',\r\n video: 'off',\r\n trace: 'on-first-retry',\r\n healing: {\r\n enabled: true,\r\n maxLevel: 5,\r\n dailyBudget: 5.0,\r\n autoPR: false,\r\n },\r\n reporting: {\r\n allure: true,\r\n html: true,\r\n json: true,\r\n },\r\n studioPort: 4400,\r\n profiles: [],\r\n};\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { execSync } from 'child_process';\r\nimport { printSuccess, printSkipped, printBox, printInfo, createSpinner, handleFatalError } from './ui.js';\r\n\r\nconst DIRS_TO_CREATE = [\r\n 'tests',\r\n 'variables',\r\n 'results',\r\n 'results/screenshots',\r\n 'results/videos',\r\n 'results/traces',\r\n 'results/reports',\r\n 'results/healing',\r\n 'fixtures',\r\n 'fixtures/auth',\r\n 'fixtures/data',\r\n 'docs',\r\n];\r\n\r\ninterface TemplateFile {\r\n dest: string;\r\n template: string;\r\n}\r\n\r\nconst TEMPLATE_FILES: TemplateFile[] = [\r\n { dest: '.env.example', template: 'env.example' },\r\n { dest: '.env', template: 'env.minimal' },\r\n { dest: '.gitignore', template: 'gitignore' },\r\n { dest: 'autotest.config.ts', template: 'autotest.config.ts' },\r\n { dest: 'variables/global.json', template: 'global-variables.json' },\r\n { dest: 'AUTOMIND.md', template: 'AUTOMIND.md' },\r\n { dest: 'docs/GETTING-STARTED.md', template: 'docs/GETTING-STARTED.md' },\r\n { dest: 'docs/STUDIO.md', template: 'docs/STUDIO.md' },\r\n { dest: 'docs/CLI-REFERENCE.md', template: 'docs/CLI-REFERENCE.md' },\r\n];\r\n\r\nconst EMPTY_JSON_FILES = [\r\n 'variables/dev.env.json',\r\n 'variables/staging.env.json',\r\n 'variables/prod.env.json',\r\n];\r\n\r\nfunction resolveTemplatesDir(): string {\r\n // Works from both dist/cli/ (production) and src/cli/ (dev/tests)\r\n return path.resolve(__dirname, '../../templates');\r\n}\r\n\r\nexport async function runInit(options: { skipPlaywright?: boolean } = {}): Promise<void> {\r\n // Step 1: Validate environment\r\n if (!(await fs.pathExists('package.json'))) {\r\n handleFatalError(\r\n 'No package.json found in the current directory.\\n' +\r\n ' How to fix: Run \"npm init -y\" first, then retry \"npx assuremind init\".',\r\n );\r\n }\r\n\r\n printInfo('Initialising Assuremind in the current directory…\\n');\r\n\r\n // Step 2: Create directory structure\r\n printInfo('Creating directories…');\r\n for (const dir of DIRS_TO_CREATE) {\r\n await fs.ensureDir(dir);\r\n const isEmpty = (await fs.readdir(dir)).length === 0;\r\n if (isEmpty) {\r\n await fs.writeFile(path.join(dir, '.gitkeep'), '');\r\n }\r\n printSuccess(` ${dir}/`);\r\n }\r\n\r\n // Step 3: Copy template files (idempotent — never overwrite)\r\n process.stdout.write('\\n');\r\n printInfo('Creating config files…');\r\n const templatesDir = resolveTemplatesDir();\r\n\r\n for (const { dest, template } of TEMPLATE_FILES) {\r\n if (await fs.pathExists(dest)) {\r\n printSkipped(` ${dest} (already exists)`);\r\n continue;\r\n }\r\n const src = path.join(templatesDir, template);\r\n await fs.copy(src, dest);\r\n printSuccess(` ${dest}`);\r\n }\r\n\r\n for (const jsonFile of EMPTY_JSON_FILES) {\r\n if (await fs.pathExists(jsonFile)) {\r\n printSkipped(` ${jsonFile} (already exists)`);\r\n continue;\r\n }\r\n await fs.writeJson(jsonFile, {}, { spaces: 2 });\r\n printSuccess(` ${jsonFile}`);\r\n }\r\n\r\n // Step 4: Write autotest.config.json (runtime config, mirrors the TS file)\r\n if (!(await fs.pathExists('autotest.config.json'))) {\r\n const { DEFAULT_CONFIG } = await import('../types/config.js');\r\n await fs.writeJson('autotest.config.json', DEFAULT_CONFIG, { spaces: 2 });\r\n printSuccess(' autotest.config.json');\r\n } else {\r\n printSkipped(' autotest.config.json (already exists)');\r\n }\r\n\r\n // Step 5: Install Playwright browsers\r\n if (!options.skipPlaywright) {\r\n process.stdout.write('\\n');\r\n const spinner = createSpinner('Installing Playwright browsers (Chromium, Firefox, WebKit)…');\r\n spinner.start();\r\n try {\r\n execSync('npx playwright install --with-deps', { stdio: 'pipe' });\r\n spinner.succeed('Playwright browsers installed');\r\n } catch (err) {\r\n spinner.fail('Failed to install Playwright browsers');\r\n const msg = err instanceof Error ? err.message : String(err);\r\n process.stderr.write(\r\n ` Run manually: npx playwright install --with-deps\\n Error: ${msg}\\n`,\r\n );\r\n }\r\n }\r\n\r\n // Step 6: Print success message\r\n printBox([\r\n '✅ Assuremind initialised!',\r\n '',\r\n 'Next steps:',\r\n ' 1. Edit .env with your AI provider key',\r\n ' 2. Run: npx assuremind studio',\r\n ' 3. Start creating tests in the browser!',\r\n '',\r\n 'Docs: https://assuremind.dev/docs',\r\n ]);\r\n}\r\n","export class AssuremindError extends Error {\r\n public readonly code: string;\r\n\r\n constructor(message: string, code: string) {\r\n super(message);\r\n this.name = 'AssuremindError';\r\n this.code = code;\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n\r\nexport class ProviderError extends AssuremindError {\r\n public readonly provider: string;\r\n\r\n constructor(message: string, provider: string, code = 'PROVIDER_ERROR') {\r\n super(message, code);\r\n this.name = 'ProviderError';\r\n this.provider = provider;\r\n }\r\n}\r\n\r\nexport class ExecutionError extends AssuremindError {\r\n public readonly stepId: string;\r\n\r\n constructor(message: string, stepId: string, code = 'EXECUTION_ERROR') {\r\n super(message, code);\r\n this.name = 'ExecutionError';\r\n this.stepId = stepId;\r\n }\r\n}\r\n\r\nexport class ConfigError extends AssuremindError {\r\n constructor(message: string, code = 'CONFIG_ERROR') {\r\n super(message, code);\r\n this.name = 'ConfigError';\r\n }\r\n}\r\n\r\nexport class ValidationError extends AssuremindError {\r\n public readonly field?: string;\r\n\r\n constructor(message: string, field?: string, code = 'VALIDATION_ERROR') {\r\n super(message, code);\r\n this.name = 'ValidationError';\r\n this.field = field;\r\n }\r\n}\r\n\r\nexport class HealingError extends AssuremindError {\r\n public readonly level: number;\r\n\r\n constructor(message: string, level: number, code = 'HEALING_ERROR') {\r\n super(message, code);\r\n this.name = 'HealingError';\r\n this.level = level;\r\n }\r\n}\r\n\r\nexport class StorageError extends AssuremindError {\r\n public readonly path: string;\r\n\r\n constructor(message: string, path: string, code = 'STORAGE_ERROR') {\r\n super(message, code);\r\n this.name = 'StorageError';\r\n this.path = path;\r\n }\r\n}\r\n\r\nexport function isAssuremindError(error: unknown): error is AssuremindError {\r\n return error instanceof AssuremindError;\r\n}\r\n\r\nexport function formatError(error: unknown): string {\r\n if (error instanceof AssuremindError) {\r\n return `[${error.code}] ${error.message}`;\r\n }\r\n if (error instanceof Error) {\r\n return error.message;\r\n }\r\n return String(error);\r\n}\r\n","import { config as loadDotenv } from 'dotenv';\r\nimport { z } from 'zod';\r\nimport { ConfigError } from './errors.js';\r\n\r\nloadDotenv();\r\n\r\nconst AI_PROVIDERS = [\r\n 'anthropic',\r\n 'openai',\r\n 'google',\r\n 'azure-openai',\r\n 'bedrock',\r\n 'deepseek',\r\n 'groq',\r\n 'together',\r\n 'qwen',\r\n 'perplexity',\r\n 'ollama',\r\n 'custom',\r\n] as const;\r\n\r\nexport type AIProviderName = (typeof AI_PROVIDERS)[number];\r\n\r\nconst BaseEnvSchema = z.object({\r\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\r\n LOG_LEVEL: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'),\r\n AI_PROVIDER: z.enum(AI_PROVIDERS),\r\n AI_TIERED_ENABLED: z\r\n .string()\r\n .transform((v) => v === 'true')\r\n .default('false'),\r\n AI_TIERED_FAST_PROVIDER: z.enum(AI_PROVIDERS).optional(),\r\n AI_TIERED_FAST_MODEL: z.string().optional(),\r\n AI_TIMEOUT: z.coerce.number().int().positive().default(30),\r\n AI_MAX_RETRIES: z.coerce.number().int().min(0).max(10).default(2),\r\n});\r\n\r\nconst AnthropicEnvSchema = z.object({\r\n ANTHROPIC_API_KEY: z.string().min(1),\r\n ANTHROPIC_MODEL: z.string().default('claude-sonnet-4-20250514'),\r\n});\r\n\r\nconst OpenAIEnvSchema = z.object({\r\n OPENAI_API_KEY: z.string().min(1),\r\n OPENAI_MODEL: z.string().default('gpt-4o'),\r\n});\r\n\r\nconst GoogleEnvSchema = z.object({\r\n GOOGLE_API_KEY: z.string().min(1),\r\n GOOGLE_MODEL: z.string().default('gemini-2.5-pro'),\r\n});\r\n\r\nconst AzureOpenAIEnvSchema = z.object({\r\n AZURE_OPENAI_API_KEY: z.string().min(1),\r\n AZURE_OPENAI_ENDPOINT: z.string().url(),\r\n AZURE_OPENAI_DEPLOYMENT: z.string().min(1),\r\n AZURE_OPENAI_API_VERSION: z.string().default('2024-10-21'),\r\n});\r\n\r\nconst BedrockEnvSchema = z.object({\r\n AWS_ACCESS_KEY_ID: z.string().min(1),\r\n AWS_SECRET_ACCESS_KEY: z.string().min(1),\r\n AWS_SESSION_TOKEN: z.string().optional(),\r\n AWS_REGION: z.string().default('us-east-1'),\r\n BEDROCK_MODEL: z.string().default('anthropic.claude-sonnet-4-20250514-v1:0'),\r\n});\r\n\r\nconst DeepSeekEnvSchema = z.object({\r\n DEEPSEEK_API_KEY: z.string().min(1),\r\n DEEPSEEK_MODEL: z.string().default('deepseek-chat'),\r\n});\r\n\r\nconst GroqEnvSchema = z.object({\r\n GROQ_API_KEY: z.string().min(1),\r\n GROQ_MODEL: z.string().default('llama-3.3-70b-versatile'),\r\n});\r\n\r\nconst TogetherEnvSchema = z.object({\r\n TOGETHER_API_KEY: z.string().min(1),\r\n TOGETHER_MODEL: z.string().default('meta-llama/Llama-3.3-70B-Instruct-Turbo'),\r\n});\r\n\r\nconst QwenEnvSchema = z.object({\r\n QWEN_API_KEY: z.string().min(1),\r\n QWEN_BASE_URL: z.string().url().default('https://dashscope-intl.aliyuncs.com/compatible-mode/v1'),\r\n QWEN_MODEL: z.string().default('qwen-max'),\r\n});\r\n\r\nconst PerplexityEnvSchema = z.object({\r\n PERPLEXITY_API_KEY: z.string().min(1),\r\n PERPLEXITY_MODEL: z.string().default('sonar-pro'),\r\n});\r\n\r\nconst OllamaEnvSchema = z.object({\r\n OLLAMA_BASE_URL: z.string().url().default('http://localhost:11434'),\r\n OLLAMA_MODEL: z.string().default('llama3.3'),\r\n});\r\n\r\nconst CustomEnvSchema = z.object({\r\n CUSTOM_API_KEY: z.string().min(1),\r\n CUSTOM_BASE_URL: z.string().url(),\r\n CUSTOM_MODEL: z.string().min(1),\r\n});\r\n\r\nconst PROVIDER_SCHEMAS: Record<AIProviderName, z.ZodObject<z.ZodRawShape>> = {\r\n anthropic: AnthropicEnvSchema,\r\n openai: OpenAIEnvSchema,\r\n google: GoogleEnvSchema,\r\n 'azure-openai': AzureOpenAIEnvSchema,\r\n bedrock: BedrockEnvSchema,\r\n deepseek: DeepSeekEnvSchema,\r\n groq: GroqEnvSchema,\r\n together: TogetherEnvSchema,\r\n qwen: QwenEnvSchema,\r\n perplexity: PerplexityEnvSchema,\r\n ollama: OllamaEnvSchema,\r\n custom: CustomEnvSchema,\r\n};\r\n\r\nexport type BaseEnv = z.infer<typeof BaseEnvSchema>;\r\nexport type ValidatedEnv = BaseEnv & Record<string, unknown>;\r\n\r\nlet _cachedEnv: ValidatedEnv | null = null;\r\n\r\n/**\r\n * Loads and validates the environment for the configured AI provider.\r\n * Throws a ConfigError with actionable message if validation fails.\r\n * Result is cached after first call.\r\n */\r\nexport function validateEnv(): ValidatedEnv {\r\n if (_cachedEnv !== null) return _cachedEnv;\r\n\r\n const baseResult = BaseEnvSchema.safeParse(process.env);\r\n if (!baseResult.success) {\r\n const issues = baseResult.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ConfigError(\r\n `Missing or invalid environment variables:\\n${issues}\\n\\n` +\r\n `How to fix: Copy .env.example to .env and fill in your AI provider credentials.`,\r\n 'ENV_VALIDATION_FAILED',\r\n );\r\n }\r\n\r\n const providerName = baseResult.data.AI_PROVIDER;\r\n const providerSchema = PROVIDER_SCHEMAS[providerName];\r\n const providerResult = providerSchema.safeParse(process.env);\r\n\r\n if (!providerResult.success) {\r\n const issues = providerResult.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ConfigError(\r\n `Provider \"${providerName}\" is missing required environment variables:\\n${issues}\\n\\n` +\r\n `How to fix: Check .env.example for the ${providerName} section and add the required keys to .env.`,\r\n 'PROVIDER_ENV_MISSING',\r\n );\r\n }\r\n\r\n const merged: ValidatedEnv = {\r\n ...baseResult.data,\r\n ...(providerResult.data as Record<string, unknown>),\r\n };\r\n _cachedEnv = merged;\r\n\r\n return _cachedEnv;\r\n}\r\n\r\n/** Clears the cached env — used in tests to reset state between test cases. */\r\nexport function clearEnvCache(): void {\r\n _cachedEnv = null;\r\n}\r\n\r\n/** Returns the validated env without throwing — for non-critical reads. */\r\nexport function tryGetEnv(): ValidatedEnv | null {\r\n try {\r\n return validateEnv();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","import pino from 'pino';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\n\r\nconst isDevelopment = process.env['NODE_ENV'] !== 'production';\r\n\r\nconst transport = isDevelopment\r\n ? {\r\n target: 'pino-pretty',\r\n options: {\r\n colorize: true,\r\n translateTime: 'HH:MM:ss',\r\n ignore: 'pid,hostname',\r\n messageFormat: '[assuremind] {msg}',\r\n },\r\n }\r\n : undefined;\r\n\r\nexport const logger = pino(\r\n {\r\n level: process.env['LOG_LEVEL'] ?? 'info',\r\n base: { name: 'assuremind' },\r\n },\r\n transport ? pino.transport(transport) : undefined,\r\n);\r\n\r\nexport type Logger = typeof logger;\r\n\r\nexport function createChildLogger(component: string): pino.Logger {\r\n return logger.child({ component });\r\n}\r\n\r\n// ─── Per-run file logging ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Creates a per-run log file and returns a writable stream + file path.\r\n * All log entries during the run are written to this file in addition to console.\r\n */\r\nexport interface RunLogHandle {\r\n logFilePath: string;\r\n write: (entry: string) => void;\r\n close: () => void;\r\n}\r\n\r\nexport async function createRunLogFile(rootDir: string, runId: string): Promise<RunLogHandle> {\r\n const logsDir = path.join(rootDir, 'results', 'logs');\r\n await fs.ensureDir(logsDir);\r\n const logFilePath = path.join(logsDir, `run-${runId}.log`);\r\n const stream = fs.createWriteStream(logFilePath, { flags: 'a', encoding: 'utf-8' });\r\n\r\n // Write header\r\n stream.write(`=== AutoMind Test Run: ${runId} ===\\n`);\r\n stream.write(`Started: ${new Date().toISOString()}\\n`);\r\n stream.write('='.repeat(60) + '\\n\\n');\r\n\r\n return {\r\n logFilePath,\r\n write: (entry: string) => {\r\n stream.write(entry + '\\n');\r\n },\r\n close: () => {\r\n stream.write('\\n' + '='.repeat(60) + '\\n');\r\n stream.write(`Completed: ${new Date().toISOString()}\\n`);\r\n stream.end();\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Creates a pino destination that writes to both console and a run log file.\r\n * Returns a child logger that tees to the file.\r\n */\r\nexport function createRunLogger(runLogHandle: RunLogHandle): pino.Logger {\r\n const runLogger = pino(\r\n {\r\n level: process.env['LOG_LEVEL'] ?? 'info',\r\n base: { name: 'assuremind' },\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n },\r\n {\r\n write(msg: string) {\r\n // Write to the run log file (plain JSON line)\r\n runLogHandle.write(msg.trim());\r\n },\r\n },\r\n );\r\n return runLogger;\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { StorageError } from '../utils/errors.js';\r\n\r\n/**\r\n * Atomically writes JSON to a file using a temp file + rename pattern.\r\n * This ensures the file is never left in a partially-written state.\r\n */\r\nexport async function atomicWriteJson(filePath: string, data: unknown): Promise<void> {\r\n const dir = path.dirname(filePath);\r\n await fs.ensureDir(dir);\r\n\r\n const tmpPath = `${filePath}.${process.pid}.tmp`;\r\n try {\r\n await fs.writeJson(tmpPath, data, { spaces: 2 });\r\n await fs.rename(tmpPath, filePath);\r\n } catch (err) {\r\n // Clean up temp file on failure\r\n await fs.remove(tmpPath).catch(() => undefined);\r\n throw new StorageError(\r\n `Failed to write file \"${filePath}\": ${err instanceof Error ? err.message : String(err)}`,\r\n filePath,\r\n 'WRITE_FAILED',\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Reads and parses a JSON file, returning the parsed value.\r\n * Throws a StorageError if the file cannot be read or parsed.\r\n */\r\nexport async function readJson(filePath: string): Promise<unknown> {\r\n try {\r\n return await fs.readJson(filePath);\r\n } catch (err) {\r\n throw new StorageError(\r\n `Failed to read JSON file \"${filePath}\": ${err instanceof Error ? err.message : String(err)}`,\r\n filePath,\r\n 'READ_FAILED',\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Reads a plain text file. Throws StorageError on failure.\r\n */\r\nexport async function readText(filePath: string): Promise<string> {\r\n try {\r\n return await fs.readFile(filePath, 'utf8');\r\n } catch (err) {\r\n throw new StorageError(\r\n `Failed to read file \"${filePath}\": ${err instanceof Error ? err.message : String(err)}`,\r\n filePath,\r\n 'READ_FAILED',\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Atomically writes plain text to a file.\r\n */\r\nexport async function atomicWriteText(filePath: string, content: string): Promise<void> {\r\n const dir = path.dirname(filePath);\r\n await fs.ensureDir(dir);\r\n\r\n const tmpPath = `${filePath}.${process.pid}.tmp`;\r\n try {\r\n await fs.writeFile(tmpPath, content, 'utf8');\r\n await fs.rename(tmpPath, filePath);\r\n } catch (err) {\r\n await fs.remove(tmpPath).catch(() => undefined);\r\n throw new StorageError(\r\n `Failed to write file \"${filePath}\": ${err instanceof Error ? err.message : String(err)}`,\r\n filePath,\r\n 'WRITE_FAILED',\r\n );\r\n }\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { AutotestConfig, AutotestConfigSchema, DEFAULT_CONFIG } from '../types/config.js';\r\nimport { ConfigError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson, atomicWriteText, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('config-store');\r\n\r\n/** Runtime config is stored as JSON for reliable loading without TS compilation. */\r\nconst CONFIG_JSON = 'autotest.config.json';\r\n/** Human-readable TypeScript config kept in sync with the JSON. */\r\nconst CONFIG_TS = 'autotest.config.ts';\r\n\r\n/**\r\n * Reads the runtime config from autotest.config.json.\r\n * Falls back to DEFAULT_CONFIG if the file does not exist.\r\n */\r\nexport async function readConfig(rootDir: string): Promise<AutotestConfig> {\r\n const jsonPath = path.join(rootDir, CONFIG_JSON);\r\n\r\n if (!(await fs.pathExists(jsonPath))) {\r\n logger.debug({ rootDir }, 'No autotest.config.json found — using defaults');\r\n return DEFAULT_CONFIG;\r\n }\r\n\r\n const raw = await readJson(jsonPath);\r\n const result = AutotestConfigSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Invalid autotest.config.json at \"${jsonPath}\":\\n${issues}\\n\\n` +\r\n `How to fix: Run \"npx assuremind init\" to reset to defaults, ` +\r\n `or manually correct the file using autotest.config.ts as reference.`,\r\n 'config',\r\n 'INVALID_CONFIG',\r\n );\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes the config atomically to autotest.config.json\r\n * and regenerates the human-readable autotest.config.ts.\r\n */\r\nexport async function writeConfig(rootDir: string, config: AutotestConfig): Promise<void> {\r\n const result = AutotestConfigSchema.safeParse(config);\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid config:\\n${issues}`,\r\n 'config',\r\n 'INVALID_CONFIG',\r\n );\r\n }\r\n\r\n const jsonPath = path.join(rootDir, CONFIG_JSON);\r\n await atomicWriteJson(jsonPath, result.data);\r\n\r\n const tsPath = path.join(rootDir, CONFIG_TS);\r\n await atomicWriteText(tsPath, generateConfigTs(result.data));\r\n\r\n logger.info({ rootDir }, 'Config saved');\r\n}\r\n\r\n/**\r\n * Updates specific config fields (merges, validates, and writes).\r\n */\r\nexport async function updateConfig(\r\n rootDir: string,\r\n updates: Partial<AutotestConfig>,\r\n): Promise<AutotestConfig> {\r\n const current = await readConfig(rootDir);\r\n const merged: AutotestConfig = {\r\n ...current,\r\n ...updates,\r\n healing: { ...current.healing, ...(updates.healing ?? {}) },\r\n reporting: { ...current.reporting, ...(updates.reporting ?? {}) },\r\n environmentUrls: { ...current.environmentUrls, ...(updates.environmentUrls ?? {}) },\r\n };\r\n await writeConfig(rootDir, merged);\r\n return merged;\r\n}\r\n\r\n/**\r\n * Checks whether a config exists in the given directory.\r\n */\r\nexport async function configExists(rootDir: string): Promise<boolean> {\r\n const jsonPath = path.join(rootDir, CONFIG_JSON);\r\n const tsPath = path.join(rootDir, CONFIG_TS);\r\n return (await fs.pathExists(jsonPath)) || (await fs.pathExists(tsPath));\r\n}\r\n\r\n/**\r\n * Validates the config and throws a ConfigError with actionable message if invalid.\r\n */\r\nexport async function validateConfig(rootDir: string): Promise<void> {\r\n const config = await readConfig(rootDir);\r\n\r\n if (!config.baseUrl) {\r\n throw new ConfigError(\r\n 'baseUrl is required in autotest.config.ts. ' +\r\n 'Set it to your application URL, e.g. \"http://localhost:3000\".',\r\n 'CONFIG_BASE_URL_MISSING',\r\n );\r\n }\r\n\r\n logger.debug({ config }, 'Config validated successfully');\r\n}\r\n\r\n/**\r\n * Generates the human-readable autotest.config.ts content from a config object.\r\n */\r\nfunction generateConfigTs(config: AutotestConfig): string {\r\n return `import { defineConfig } from 'assuremind';\r\n\r\nexport default defineConfig({\r\n baseUrl: '${config.baseUrl}',\r\n browsers: ${JSON.stringify(config.browsers)},\r\n headless: ${config.headless},\r\n timeout: ${config.timeout},\r\n retries: ${config.retries},\r\n parallel: ${config.parallel},\r\n screenshot: '${config.screenshot}',\r\n video: '${config.video}',\r\n trace: '${config.trace}',\r\n healing: {\r\n enabled: ${config.healing.enabled},\r\n maxLevel: ${config.healing.maxLevel},\r\n dailyBudget: ${config.healing.dailyBudget},\r\n autoPR: ${config.healing.autoPR},\r\n },\r\n reporting: {\r\n allure: ${config.reporting.allure},\r\n html: ${config.reporting.html},\r\n json: ${config.reporting.json},\r\n },\r\n studioPort: ${config.studioPort},\r\n});\r\n`;\r\n}\r\n","/**\r\n * Fastify instance augmentation — adds rootDir and wsManager decorators.\r\n */\r\nimport type { WebSocketManager } from './websocket.js';\r\n\r\ndeclare module 'fastify' {\r\n interface FastifyInstance {\r\n rootDir: string;\r\n wsManager: WebSocketManager;\r\n }\r\n}\r\n","/**\r\n * WebSocket Manager — broadcasts real-time run progress to all connected Studio clients.\r\n *\r\n * Events emitted:\r\n * run:start { runId, totalTests, browser }\r\n * run:case { runId, suiteId, caseId, caseName, status }\r\n * run:step { runId, caseId, stepId, instruction, status, duration }\r\n * run:complete { runId, passed, failed, skipped, duration }\r\n * healing:event { stepId, instruction, level, strategy }\r\n */\r\nimport type { WebSocket } from 'ws';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('websocket');\r\n\r\nexport interface WsEvent {\r\n event: string;\r\n data: unknown;\r\n timestamp: number;\r\n}\r\n\r\nexport class WebSocketManager {\r\n private readonly sockets = new Set<WebSocket>();\r\n\r\n /** Called by the Fastify WebSocket route when a client connects. */\r\n add(socket: WebSocket): void {\r\n this.sockets.add(socket);\r\n logger.debug({ total: this.sockets.size }, 'WS client connected');\r\n\r\n socket.on('close', () => {\r\n this.sockets.delete(socket);\r\n logger.debug({ total: this.sockets.size }, 'WS client disconnected');\r\n });\r\n\r\n socket.on('error', (err) => {\r\n logger.warn({ err }, 'WS socket error');\r\n this.sockets.delete(socket);\r\n });\r\n }\r\n\r\n /** Broadcasts an event to every open client. */\r\n broadcast(event: string, data: unknown): void {\r\n if (this.sockets.size === 0) return;\r\n\r\n const msg = JSON.stringify({ event, data, timestamp: Date.now() } satisfies WsEvent);\r\n\r\n for (const socket of this.sockets) {\r\n if (socket.readyState === 1 /* WebSocket.OPEN */) {\r\n socket.send(msg);\r\n }\r\n }\r\n }\r\n\r\n get clientCount(): number {\r\n return this.sockets.size;\r\n }\r\n}\r\n","/**\r\n * Static file plugin — serves:\r\n * / → built React UI (ui/dist/)\r\n * /trace/* → Playwright Trace Viewer (playwright-core/lib/vite/traceViewer/)\r\n *\r\n * Falls back to a plain JSON message when the UI hasn't been built yet.\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('static');\r\n\r\nexport async function registerStatic(fastify: FastifyInstance, rootDir: string): Promise<void> {\r\n const { default: staticPlugin } = await import('@fastify/static');\r\n\r\n // ── 1. Playwright Trace Viewer ─────────────────────────────────────────────\r\n // Served at /trace/ so the UI can open:\r\n // /trace/index.html?trace=/api/results/traces/<filename>.zip\r\n const traceViewerDir = path.resolve(\r\n __dirname,\r\n '../../node_modules/playwright-core/lib/vite/traceViewer',\r\n );\r\n if (await fs.pathExists(traceViewerDir)) {\r\n await fastify.register(staticPlugin, {\r\n root: traceViewerDir,\r\n prefix: '/trace/',\r\n decorateReply: false, // only first registration decorates reply\r\n });\r\n logger.info({ traceViewerDir }, 'Serving Playwright Trace Viewer at /trace/');\r\n } else {\r\n logger.warn({ traceViewerDir }, 'Playwright Trace Viewer not found — skipping');\r\n }\r\n\r\n // ── 2. Allure HTML Reports (per-run) ──────────────────────────────────────\r\n // Each run generates results/allure-report/<runId>/index.html (single file).\r\n // Served at /allure/<runId> via the setNotFoundHandler below.\r\n const allureReportDir = path.join(rootDir, 'results', 'allure-report');\r\n await fs.ensureDir(allureReportDir);\r\n logger.info({ allureReportDir }, 'Per-run Allure reports will be served at /allure/<runId>');\r\n\r\n // ── 3. React Studio UI ─────────────────────────────────────────────────────\r\n // Must be registered last — it's the SPA catch-all.\r\n const uiDist = path.resolve(__dirname, '../../ui/dist');\r\n const uiDistExists = await fs.pathExists(uiDist);\r\n\r\n if (uiDistExists) {\r\n await fastify.register(staticPlugin, {\r\n root: uiDist,\r\n prefix: '/',\r\n decorateReply: true,\r\n index: 'index.html',\r\n });\r\n logger.info({ uiDist }, 'Serving React UI');\r\n\r\n // ── SPA fallback ──────────────────────────────────────────────────────────\r\n // When the user refreshes on /reports, /settings, /tests, etc., the browser\r\n // sends a real GET request to Fastify. No static file matches, so without\r\n // this handler Fastify returns 404. We intercept every unmatched GET that\r\n // is NOT an API / trace / allure / WebSocket URL and serve index.html so\r\n // React Router can take over on the client side.\r\n fastify.setNotFoundHandler(async (req, reply) => {\r\n const { url, method } = req;\r\n\r\n // Per-run Allure report: /allure/<runId>\r\n if (method === 'GET' && url.startsWith('/allure/')) {\r\n const runId = url.slice('/allure/'.length).replace(/\\/$/, '').split('/')[0];\r\n if (runId) {\r\n const reportFile = path.join(rootDir, 'results', 'allure-report', runId, 'index.html');\r\n if (await fs.pathExists(reportFile)) {\r\n const html = await fs.readFile(reportFile, 'utf-8');\r\n return reply.code(200).type('text/html').send(html);\r\n }\r\n }\r\n // Report not generated yet — show friendly instructions page\r\n return reply.code(200).type('text/html').send(`<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head><meta charset=\"UTF-8\"><title>Allure Report — Not Generated</title>\r\n<style>\r\n body { font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f8fafc; color: #334155; }\r\n .box { text-align: center; max-width: 480px; padding: 2rem; background: white; border-radius: 12px; box-shadow: 0 2px 16px rgba(0,0,0,.08); }\r\n h1 { font-size: 1.25rem; margin-bottom: .5rem; }\r\n p { font-size: .9rem; color: #64748b; line-height: 1.6; }\r\n code { background: #f1f5f9; padding: .15em .4em; border-radius: 4px; font-size: .85em; }\r\n .steps { text-align: left; margin-top: 1rem; }\r\n .steps li { margin-bottom: .4rem; font-size: .875rem; color: #475569; }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"box\">\r\n <h1>Allure Report Not Yet Generated</h1>\r\n <p>The Allure HTML report is produced automatically after each test run. To see it here:</p>\r\n <ol class=\"steps\">\r\n <li>Make sure <strong>Allure report</strong> is enabled in <strong>Settings → Reporting</strong></li>\r\n <li>Make sure <strong>Java</strong> is installed — Allure needs the JVM (<a href=\"https://adoptium.net\" target=\"_blank\">adoptium.net</a>)</li>\r\n <li>Run a test suite from the <strong>Run Config</strong> or <strong>Test Suites</strong> page</li>\r\n <li>Come back to <strong>Reports</strong> and click the chart icon on the run row</li>\r\n </ol>\r\n <p style=\"margin-top:1.2rem;font-size:.8rem;color:#94a3b8\">Report directory: <code>results/allure-report/<runId>/</code></p>\r\n</div>\r\n</body>\r\n</html>`);\r\n }\r\n\r\n const isClientRoute =\r\n method === 'GET' &&\r\n !url.startsWith('/api/') &&\r\n !url.startsWith('/trace/') &&\r\n url !== '/ws';\r\n\r\n if (isClientRoute) {\r\n return reply.sendFile('index.html');\r\n }\r\n\r\n return reply.code(404).send({\r\n message: `Route ${method}:${url} not found`,\r\n error: 'Not Found',\r\n statusCode: 404,\r\n });\r\n });\r\n } else {\r\n logger.warn({ uiDist }, 'UI not built — serving placeholder. Run \"npm run build:ui\" first.');\r\n fastify.get('/', (_req, reply) => {\r\n void reply.type('application/json').send({\r\n message: 'Assuremind Studio',\r\n status: 'ui-not-built',\r\n note: 'Run \"npm run build:ui\" to build the React UI, then restart the server.',\r\n });\r\n });\r\n }\r\n}\r\n","/**\r\n * Shared server utilities — error response helpers.\r\n */\r\nimport type { FastifyReply } from 'fastify';\r\nimport { AssuremindError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('server');\r\n\r\n/** Send a structured error response and log it. */\r\nexport function sendError(\r\n reply: FastifyReply,\r\n statusCode: number,\r\n message: string,\r\n err?: unknown,\r\n): ReturnType<FastifyReply['send']> {\r\n const code =\r\n err instanceof AssuremindError\r\n ? err.code\r\n : 'INTERNAL_ERROR';\r\n\r\n const detail =\r\n err instanceof Error ? err.message : err !== undefined ? String(err) : undefined;\r\n\r\n if (statusCode >= 500) {\r\n logger.error({ err }, message);\r\n } else {\r\n logger.debug({ err }, message);\r\n }\r\n\r\n return reply.status(statusCode).send({\r\n error: message,\r\n ...(detail && detail !== message && { detail }),\r\n code,\r\n });\r\n}\r\n","/**\r\n * Config routes — read and update autotest.config.json.\r\n *\r\n * GET /api/config — return current config\r\n * PUT /api/config — update config (partial patch supported)\r\n */\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { readConfig, writeConfig } from '../../storage/config-store.js';\r\nimport { AutotestConfigSchema } from '../../types/config.js';\r\nimport { validateEnv } from '../../utils/env.js';\r\nimport { sendError } from '../utils.js';\r\n\r\nconst PatchConfigSchema = AutotestConfigSchema.partial();\r\n\r\nexport async function configRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir: string = fastify.rootDir;\r\n\r\n // GET /api/config\r\n fastify.get('/config', async (_req, reply) => {\r\n try {\r\n const config = await readConfig(rootDir);\r\n return reply.send(config);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to read config', err);\r\n }\r\n });\r\n\r\n // PUT /api/config\r\n fastify.put('/config', async (req, reply) => {\r\n const parsed = PatchConfigSchema.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid config', details: parsed.error.issues });\r\n }\r\n\r\n try {\r\n const current = await readConfig(rootDir);\r\n const updated = AutotestConfigSchema.parse({ ...current, ...parsed.data });\r\n await writeConfig(rootDir, updated);\r\n return reply.send(updated);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to update config', err);\r\n }\r\n });\r\n\r\n // GET /api/ai-provider — returns the active AI provider name and model\r\n fastify.get('/ai-provider', async (_req, reply) => {\r\n try {\r\n const env = validateEnv();\r\n const provider = String(env.AI_PROVIDER ?? 'unknown');\r\n const modelMap: Record<string, string> = {\r\n anthropic: String(env.ANTHROPIC_MODEL ?? 'claude-sonnet-4-20250514'),\r\n bedrock: String(env.BEDROCK_MODEL ?? 'us.anthropic.claude-sonnet-4-20250514-v1:0'),\r\n openai: String(env.OPENAI_MODEL ?? 'gpt-4o'),\r\n google: String(env.GOOGLE_MODEL ?? 'gemini-2.5-flash'),\r\n 'azure-openai': String(env.AZURE_OPENAI_DEPLOYMENT ?? 'gpt-4o'),\r\n ollama: String(env.OLLAMA_MODEL ?? 'codellama'),\r\n };\r\n return reply.send({ provider, model: modelMap[provider] ?? 'unknown' });\r\n } catch {\r\n return reply.send({ provider: 'unknown', model: 'unknown' });\r\n }\r\n });\r\n}\r\n","import { z } from 'zod';\r\n\r\nexport type Priority = 'critical' | 'high' | 'medium' | 'low';\r\nexport type GenerationStrategy = 'template' | 'cache' | 'batch' | 'fast' | 'primary';\r\n\r\nexport const TestStepSchema = z.object({\r\n id: z.string().min(1),\r\n order: z.number().int().positive(),\r\n instruction: z.string().min(1),\r\n generatedCode: z.string(),\r\n strategy: z.enum(['template', 'cache', 'batch', 'fast', 'primary']),\r\n stepType: z.enum(['ui', 'api', 'mock']).default('ui'),\r\n lastHealed: z.string().nullable(),\r\n timeout: z.number().int().positive().optional(),\r\n retries: z.number().int().min(0).optional(),\r\n mockUrl: z.string().optional(),\r\n mockResponse: z.string().optional(),\r\n mockStatus: z.number().int().optional(),\r\n runAudit: z.boolean().optional(), // Mark this step as a Lighthouse audit checkpoint\r\n});\r\n\r\nexport const DataSourceSchema = z.object({\r\n type: z.enum(['inline', 'json-file', 'csv-file']),\r\n path: z.string().optional(),\r\n data: z.array(z.record(z.string())).optional(),\r\n}).optional();\r\n\r\nconst CaseHookStepSchema = z.object({\r\n id: z.string(),\r\n instruction: z.string(),\r\n generatedCode: z.string().default(''),\r\n order: z.number().int().default(0),\r\n});\r\n\r\nconst CaseHooksSchema = z.object({\r\n before: z.array(CaseHookStepSchema).default([]),\r\n after: z.array(CaseHookStepSchema).default([]),\r\n}).default({ before: [], after: [] });\r\n\r\nexport type CaseHookStep = z.infer<typeof CaseHookStepSchema>;\r\nexport type CaseHooks = z.infer<typeof CaseHooksSchema>;\r\n\r\nexport const TestCaseSchema = z.object({\r\n id: z.string().min(1),\r\n name: z.string().min(1),\r\n description: z.string(),\r\n tags: z.array(z.string()),\r\n priority: z.enum(['critical', 'high', 'medium', 'low']),\r\n timeout: z.number().int().positive().optional(),\r\n dataSource: DataSourceSchema,\r\n steps: z.array(TestStepSchema),\r\n caseHooks: CaseHooksSchema,\r\n lighthouseCategories: z.array(z.enum(['performance', 'accessibility', 'seo']))\r\n .default(['performance', 'accessibility', 'seo']),\r\n createdAt: z.string().datetime(),\r\n updatedAt: z.string().datetime(),\r\n});\r\n\r\nexport type SuiteType = 'ui' | 'api' | 'audit' | 'performance';\r\n\r\nexport const TestSuiteSchema = z.object({\r\n id: z.string().min(1),\r\n name: z.string().min(1),\r\n description: z.string(),\r\n tags: z.array(z.string()),\r\n type: z.enum(['ui', 'api', 'audit', 'performance']).default('ui'),\r\n timeout: z.number().int().positive().optional(),\r\n createdAt: z.string().datetime(),\r\n updatedAt: z.string().datetime(),\r\n});\r\n\r\n// ─── Suite Hooks (before_all / before_each / after_each / after_all) ─────────\r\n\r\nexport const HookTypeEnum = z.enum(['before_all', 'before_each', 'after_each', 'after_all']);\r\nexport type HookType = z.infer<typeof HookTypeEnum>;\r\n\r\nexport const SuiteHooksSchema = z.object({\r\n before_all: z.array(TestStepSchema).default([]),\r\n before_each: z.array(TestStepSchema).default([]),\r\n after_each: z.array(TestStepSchema).default([]),\r\n after_all: z.array(TestStepSchema).default([]),\r\n});\r\n\r\nexport type TestStep = z.infer<typeof TestStepSchema>;\r\nexport type TestCase = z.infer<typeof TestCaseSchema>;\r\nexport type TestSuite = z.infer<typeof TestSuiteSchema>;\r\nexport type SuiteHooks = z.infer<typeof SuiteHooksSchema>;\r\n","import { ValidationError } from './errors.js';\r\n\r\n/**\r\n * Strips markdown code fences from AI-generated code responses.\r\n * Handles ```typescript, ```ts, ```javascript, ```js, and plain ``` blocks.\r\n */\r\nexport function stripCodeFences(raw: string): string {\r\n const fencePattern = /^```(?:typescript|javascript|ts|js)?\\n?([\\s\\S]*?)```\\s*$/m;\r\n const match = raw.match(fencePattern);\r\n if (match?.[1] !== undefined) {\r\n return match[1].trim();\r\n }\r\n return raw.trim();\r\n}\r\n\r\n/**\r\n * Robustly extracts the first complete JSON object `{...}` or array `[...]`\r\n * from an AI response that may have preamble text, markdown fences, or\r\n * trailing explanation. Works even when models ignore \"return only JSON\" instructions.\r\n *\r\n * Returns the extracted JSON string, or the original input if no block is found.\r\n */\r\nexport function extractJsonBlock(raw: string): string {\r\n // First try stripping code fences\r\n const stripped = stripCodeFences(raw);\r\n\r\n // If already valid JSON, return as-is\r\n try { JSON.parse(stripped); return stripped; } catch { /* continue */ }\r\n\r\n // Find the first '{' or '[' and extract the matching closing bracket\r\n const firstObj = stripped.indexOf('{');\r\n const firstArr = stripped.indexOf('[');\r\n const start = firstObj === -1 ? firstArr\r\n : firstArr === -1 ? firstObj\r\n : Math.min(firstObj, firstArr);\r\n\r\n if (start === -1) return stripped;\r\n\r\n const opener = stripped[start];\r\n const closer = opener === '{' ? '}' : ']';\r\n let depth = 0;\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (let i = start; i < stripped.length; i++) {\r\n const ch = stripped[i];\r\n if (escape) { escape = false; continue; }\r\n if (ch === '\\\\' && inString) { escape = true; continue; }\r\n if (ch === '\"') { inString = !inString; continue; }\r\n if (inString) continue;\r\n if (ch === opener) depth++;\r\n else if (ch === closer) {\r\n depth--;\r\n if (depth === 0) return stripped.slice(start, i + 1);\r\n }\r\n }\r\n\r\n // Didn't find matching close — return from start to end (truncated, let repair handle it)\r\n return stripped.slice(start);\r\n}\r\n\r\n/**\r\n * Forbidden globals that must not appear in generated code.\r\n * Generated code runs inside `new Function('page', 'context', 'expect', code)`,\r\n * so only page, context, and expect are available anyway — but we validate\r\n * defensively to catch prompt-injection attempts.\r\n */\r\nconst FORBIDDEN_PATTERNS: ReadonlyArray<RegExp> = [\r\n /\\brequire\\s*\\(/,\r\n /\\bimport\\s*\\(/,\r\n /\\bprocess\\b/,\r\n /\\bchild_process\\b/,\r\n /\\bexec\\s*\\(/,\r\n /\\bspawn\\s*\\(/,\r\n /\\beval\\s*\\(/,\r\n /\\bFunction\\s*\\(/,\r\n /\\b__dirname\\b/,\r\n /\\b__filename\\b/,\r\n /\\bglobal\\b/,\r\n /\\bwindow\\.location\\.href\\s*=/,\r\n /\\bdocument\\.cookie\\b/,\r\n /\\blocalStorage\\b/,\r\n /\\bsessionStorage\\b/,\r\n /\\bIndexedDB\\b/,\r\n /\\bXMLHttpRequest\\b/,\r\n /\\bfetch\\s*\\(/,\r\n /\\bWebSocket\\s*\\(/,\r\n];\r\n\r\n/**\r\n * Validates that generated code is safe to execute.\r\n * Throws a ValidationError if forbidden patterns are detected.\r\n */\r\nexport function validateGeneratedCode(code: string): void {\r\n for (const pattern of FORBIDDEN_PATTERNS) {\r\n if (pattern.test(code)) {\r\n throw new ValidationError(\r\n `Generated code contains forbidden pattern: ${pattern.source}. ` +\r\n `This may be a prompt injection attempt. Please regenerate the step.`,\r\n 'generatedCode',\r\n 'UNSAFE_CODE',\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Removes known Playwright anti-patterns from any generated code.\r\n * Exported so smart-router can apply it to template + cache hits too.\r\n *\r\n * Patterns removed:\r\n * 1. `.or(locator).first()` / `.or(locator).last()` / `.or(locator)`\r\n * AI models often chain .or() when unsure; we always prefer a single locator.\r\n * Handles one level of nested parens which covers all getBy* calls.\r\n *\r\n * 2. Standalone `.first()` / `.last()` after any locator (not method chaining)\r\n * e.g. page.getByRole('button', { name: '...' }).first().click()\r\n * → page.getByRole('button', { name: '...' }).click()\r\n */\r\n/**\r\n * Post-processes AI-generated code to fix incorrect selector choices.\r\n *\r\n * Rule: if the instruction says \"...button...\" and the code uses\r\n * page.getByText('X').click() or page.getByText(\"X\").click()\r\n * rewrite to:\r\n * page.getByRole('button', { name: 'X' }).click()\r\n *\r\n * This is a deterministic fallback for when the AI ignores prompt rules.\r\n */\r\nexport function fixButtonSelectors(instruction: string, code: string): string {\r\n const mentionsButton = /\\bbutton\\b/i.test(instruction);\r\n if (!mentionsButton) return code;\r\n\r\n // Match getByText('Name') or getByText(\"Name\") followed by .click()\r\n return code.replace(\r\n /page\\.getByText\\((['\"])(.*?)\\1\\)\\.click\\(\\)/g,\r\n (_match, _q, name: string) => `page.getByRole('button', { name: '${name}' }).click()`,\r\n );\r\n}\r\n\r\nexport function fixAntiPatterns(code: string): string {\r\n let result = code;\r\n\r\n // Remove .or(anyLocator) chains (with optional trailing .first()/.last())\r\n // Regex handles one level of nested parens: covers page.getByRole('btn', { name: 'x' })\r\n result = result.replace(\r\n /\\.or\\((?:[^()]*|\\([^()]*\\))*\\)(?:\\.(?:first|last)\\(\\))?/g,\r\n '',\r\n );\r\n\r\n // Remove leftover .first() / .last() that directly precede .click()/.fill()/etc.\r\n // i.e. locator.first().click() → locator.click()\r\n result = result.replace(/\\.(?:first|last)\\(\\)(?=\\.\\w)/g, '');\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Sanitizes AI-generated code: strips fences, removes anti-patterns,\r\n * trims whitespace, and validates against forbidden patterns.\r\n */\r\nexport function sanitizeGeneratedCode(raw: string): string {\r\n const stripped = stripCodeFences(raw);\r\n\r\n if (!stripped) {\r\n throw new ValidationError(\r\n 'AI returned an empty code response. Please try regenerating.',\r\n 'generatedCode',\r\n 'EMPTY_CODE',\r\n );\r\n }\r\n\r\n const fixed = fixAntiPatterns(stripped);\r\n validateGeneratedCode(fixed);\r\n return fixed;\r\n}\r\n\r\n/**\r\n * Sanitizes a string for safe use as a filename component.\r\n * Replaces whitespace and special chars with hyphens, lowercases.\r\n */\r\nexport function toSlug(input: string): string {\r\n return input\r\n .toLowerCase()\r\n .trim()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/^-+|-+$/g, '');\r\n}\r\n\r\n/**\r\n * Redacts secret variable values from a string so they never appear in logs.\r\n */\r\nexport function redactSecrets(\r\n text: string,\r\n secrets: ReadonlyArray<string>,\r\n): string {\r\n let result = text;\r\n for (const secret of secrets) {\r\n if (secret.length > 0) {\r\n result = result.replaceAll(secret, '[REDACTED]');\r\n }\r\n }\r\n return result;\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { TestSuite, TestSuiteSchema, type SuiteType } from '../types/suite.js';\r\nimport { StorageError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { toSlug } from '../utils/sanitize.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('suite-store');\r\n\r\nconst SUITE_FILE = 'suite.json';\r\n\r\n/**\r\n * Reads a suite.json from the given suite directory.\r\n */\r\nexport async function readSuite(suiteDir: string): Promise<TestSuite> {\r\n const filePath = path.join(suiteDir, SUITE_FILE);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new StorageError(\r\n `Suite file not found at \"${filePath}\". ` +\r\n `Ensure the suite directory exists and contains a suite.json file.`,\r\n filePath,\r\n 'SUITE_NOT_FOUND',\r\n );\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = TestSuiteSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n const issues = result.error.issues.map((i) => ` • ${i.path.join('.')}: ${i.message}`).join('\\n');\r\n throw new ValidationError(\r\n `Invalid suite.json at \"${filePath}\":\\n${issues}`,\r\n 'suite',\r\n 'INVALID_SUITE',\r\n );\r\n }\r\n\r\n // Infer type from folder path if not explicitly set in suite.json\r\n // (Zod .default('ui') always fills the value, so check the raw JSON instead)\r\n const rawObj = raw as Record<string, unknown>;\r\n if (!rawObj.type) {\r\n const parentDir = path.basename(path.dirname(suiteDir));\r\n if (parentDir === 'api') result.data.type = 'api';\r\n else if (parentDir === 'audit') result.data.type = 'audit';\r\n else if (parentDir === 'performance') result.data.type = 'audit'; // backward compat: performance dir → audit type\r\n else result.data.type = 'ui';\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes a suite.json atomically to the given suite directory.\r\n */\r\nexport async function writeSuite(suiteDir: string, suite: TestSuite): Promise<void> {\r\n await fs.ensureDir(suiteDir);\r\n const filePath = path.join(suiteDir, SUITE_FILE);\r\n\r\n const result = TestSuiteSchema.safeParse(suite);\r\n if (!result.success) {\r\n const issues = result.error.issues.map((i) => ` • ${i.path.join('.')}: ${i.message}`).join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid suite to \"${filePath}\":\\n${issues}`,\r\n 'suite',\r\n 'INVALID_SUITE',\r\n );\r\n }\r\n\r\n await atomicWriteJson(filePath, result.data);\r\n logger.debug({ suiteId: suite.id, path: filePath }, 'Suite written');\r\n}\r\n\r\n/**\r\n * Creates a new suite directory and writes its suite.json.\r\n * Returns both the directory path and the generated suite ID.\r\n */\r\nexport async function createSuite(\r\n testsDir: string,\r\n suite: Omit<TestSuite, 'id' | 'createdAt' | 'updatedAt'>,\r\n): Promise<{ suiteDir: string; suiteId: string }> {\r\n const now = new Date().toISOString();\r\n const suiteType: SuiteType = suite.type ?? 'ui';\r\n const newSuite: TestSuite = {\r\n ...suite,\r\n type: suiteType,\r\n id: uuidv4(),\r\n createdAt: now,\r\n updatedAt: now,\r\n };\r\n\r\n const targetDir = path.join(testsDir, suiteType);\r\n const suiteDir = path.join(targetDir, toSlug(newSuite.name));\r\n if (await fs.pathExists(path.join(suiteDir, SUITE_FILE))) {\r\n throw new StorageError(\r\n `Suite directory already exists at \"${suiteDir}\". ` +\r\n `Choose a different name or delete the existing suite first.`,\r\n suiteDir,\r\n 'SUITE_ALREADY_EXISTS',\r\n );\r\n }\r\n\r\n await writeSuite(suiteDir, newSuite);\r\n logger.info({ suiteId: newSuite.id, path: suiteDir }, 'Suite created');\r\n return { suiteDir, suiteId: newSuite.id };\r\n}\r\n\r\n/**\r\n * Updates an existing suite (merges partial fields, updates updatedAt).\r\n */\r\nexport async function updateSuite(\r\n suiteDir: string,\r\n updates: Partial<Omit<TestSuite, 'id' | 'createdAt'>>,\r\n): Promise<TestSuite> {\r\n const existing = await readSuite(suiteDir);\r\n const updated: TestSuite = {\r\n ...existing,\r\n ...updates,\r\n id: existing.id,\r\n createdAt: existing.createdAt,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n await writeSuite(suiteDir, updated);\r\n return updated;\r\n}\r\n\r\n/**\r\n * Deletes a suite directory and all its contents.\r\n */\r\nexport async function deleteSuite(suiteDir: string): Promise<void> {\r\n if (!(await fs.pathExists(suiteDir))) {\r\n throw new StorageError(\r\n `Suite directory not found at \"${suiteDir}\".`,\r\n suiteDir,\r\n 'SUITE_NOT_FOUND',\r\n );\r\n }\r\n await fs.remove(suiteDir);\r\n logger.info({ path: suiteDir }, 'Suite deleted');\r\n}\r\n\r\n/**\r\n * Lists all suite directories under testsDir.\r\n * Scans: testsDir/ui/, testsDir/api/, testsDir/performance/, and testsDir/ (legacy root).\r\n */\r\nexport async function listSuiteDirs(testsDir: string): Promise<string[]> {\r\n const suiteDirs: string[] = [];\r\n const searchDirs = [\r\n path.join(testsDir, 'ui'),\r\n path.join(testsDir, 'api'),\r\n path.join(testsDir, 'audit'),\r\n path.join(testsDir, 'performance'), // legacy: keep scanning for backward compat\r\n testsDir, // legacy: suites at root level\r\n ];\r\n\r\n for (const baseDir of searchDirs) {\r\n if (!(await fs.pathExists(baseDir))) continue;\r\n const entries = await fs.readdir(baseDir, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n // Skip the ui/, api/, and performance/ subdirs themselves when scanning root\r\n if (baseDir === testsDir && (entry.name === 'ui' || entry.name === 'api' || entry.name === 'audit' || entry.name === 'performance')) continue;\r\n const suiteFile = path.join(baseDir, entry.name, SUITE_FILE);\r\n if (await fs.pathExists(suiteFile)) {\r\n suiteDirs.push(path.join(baseDir, entry.name));\r\n }\r\n }\r\n }\r\n\r\n return suiteDirs;\r\n}\r\n\r\n/**\r\n * Moves a suite between ui/ and api/ folders when type changes.\r\n */\r\nexport async function moveSuiteType(\r\n testsDir: string,\r\n suiteDir: string,\r\n newType: SuiteType,\r\n): Promise<string> {\r\n const suite = await readSuite(suiteDir);\r\n const suiteDirName = path.basename(suiteDir);\r\n const newParent = path.join(testsDir, newType);\r\n const newSuiteDir = path.join(newParent, suiteDirName);\r\n\r\n if (suiteDir === newSuiteDir) return suiteDir; // already in correct folder\r\n\r\n await fs.ensureDir(newParent);\r\n if (await fs.pathExists(newSuiteDir)) {\r\n throw new StorageError(\r\n `Cannot move suite — \"${newSuiteDir}\" already exists.`,\r\n newSuiteDir,\r\n 'SUITE_ALREADY_EXISTS',\r\n );\r\n }\r\n\r\n await fs.move(suiteDir, newSuiteDir);\r\n // Update type in suite.json\r\n await updateSuite(newSuiteDir, { type: newType });\r\n logger.info({ suiteId: suite.id, from: suiteDir, to: newSuiteDir }, 'Suite moved');\r\n return newSuiteDir;\r\n}\r\n\r\n/**\r\n * Finds the suite directory for a given suite UUID.\r\n * Scans all suite dirs and returns the one whose suite.json has the matching id.\r\n * Returns null if not found.\r\n */\r\nexport async function findSuiteDirById(testsDir: string, id: string): Promise<string | null> {\r\n const dirs = await listSuiteDirs(testsDir);\r\n for (const dir of dirs) {\r\n try {\r\n const suite = await readSuite(dir);\r\n if (suite.id === id) return dir;\r\n } catch {\r\n // skip malformed suites\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Reads all suites from testsDir.\r\n */\r\nexport async function listSuites(testsDir: string): Promise<TestSuite[]> {\r\n const dirs = await listSuiteDirs(testsDir);\r\n const suites: TestSuite[] = [];\r\n\r\n for (const dir of dirs) {\r\n try {\r\n suites.push(await readSuite(dir));\r\n } catch (err) {\r\n logger.warn({ path: dir, err }, 'Failed to read suite — skipping');\r\n }\r\n }\r\n\r\n return suites;\r\n}\r\n\r\n/**\r\n * Reads all suites with their case counts (lightweight — counts files, doesn't parse).\r\n */\r\nexport async function listSuitesWithCounts(testsDir: string): Promise<(TestSuite & { caseCount: number })[]> {\r\n const dirs = await listSuiteDirs(testsDir);\r\n const suites: (TestSuite & { caseCount: number })[] = [];\r\n\r\n for (const dir of dirs) {\r\n try {\r\n const suite = await readSuite(dir);\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n const caseCount = entries.filter((e) => e.isFile() && e.name.endsWith('.test.json')).length;\r\n suites.push({ ...suite, caseCount });\r\n } catch (err) {\r\n logger.warn({ path: dir, err }, 'Failed to read suite — skipping');\r\n }\r\n }\r\n\r\n return suites;\r\n}\r\n","/**\r\n * Suite routes — CRUD for test suites.\r\n *\r\n * GET /api/suites — list all suites\r\n * POST /api/suites — create suite\r\n * GET /api/suites/:id — get suite by id\r\n * PATCH /api/suites/:id — update suite metadata\r\n * DELETE /api/suites/:id — delete suite\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport {\r\n listSuitesWithCounts,\r\n readSuite,\r\n createSuite,\r\n updateSuite,\r\n deleteSuite,\r\n findSuiteDirById,\r\n moveSuiteType,\r\n} from '../../storage/suite-store.js';\r\nimport { sendError } from '../utils.js';\r\n\r\nconst CreateSuiteBody = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n type: z.enum(['ui', 'api', 'audit', 'performance']).default('ui'),\r\n});\r\n\r\nconst UpdateSuiteBody = z.object({\r\n name: z.string().min(1).optional(),\r\n description: z.string().optional(),\r\n tags: z.array(z.string()).optional(),\r\n timeout: z.number().int().positive().optional(),\r\n type: z.enum(['ui', 'api', 'audit', 'performance']).optional(),\r\n});\r\n\r\nexport async function suiteRoutes(fastify: FastifyInstance): Promise<void> {\r\n const testsDir = path.join(fastify.rootDir, 'tests');\r\n\r\n // GET /api/suites?type=ui|api\r\n fastify.get<{ Querystring: { type?: string } }>('/suites', async (req, reply) => {\r\n try {\r\n let suites = await listSuitesWithCounts(testsDir);\r\n const typeFilter = req.query.type;\r\n if (typeFilter === 'ui' || typeFilter === 'api' || typeFilter === 'performance') {\r\n suites = suites.filter((s) => s.type === typeFilter);\r\n }\r\n return reply.send(suites);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to list suites', err);\r\n }\r\n });\r\n\r\n // POST /api/suites\r\n fastify.post('/suites', async (req, reply) => {\r\n const parsed = CreateSuiteBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid suite data', details: parsed.error.issues });\r\n }\r\n try {\r\n const { suiteDir } = await createSuite(testsDir, parsed.data);\r\n const suite = await readSuite(suiteDir);\r\n return reply.status(201).send(suite);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to create suite', err);\r\n }\r\n });\r\n\r\n // GET /api/suites/:id\r\n fastify.get<{ Params: { id: string } }>('/suites/:id', async (req, reply) => {\r\n try {\r\n const suiteDir = await findSuiteDirById(testsDir, req.params.id);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.id}\" not found` });\r\n const suite = await readSuite(suiteDir);\r\n return reply.send(suite);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get suite', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:id\r\n fastify.patch<{ Params: { id: string } }>('/suites/:id', async (req, reply) => {\r\n const parsed = UpdateSuiteBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid suite data', details: parsed.error.issues });\r\n }\r\n try {\r\n let suiteDir = await findSuiteDirById(testsDir, req.params.id);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.id}\" not found` });\r\n\r\n // If type changed, move suite to the new folder first\r\n if (parsed.data.type) {\r\n const currentSuite = await readSuite(suiteDir);\r\n if (currentSuite.type !== parsed.data.type) {\r\n suiteDir = await moveSuiteType(testsDir, suiteDir, parsed.data.type);\r\n }\r\n }\r\n\r\n const suite = await updateSuite(suiteDir, parsed.data);\r\n return reply.send(suite);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to update suite', err);\r\n }\r\n });\r\n\r\n // DELETE /api/suites/:id\r\n fastify.delete<{ Params: { id: string } }>('/suites/:id', async (req, reply) => {\r\n try {\r\n const suiteDir = await findSuiteDirById(testsDir, req.params.id);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.id}\" not found` });\r\n await deleteSuite(suiteDir);\r\n return reply.status(204).send();\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete suite', err);\r\n }\r\n });\r\n}\r\n","/**\n * Auto-detects whether a test step instruction is UI or API based on keywords.\n */\nconst API_PATTERNS = [\n /\\b(GET|POST|PUT|DELETE|PATCH)\\s+\\//i,\n /\\bsend\\s+(a\\s+)?(GET|POST|PUT|DELETE|PATCH)\\b/i,\n /\\b(api|rest|http|graphql)\\s+(call|request|endpoint)/i,\n /\\bresponse\\s+(status|body|code|header|time|structure|bodies|fields)/i,\n /\\bstatus\\s+code/i,\n /\\brequest\\s+(to|with|body|header)/i,\n /\\bextract\\s+.*\\bfrom\\s+response\\b/i,\n /\\bauthenticate\\s+via\\s+(api|token)\\b/i,\n /\\bfetch\\s+.*\\bfrom\\s+api\\b/i,\n /\\bverify\\s+(the\\s+)?(response|api|endpoint|status)/i,\n /\\b\\/api\\//i,\n /\\brequest\\s+body\\b/i,\n /\\b(response|request)\\s+(body|code|header)/i,\n /\\b(store|save|extract)\\s+(the\\s+)?(full\\s+)?(response|request|body|token|header)/i,\n /\\berror\\s+(fields?|messages?)\\s+.*\\bresponse/i,\n /\\bresponse\\s+.*\\b(error|fields?|messages?|bodies|keys|data\\s+types?)/i,\n /\\b(three|two|all|multiple)\\s+(response|request)/i,\n /\\bscoped.?token\\b/i,\n /\\boauth\\b/i,\n /\\baccess.?token\\b/i,\n /\\b(bearer|authorization)\\s+token\\b/i,\n /\\bjson\\s+(response|body|payload)\\b/i,\n /\\bhttp\\s+\\d{3}\\b/i,\n /\\bpayload\\b/i,\n];\n\nexport function detectStepType(instruction: string): 'ui' | 'api' {\n return API_PATTERNS.some((p) => p.test(instruction)) ? 'api' : 'ui';\n}\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport { TestCase, TestCaseSchema } from '../types/suite.js';\r\nimport { StorageError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { toSlug } from '../utils/sanitize.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('case-store');\r\n\r\nconst CASE_EXTENSION = '.test.json';\r\n\r\n/**\r\n * Reads a .test.json file from the given path.\r\n */\r\nexport async function readCase(casePath: string): Promise<TestCase> {\r\n if (!(await fs.pathExists(casePath))) {\r\n throw new StorageError(\r\n `Test case file not found at \"${casePath}\".`,\r\n casePath,\r\n 'CASE_NOT_FOUND',\r\n );\r\n }\r\n\r\n const raw = await readJson(casePath);\r\n const result = TestCaseSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Invalid test case file at \"${casePath}\":\\n${issues}`,\r\n 'case',\r\n 'INVALID_CASE',\r\n );\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes a TestCase atomically to the given path.\r\n */\r\nexport async function writeCase(casePath: string, testCase: TestCase): Promise<void> {\r\n const result = TestCaseSchema.safeParse(testCase);\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid test case to \"${casePath}\":\\n${issues}`,\r\n 'case',\r\n 'INVALID_CASE',\r\n );\r\n }\r\n\r\n await atomicWriteJson(casePath, result.data);\r\n logger.debug({ caseId: testCase.id, path: casePath }, 'Test case written');\r\n}\r\n\r\n/**\r\n * Creates a new .test.json file in the given suite directory.\r\n * Returns the path to the created file.\r\n */\r\nexport async function createCase(\r\n suiteDir: string,\r\n testCase: Omit<TestCase, 'id' | 'createdAt' | 'updatedAt'>,\r\n): Promise<string> {\r\n const now = new Date().toISOString();\r\n const newCase: TestCase = {\r\n ...testCase,\r\n id: uuidv4(),\r\n createdAt: now,\r\n updatedAt: now,\r\n };\r\n\r\n const casePath = path.join(suiteDir, `${toSlug(newCase.name)}${CASE_EXTENSION}`);\r\n await writeCase(casePath, newCase);\r\n logger.info({ caseId: newCase.id, path: casePath }, 'Test case created');\r\n return casePath;\r\n}\r\n\r\n/**\r\n * Updates an existing test case (merges partial fields, bumps updatedAt).\r\n */\r\nexport async function updateCase(\r\n casePath: string,\r\n updates: Partial<Omit<TestCase, 'id' | 'createdAt'>>,\r\n): Promise<TestCase> {\r\n const existing = await readCase(casePath);\r\n const updated: TestCase = {\r\n ...existing,\r\n ...updates,\r\n id: existing.id,\r\n createdAt: existing.createdAt,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n await writeCase(casePath, updated);\r\n return updated;\r\n}\r\n\r\n/**\r\n * Deletes a .test.json file.\r\n */\r\nexport async function deleteCase(casePath: string): Promise<void> {\r\n if (!(await fs.pathExists(casePath))) {\r\n throw new StorageError(\r\n `Test case file not found at \"${casePath}\".`,\r\n casePath,\r\n 'CASE_NOT_FOUND',\r\n );\r\n }\r\n await fs.remove(casePath);\r\n logger.info({ path: casePath }, 'Test case deleted');\r\n}\r\n\r\n/**\r\n * Lists all .test.json file paths within a suite directory.\r\n */\r\nexport async function listCasePaths(suiteDir: string): Promise<string[]> {\r\n if (!(await fs.pathExists(suiteDir))) return [];\r\n\r\n const entries = await fs.readdir(suiteDir, { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isFile() && e.name.endsWith(CASE_EXTENSION))\r\n .map((e) => path.join(suiteDir, e.name));\r\n}\r\n\r\n/**\r\n * Reads all test cases from a suite directory.\r\n */\r\nexport async function listCases(suiteDir: string): Promise<TestCase[]> {\r\n const paths = await listCasePaths(suiteDir);\r\n const cases: TestCase[] = [];\r\n\r\n for (const casePath of paths) {\r\n try {\r\n cases.push(await readCase(casePath));\r\n } catch (err) {\r\n logger.warn({ path: casePath, err }, 'Failed to read test case — skipping');\r\n }\r\n }\r\n\r\n return cases.sort((a, b) => a.name.localeCompare(b.name));\r\n}\r\n\r\n/**\r\n * Returns the .test.json path for a case given its suite directory and case name.\r\n */\r\nexport function getCasePath(suiteDir: string, caseName: string): string {\r\n return path.join(suiteDir, `${toSlug(caseName)}${CASE_EXTENSION}`);\r\n}\r\n\r\n/**\r\n * Finds the .test.json file path for a case by its UUID.\r\n * Scans all case files in suiteDir and returns the path whose id matches.\r\n * Returns null if not found.\r\n */\r\nexport async function findCasePathById(suiteDir: string, id: string): Promise<string | null> {\r\n const paths = await listCasePaths(suiteDir);\r\n for (const casePath of paths) {\r\n try {\r\n const tc = await readCase(casePath);\r\n if (tc.id === id) return casePath;\r\n } catch {\r\n // skip malformed files\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Case routes — CRUD for test cases within a suite.\r\n *\r\n * GET /api/suites/:suiteId/cases — list cases\r\n * POST /api/suites/:suiteId/cases — create case\r\n * GET /api/suites/:suiteId/cases/:caseId — get case\r\n * PATCH /api/suites/:suiteId/cases/:caseId — update case\r\n * DELETE /api/suites/:suiteId/cases/:caseId — delete case\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { detectStepType } from '../../engine/step-type-detector.js';\r\nimport {\r\n listCases,\r\n readCase,\r\n createCase,\r\n updateCase,\r\n deleteCase,\r\n findCasePathById,\r\n} from '../../storage/case-store.js';\r\nimport { findSuiteDirById } from '../../storage/suite-store.js';\r\nimport { sendError } from '../utils.js';\r\n\r\nconst CreateCaseBody = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n priority: z.enum(['critical', 'high', 'medium', 'low']).default('medium'),\r\n steps: z.array(z.object({\r\n instruction: z.string().min(1),\r\n })).default([]),\r\n});\r\n\r\nconst DataSourceBody = z.object({\r\n type: z.enum(['inline', 'json-file', 'csv-file']),\r\n path: z.string().optional(),\r\n data: z.array(z.record(z.string())).optional(),\r\n}).optional().nullable();\r\n\r\nconst UpdateCaseBody = z.object({\r\n name: z.string().min(1).optional(),\r\n description: z.string().optional(),\r\n tags: z.array(z.string()).optional(),\r\n priority: z.enum(['critical', 'high', 'medium', 'low']).optional(),\r\n timeout: z.number().int().positive().optional(),\r\n dataSource: DataSourceBody,\r\n lighthouseCategories: z.array(z.enum(['performance', 'accessibility', 'seo'])).optional(),\r\n});\r\n\r\ntype SuiteParams = { suiteId: string };\r\ntype CaseParams = { suiteId: string; caseId: string };\r\n\r\nconst BulkDeleteBody = z.object({ ids: z.array(z.string().min(1)).min(1) });\r\nconst BulkMoveBody = z.object({ ids: z.array(z.string().min(1)).min(1), targetSuiteId: z.string().min(1) });\r\n\r\nexport async function caseRoutes(fastify: FastifyInstance): Promise<void> {\r\n const testsDir = path.join(fastify.rootDir, 'tests');\r\n\r\n // Helper: resolve suiteId UUID → actual directory path\r\n async function resolveSuiteDir(suiteId: string): Promise<string | null> {\r\n return findSuiteDirById(testsDir, suiteId);\r\n }\r\n\r\n // POST /api/suites/:suiteId/cases/bulk-delete\r\n fastify.post<{ Params: { suiteId: string } }>('/suites/:suiteId/cases/bulk-delete', async (req, reply) => {\r\n const parsed = BulkDeleteBody.safeParse(req.body);\r\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid request' });\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n let deleted = 0;\r\n for (const id of parsed.data.ids) {\r\n const casePath = await findCasePathById(suiteDir, id);\r\n if (casePath) { await deleteCase(casePath); deleted++; }\r\n }\r\n return reply.send({ deleted });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to bulk delete cases', err);\r\n }\r\n });\r\n\r\n // POST /api/suites/:suiteId/cases/bulk-move\r\n fastify.post<{ Params: { suiteId: string } }>('/suites/:suiteId/cases/bulk-move', async (req, reply) => {\r\n const parsed = BulkMoveBody.safeParse(req.body);\r\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid request' });\r\n try {\r\n const sourceSuiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!sourceSuiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const targetSuiteDir = await findSuiteDirById(testsDir, parsed.data.targetSuiteId);\r\n if (!targetSuiteDir) return reply.status(404).send({ error: `Target suite \"${parsed.data.targetSuiteId}\" not found` });\r\n let moved = 0;\r\n for (const id of parsed.data.ids) {\r\n const sourcePath = await findCasePathById(sourceSuiteDir, id);\r\n if (sourcePath) {\r\n const caseData = await readCase(sourcePath);\r\n await createCase(targetSuiteDir, caseData);\r\n await deleteCase(sourcePath);\r\n moved++;\r\n }\r\n }\r\n return reply.send({ moved });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to bulk move cases', err);\r\n }\r\n });\r\n\r\n // GET /api/suites/:suiteId/cases\r\n fastify.get<{ Params: SuiteParams }>('/suites/:suiteId/cases', async (req, reply) => {\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const cases = await listCases(suiteDir);\r\n return reply.send(cases);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to list cases', err);\r\n }\r\n });\r\n\r\n // POST /api/suites/:suiteId/cases\r\n fastify.post<{ Params: SuiteParams }>('/suites/:suiteId/cases', async (req, reply) => {\r\n const parsed = CreateCaseBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid case data', details: parsed.error.issues });\r\n }\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const { name, description, tags, priority, steps } = parsed.data;\r\n const casePath = await createCase(suiteDir, {\r\n name,\r\n description,\r\n tags,\r\n priority,\r\n steps: steps.map((s, idx) => ({\r\n id: `step-${idx + 1}`,\r\n order: idx + 1,\r\n instruction: s.instruction,\r\n generatedCode: '',\r\n strategy: 'primary' as const,\r\n stepType: detectStepType(s.instruction),\r\n lastHealed: null,\r\n })),\r\n });\r\n const tc = await readCase(casePath);\r\n return reply.status(201).send(tc);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to create case', err);\r\n }\r\n });\r\n\r\n // GET /api/suites/:suiteId/cases/:caseId\r\n fastify.get<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId', async (req, reply) => {\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const casePath = await findCasePathById(suiteDir, req.params.caseId);\r\n if (!casePath) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(casePath);\r\n return reply.send(tc);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get case', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:suiteId/cases/:caseId\r\n fastify.patch<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId', async (req, reply) => {\r\n const parsed = UpdateCaseBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid case data', details: parsed.error.issues });\r\n }\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const casePath = await findCasePathById(suiteDir, req.params.caseId);\r\n if (!casePath) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await updateCase(casePath, parsed.data);\r\n return reply.send(tc);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to update case', err);\r\n }\r\n });\r\n\r\n // DELETE /api/suites/:suiteId/cases/:caseId\r\n fastify.delete<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId', async (req, reply) => {\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: `Suite \"${req.params.suiteId}\" not found` });\r\n const casePath = await findCasePathById(suiteDir, req.params.caseId);\r\n if (!casePath) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n await deleteCase(casePath);\r\n return reply.status(204).send();\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete case', err);\r\n }\r\n });\r\n}\r\n","import { z } from 'zod';\r\n\r\nexport const SecretVariableSchema = z.object({\r\n value: z.string(),\r\n secret: z.literal(true),\r\n});\r\n\r\nexport const VariableValueSchema = z.union([z.string(), SecretVariableSchema]);\r\n\r\nexport const VariableStoreSchema = z.record(z.string(), VariableValueSchema);\r\n\r\nexport type SecretVariable = z.infer<typeof SecretVariableSchema>;\r\nexport type VariableValue = z.infer<typeof VariableValueSchema>;\r\nexport type VariableStore = z.infer<typeof VariableStoreSchema>;\r\n\r\nexport interface ResolvedVariables {\r\n [key: string]: string;\r\n}\r\n\r\nexport function isSecretVariable(value: VariableValue): value is SecretVariable {\r\n return typeof value === 'object' && value.secret === true;\r\n}\r\n\r\nexport function resolveVariableValue(value: VariableValue): string {\r\n if (isSecretVariable(value)) {\r\n return value.value;\r\n }\r\n return value;\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { VariableStore, VariableStoreSchema, ResolvedVariables, resolveVariableValue } from '../types/variable.js';\r\nimport { StorageError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('variable-store');\r\n\r\nconst VARIABLES_DIR = 'variables';\r\nconst GLOBAL_FILE = 'global.json';\r\n\r\nfunction envFileName(env: string): string {\r\n return `${env}.env.json`;\r\n}\r\n\r\n/**\r\n * Reads a variables JSON file from disk and validates its shape.\r\n */\r\nexport async function readVariables(filePath: string): Promise<VariableStore> {\r\n if (!(await fs.pathExists(filePath))) {\r\n return {};\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = VariableStoreSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Invalid variables file at \"${filePath}\":\\n${issues}`,\r\n 'variables',\r\n 'INVALID_VARIABLES',\r\n );\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes a variables file atomically.\r\n */\r\nexport async function writeVariables(filePath: string, store: VariableStore): Promise<void> {\r\n const result = VariableStoreSchema.safeParse(store);\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid variables to \"${filePath}\":\\n${issues}`,\r\n 'variables',\r\n 'INVALID_VARIABLES',\r\n );\r\n }\r\n await atomicWriteJson(filePath, result.data);\r\n logger.debug({ path: filePath }, 'Variables written');\r\n}\r\n\r\n/**\r\n * Reads the global variables file.\r\n */\r\nexport async function readGlobalVariables(rootDir: string): Promise<VariableStore> {\r\n const filePath = path.join(rootDir, VARIABLES_DIR, GLOBAL_FILE);\r\n return readVariables(filePath);\r\n}\r\n\r\n/**\r\n * Reads environment-specific variables (e.g. dev, staging, prod).\r\n */\r\nexport async function readEnvVariables(rootDir: string, env: string): Promise<VariableStore> {\r\n const filePath = path.join(rootDir, VARIABLES_DIR, envFileName(env));\r\n return readVariables(filePath);\r\n}\r\n\r\n/**\r\n * Merges global + env-specific variables, resolving all values to strings.\r\n * Environment variables override global variables.\r\n * Secrets are resolved to their plain values (never sent to AI — caller must redact).\r\n */\r\nexport async function resolveVariables(rootDir: string, env?: string): Promise<ResolvedVariables> {\r\n const global = await readGlobalVariables(rootDir);\r\n const envSpecific = env ? await readEnvVariables(rootDir, env) : {};\r\n\r\n const merged: VariableStore = { ...global, ...envSpecific };\r\n const resolved: ResolvedVariables = {};\r\n\r\n for (const [key, value] of Object.entries(merged)) {\r\n resolved[key] = resolveVariableValue(value);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\n/**\r\n * Sets a variable in the global variables file.\r\n */\r\nexport async function setGlobalVariable(\r\n rootDir: string,\r\n key: string,\r\n value: VariableStore[string],\r\n): Promise<void> {\r\n const filePath = path.join(rootDir, VARIABLES_DIR, GLOBAL_FILE);\r\n await fs.ensureDir(path.dirname(filePath));\r\n const existing = await readVariables(filePath);\r\n existing[key] = value;\r\n await writeVariables(filePath, existing);\r\n}\r\n\r\n/**\r\n * Deletes a variable from the global variables file.\r\n */\r\nexport async function deleteGlobalVariable(rootDir: string, key: string): Promise<void> {\r\n const filePath = path.join(rootDir, VARIABLES_DIR, GLOBAL_FILE);\r\n const existing = await readVariables(filePath);\r\n if (!(key in existing)) {\r\n throw new StorageError(\r\n `Variable \"${key}\" not found in global variables.`,\r\n filePath,\r\n 'VARIABLE_NOT_FOUND',\r\n );\r\n }\r\n delete existing[key];\r\n await writeVariables(filePath, existing);\r\n}\r\n\r\n/**\r\n * Lists all available variable files (global + env-specific).\r\n */\r\nexport async function listVariableFiles(rootDir: string): Promise<string[]> {\r\n const dir = path.join(rootDir, VARIABLES_DIR);\r\n if (!(await fs.pathExists(dir))) return [];\r\n\r\n const entries = await fs.readdir(dir, { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isFile() && e.name.endsWith('.json'))\r\n .map((e) => path.join(dir, e.name));\r\n}\r\n","/**\r\n * Template Engine — Strategy 1 of the Smart Router.\r\n * Handles ~60% of all test steps with zero AI calls using regex pattern matching.\r\n */\r\n\r\ntype PatternGen = (match: RegExpMatchArray) => string;\r\n\r\ninterface Pattern {\r\n regex: RegExp;\r\n gen: PatternGen;\r\n}\r\n\r\nfunction resolveUrl(text: string): string {\r\n const trimmed = text.trim();\r\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed;\r\n if (trimmed.startsWith('/')) return `{{BASE_URL}}${trimmed}`;\r\n if (/^[\\w-]+\\.[\\w.-]+/.test(trimmed)) return `https://${trimmed}`;\r\n return trimmed;\r\n}\r\n\r\nconst PATTERNS: ReadonlyArray<Pattern> = [\r\n // ── Navigation ──\r\n {\r\n regex: /^(?:go to|navigate to|open|visit)\\s+(.+)$/i,\r\n gen: (m) => `await page.goto('${resolveUrl(m[1] ?? '')}');`,\r\n },\r\n {\r\n regex: /^(?:go|navigate)\\s+back$/i,\r\n gen: () => `await page.goBack();`,\r\n },\r\n {\r\n regex: /^refresh\\s+(?:the\\s+)?page$/i,\r\n gen: () => `await page.reload();`,\r\n },\r\n\r\n // ── Click actions ──\r\n // Prefer semantic role selectors (button/link) when the instruction names the role.\r\n // Fall back to getByText for generic clicks (tabs, menu items, etc.).\r\n {\r\n // Click \"quoted text\" button|link|tab|menu\r\n regex: /^click\\s+(?:the\\s+)?(?:on\\s+)?[\"'](.+?)[\"'](\\s+button|\\s+link|\\s+tab|\\s+menu)?$/i,\r\n gen: (m) => {\r\n const text = m[1] ?? '';\r\n const role = (m[2] ?? '').trim().toLowerCase();\r\n if (role === 'button') return `await page.getByRole('button', { name: '${text}' }).click();`;\r\n if (role === 'link') return `await page.getByRole('link', { name: '${text}' }).click();`;\r\n return `await page.getByText('${text}').click();`;\r\n },\r\n },\r\n {\r\n // Click unquoted word(s) [optional: button|link|tab]\r\n regex: /^click\\s+(?:the\\s+)?(?:on\\s+)?(\\w[\\w\\s]{0,30}?)(\\s+button|\\s+link|\\s+tab)?$/i,\r\n gen: (m) => {\r\n const text = (m[1] ?? '').trim();\r\n const role = (m[2] ?? '').trim().toLowerCase();\r\n if (role === 'button') return `await page.getByRole('button', { name: '${text}' }).click();`;\r\n if (role === 'link') return `await page.getByRole('link', { name: '${text}' }).click();`;\r\n return `await page.getByText('${text}').click();`;\r\n },\r\n },\r\n {\r\n regex: /^double\\s+click\\s+(?:the\\s+)?(?:on\\s+)?[\"']?(.+?)[\"']?$/i,\r\n gen: (m) => `await page.getByText('${m[1]}').dblclick();`,\r\n },\r\n {\r\n regex: /^right\\s+click\\s+(?:the\\s+)?(?:on\\s+)?[\"']?(.+?)[\"']?$/i,\r\n gen: (m) => `await page.getByText('${m[1]}').click({ button: 'right' });`,\r\n },\r\n\r\n // ── Type / Fill ──\r\n {\r\n // Matches: enter \"value\" into field OR enter {{VAR}} into field (quotes optional)\r\n regex: /^(?:type|enter|fill|input)\\s+[\"']?(.+?)[\"']?\\s+(?:in|into)\\s+(?:the\\s+)?(.+)$/i,\r\n gen: (m) => `await page.getByLabel('${m[2]}').fill('${m[1]}');`,\r\n },\r\n {\r\n regex: /^clear\\s+(?:the\\s+)?(.+?)(?:\\s+field)?$/i,\r\n gen: (m) => `await page.getByLabel('${m[1]}').clear();`,\r\n },\r\n\r\n // ── Assertions ──\r\n {\r\n regex: /^(?:verify|check|assert|ensure|confirm)\\s+(?:that\\s+)?[\"'](.+?)[\"']\\s+(?:is\\s+)?(?:visible|shown|displayed|present|appears)$/i,\r\n gen: (m) => `await expect(page.getByText('${m[1]}')).toBeVisible();`,\r\n },\r\n {\r\n regex: /^(?:verify|check|assert)\\s+(?:that\\s+)?[\"'](.+?)[\"']\\s+(?:is\\s+)?(?:not visible|hidden|not shown|gone|disappeared|not present)$/i,\r\n gen: (m) => `await expect(page.getByText('${m[1]}')).not.toBeVisible();`,\r\n },\r\n {\r\n regex: /^(?:verify|check)\\s+(?:the\\s+)?(?:page\\s+)?title\\s+(?:is|contains)\\s+[\"'](.+?)[\"']$/i,\r\n gen: (m) => `await expect(page).toHaveTitle(/${m[1]}/);`,\r\n },\r\n {\r\n regex: /^(?:verify|check)\\s+(?:the\\s+)?url\\s+(?:is|contains|matches)\\s+[\"'](.+?)[\"']$/i,\r\n gen: (m) =>\r\n `await expect(page).toHaveURL(/${(m[1] ?? '').replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}/);`,\r\n },\r\n {\r\n regex: /^(?:verify|check)\\s+(?:the\\s+)?[\"'](.+?)[\"']\\s+(?:field|input)\\s+(?:has value|contains|equals)\\s+[\"'](.+?)[\"']$/i,\r\n gen: (m) => `await expect(page.getByLabel('${m[1]}')).toHaveValue('${m[2]}');`,\r\n },\r\n\r\n // ── Keyboard ──\r\n {\r\n regex: /^press\\s+(.+)$/i,\r\n gen: (m) => `await page.keyboard.press('${(m[1] ?? '').trim()}');`,\r\n },\r\n {\r\n regex: /^(?:type|enter|fill)\\s+[\"']?(.+?)[\"']?\\s+(?:and\\s+)?press\\s+enter$/i,\r\n gen: (m) =>\r\n `await page.keyboard.type('${m[1]}');\\nawait page.keyboard.press('Enter');`,\r\n },\r\n\r\n // ── Dropdown / Select ──\r\n {\r\n regex: /^select\\s+[\"'](.+?)[\"']\\s+from\\s+(?:the\\s+)?(.+)$/i,\r\n gen: (m) => `await page.getByLabel('${m[2]}').selectOption('${m[1]}');`,\r\n },\r\n\r\n // ── Checkbox / Radio ──\r\n {\r\n regex: /^check\\s+(?:the\\s+)?[\"']?(.+?)[\"']?(?:\\s+checkbox)?$/i,\r\n gen: (m) => `await page.getByLabel('${m[1]}').check();`,\r\n },\r\n {\r\n regex: /^uncheck\\s+(?:the\\s+)?[\"']?(.+?)[\"']?(?:\\s+checkbox)?$/i,\r\n gen: (m) => `await page.getByLabel('${m[1]}').uncheck();`,\r\n },\r\n\r\n // ── Wait ──\r\n {\r\n regex: /^wait\\s+(?:for\\s+)?(\\d+)\\s+seconds?$/i,\r\n gen: (m) => `await page.waitForTimeout(${parseInt(m[1] ?? '1', 10) * 1000});`,\r\n },\r\n {\r\n regex: /^wait\\s+(?:for\\s+)?(?:the\\s+)?page\\s+(?:to\\s+)?load$/i,\r\n gen: () => `await page.waitForLoadState('networkidle');`,\r\n },\r\n\r\n // ── Scroll ──\r\n {\r\n regex: /^scroll\\s+(down|up)$/i,\r\n gen: (m) =>\r\n `await page.evaluate(() => window.scrollBy(0, ${(m[1] ?? '').toLowerCase() === 'down' ? 500 : -500}));`,\r\n },\r\n {\r\n regex: /^scroll\\s+to\\s+(top|bottom)$/i,\r\n gen: (m) =>\r\n `await page.evaluate(() => window.scrollTo(0, ${(m[1] ?? '').toLowerCase() === 'top' ? 0 : 'document.body.scrollHeight'}));`,\r\n },\r\n\r\n // ── Hover ──\r\n {\r\n regex: /^hover\\s+(?:over\\s+)?(?:the\\s+)?[\"']?(.+?)[\"']?$/i,\r\n gen: (m) => `await page.getByText('${m[1]}').hover();`,\r\n },\r\n\r\n // ── Screenshot ──\r\n {\r\n regex: /^take\\s+(?:a\\s+)?screenshot$/i,\r\n gen: () =>\r\n `await page.screenshot({ path: 'results/screenshots/step_${Date.now()}.png', fullPage: true });`,\r\n },\r\n\r\n // ── Focus ──\r\n {\r\n regex: /^(?:focus|tab to)\\s+(?:the\\s+)?(.+?)(?:\\s+field)?$/i,\r\n gen: (m) => `await page.getByLabel('${m[1]}').focus();`,\r\n },\r\n];\r\n\r\nexport class TemplateEngine {\r\n /**\r\n * Tries to match the instruction against all known patterns.\r\n * Returns generated Playwright code on the first match, or null if no match.\r\n * Cost: $0.00 — no AI call.\r\n */\r\n tryMatch(instruction: string): string | null {\r\n for (const pattern of PATTERNS) {\r\n const match = instruction.match(pattern.regex);\r\n if (match !== null) {\r\n return pattern.gen(match);\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /** Returns the number of patterns registered. */\r\n get patternCount(): number {\r\n return PATTERNS.length;\r\n }\r\n}\r\n","import { createHash } from 'crypto';\r\n\r\nexport function sha256(input: string): string {\r\n return createHash('sha256').update(input, 'utf8').digest('hex');\r\n}\r\n\r\nexport function md5(input: string): string {\r\n return createHash('md5').update(input, 'utf8').digest('hex');\r\n}\r\n\r\n/**\r\n * Normalises a URL by replacing dynamic path segments (IDs) with wildcards.\r\n * Example: /users/123/edit becomes /users/{star}/edit\r\n * Example: /posts/abc-def/comments becomes /posts/{star}/comments\r\n */\r\nexport function normalizeUrl(url: string): string {\r\n try {\r\n const parsed = new URL(url);\r\n const normalizedPath = parsed.pathname\r\n .split('/')\r\n .map((segment) => {\r\n // Numeric IDs\r\n if (/^\\d+$/.test(segment)) return '*';\r\n // UUIDs\r\n if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(segment)) {\r\n return '*';\r\n }\r\n // Slugs that look like IDs (alphanumeric + dashes, 8+ chars)\r\n if (/^[a-z0-9-]{8,}$/i.test(segment) && /-/.test(segment)) return '*';\r\n return segment;\r\n })\r\n .join('/');\r\n return normalizedPath;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * Generates a short cache key from an instruction and URL.\r\n * Key = first 16 chars of sha256(normalizedInstruction|urlPattern)\r\n */\r\nexport function generateCacheKey(instruction: string, url: string): string {\r\n const normalizedInstruction = instruction.toLowerCase().replace(/\\s+/g, ' ').trim();\r\n const urlPattern = normalizeUrl(url);\r\n return sha256(`${normalizedInstruction}|${urlPattern}`).slice(0, 16);\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { generateCacheKey } from '../utils/hash.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson } from '../storage/utils.js';\r\n\r\nconst logger = createChildLogger('code-cache');\r\n\r\nconst CACHE_FILE = path.join('results', '.code-cache.json');\r\nconst PERSIST_INTERVAL_MS = 30_000; // persist every 30 s\r\n\r\nexport interface CacheEntry {\r\n code: string;\r\n urlPattern: string;\r\n successCount: number;\r\n failCount: number;\r\n createdAt: number;\r\n lastUsedAt: number;\r\n}\r\n\r\ntype CacheData = Record<string, CacheEntry>;\r\n\r\n/**\r\n * Code Cache — Strategy 2 of the Smart Router.\r\n * Stores previously generated Playwright code keyed by (instruction, urlPattern).\r\n * Persists to results/.code-cache.json so re-runs never re-generate existing steps.\r\n * Cost: $0.00 — no AI call.\r\n */\r\nexport class CodeCache {\r\n private cache: Map<string, CacheEntry> = new Map();\r\n private dirty = false;\r\n private persistTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(private readonly persistPath = CACHE_FILE) {}\r\n\r\n /** Generates the cache key for a given instruction + URL. */\r\n generateKey(instruction: string, url: string): string {\r\n return generateCacheKey(instruction, url);\r\n }\r\n\r\n /** Returns the cached entry if valid, or null on miss/invalidation. */\r\n get(key: string): CacheEntry | null {\r\n const entry = this.cache.get(key);\r\n if (!entry) return null;\r\n\r\n // Auto-invalidate after 2 consecutive failures\r\n if (entry.failCount >= 2) {\r\n this.cache.delete(key);\r\n this.dirty = true;\r\n logger.debug({ key }, 'Cache entry invalidated after 2 failures');\r\n return null;\r\n }\r\n\r\n entry.lastUsedAt = Date.now();\r\n return entry;\r\n }\r\n\r\n /** Stores a new cache entry. */\r\n set(key: string, code: string, urlPattern: string): void {\r\n this.cache.set(key, {\r\n code,\r\n urlPattern,\r\n successCount: 0,\r\n failCount: 0,\r\n createdAt: Date.now(),\r\n lastUsedAt: Date.now(),\r\n });\r\n this.dirty = true;\r\n }\r\n\r\n /** Records a successful execution — resets failCount. */\r\n recordPass(key: string): void {\r\n const entry = this.cache.get(key);\r\n if (!entry) return;\r\n entry.successCount++;\r\n entry.failCount = 0;\r\n this.dirty = true;\r\n }\r\n\r\n /** Records a failed execution — invalidates after 2 consecutive failures. */\r\n recordFail(key: string): void {\r\n const entry = this.cache.get(key);\r\n if (!entry) return;\r\n entry.failCount++;\r\n if (entry.failCount >= 2) {\r\n this.cache.delete(key);\r\n logger.debug({ key }, 'Cache entry removed after 2 failures');\r\n }\r\n this.dirty = true;\r\n }\r\n\r\n /** Number of entries currently in the cache. */\r\n get size(): number {\r\n return this.cache.size;\r\n }\r\n\r\n /** Persists the cache to disk (atomic write). */\r\n async persist(): Promise<void> {\r\n if (!this.dirty) return;\r\n try {\r\n const data: CacheData = Object.fromEntries(this.cache.entries());\r\n await atomicWriteJson(this.persistPath, data);\r\n this.dirty = false;\r\n logger.debug({ entries: this.cache.size, path: this.persistPath }, 'Cache persisted');\r\n } catch (err) {\r\n logger.warn({ err }, 'Failed to persist code cache');\r\n }\r\n }\r\n\r\n /** Loads the cache from disk. */\r\n async load(): Promise<void> {\r\n if (!(await fs.pathExists(this.persistPath))) return;\r\n try {\r\n const data = await fs.readJson(this.persistPath) as CacheData;\r\n this.cache.clear();\r\n for (const [key, entry] of Object.entries(data)) {\r\n this.cache.set(key, entry);\r\n }\r\n logger.debug({ entries: this.cache.size, path: this.persistPath }, 'Cache loaded');\r\n } catch (err) {\r\n logger.warn({ err }, 'Failed to load code cache — starting fresh');\r\n }\r\n }\r\n\r\n /**\r\n * Starts periodic persistence and registers a process-exit handler.\r\n * Call once at startup.\r\n */\r\n startAutoSave(): void {\r\n if (this.persistTimer) return;\r\n this.persistTimer = setInterval(() => {\r\n void this.persist();\r\n }, PERSIST_INTERVAL_MS);\r\n\r\n // Don't block process exit\r\n if (this.persistTimer.unref) this.persistTimer.unref();\r\n\r\n const flush = (): void => { void this.persist(); };\r\n process.once('exit', flush);\r\n process.once('SIGINT', flush);\r\n process.once('SIGTERM', flush);\r\n }\r\n\r\n /** Stops auto-save. */\r\n stopAutoSave(): void {\r\n if (this.persistTimer) {\r\n clearInterval(this.persistTimer);\r\n this.persistTimer = null;\r\n }\r\n }\r\n}\r\n","/**\r\n * Complexity Classifier — Strategy 4 component of the Smart Router.\r\n * Routes instructions to cheap (simple/medium) or smart (complex) models.\r\n */\r\n\r\nexport type Complexity = 'simple' | 'medium' | 'complex';\r\n\r\nconst COMPLEX_SIGNALS: ReadonlyArray<RegExp> = [\r\n /table|grid|chart|graph|calendar|datepicker/i,\r\n /drag|drop|resize|reorder|sortable/i,\r\n /verify.*(count|greater|less|between|exactly|more than|fewer)/i,\r\n /wait\\s+until|disappears|loading\\s+(?:is\\s+)?(?:done|complete|finished)/i,\r\n /(?:first|second|third|last|nth|\\d+(?:st|nd|rd|th))\\s+(?:item|row|card|element|result)/i,\r\n /if\\s+|conditional|depending|based on/i,\r\n /iframe|shadow\\s*dom|popup|modal|dialog|alert/i,\r\n /upload|download|file|attachment/i,\r\n /hover\\s+.*then|right.click|double.click/i,\r\n /api|network|request|response|intercept/i,\r\n /(?:store|save|capture|extract)\\s+.*(?:variable|value|text)/i,\r\n /multi.?select|autocomplete|typeahead|combobox/i,\r\n];\r\n\r\nexport class ComplexityClassifier {\r\n /**\r\n * Classifies an instruction as simple, medium, or complex.\r\n * - simple (0 signals): use cheap/fast model\r\n * - medium (1 signal): use cheap/fast model\r\n * - complex (2+ signals): use primary/smart model\r\n */\r\n classify(instruction: string): Complexity {\r\n const hits = COMPLEX_SIGNALS.filter((r) => r.test(instruction)).length;\r\n if (hits >= 2) return 'complex';\r\n if (hits === 1) return 'medium';\r\n return 'simple';\r\n }\r\n}\r\n","import type { AIProvider, PageContext } from './types.js';\r\nimport { TemplateEngine } from './template-engine.js';\r\nimport { CodeCache } from './code-cache.js';\r\nimport { sanitizeGeneratedCode } from '../utils/sanitize.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('batch-processor');\r\n\r\nexport interface BatchStep {\r\n instruction: string;\r\n context: PageContext;\r\n}\r\n\r\n/**\r\n * Batch Processor — Strategy 3 of the Smart Router.\r\n * When multiple steps need AI generation, sends them all in ONE API call\r\n * instead of N separate calls.\r\n *\r\n * Cost: ~$0.001/step vs $0.005/step for individual calls.\r\n */\r\nexport class BatchProcessor {\r\n constructor(\r\n private readonly templateEngine: TemplateEngine,\r\n private readonly cache: CodeCache,\r\n ) {}\r\n\r\n /**\r\n * Generates code for multiple steps, resolving as many as possible locally first.\r\n * Returns a Map of step-index → generated-code.\r\n */\r\n async batchGenerate(\r\n steps: BatchStep[],\r\n provider: AIProvider,\r\n ): Promise<Map<number, string>> {\r\n const results = new Map<number, string>();\r\n const needsAI: Array<{ index: number; instruction: string; context: PageContext }> = [];\r\n\r\n // ── Strategy 1 + 2: Resolve locally first ───────────────────────────────\r\n for (let i = 0; i < steps.length; i++) {\r\n const { instruction, context } = steps[i];\r\n\r\n // Template engine ($0, <1ms)\r\n const templateCode = this.templateEngine.tryMatch(instruction);\r\n if (templateCode !== null) {\r\n results.set(i, templateCode);\r\n continue;\r\n }\r\n\r\n // Code cache ($0, <1ms)\r\n const cacheKey = this.cache.generateKey(instruction, context.url);\r\n const cached = this.cache.get(cacheKey);\r\n if (cached !== null) {\r\n results.set(i, cached.code);\r\n continue;\r\n }\r\n\r\n // Needs AI\r\n needsAI.push({ index: i, instruction, context });\r\n }\r\n\r\n logger.debug(\r\n { total: steps.length, local: results.size, needsAI: needsAI.length },\r\n 'Batch resolution',\r\n );\r\n\r\n // ── Strategy 3: Single AI call for all remaining ─────────────────────────\r\n if (needsAI.length === 0) return results;\r\n\r\n const aiSteps = needsAI.map((s) => ({\r\n instruction: s.instruction,\r\n context: s.context,\r\n }));\r\n\r\n // Let errors propagate — callers must handle them and surface to the user\r\n const codes = await provider.batchGenerateCode(aiSteps);\r\n\r\n for (let i = 0; i < needsAI.length; i++) {\r\n const original = needsAI[i];\r\n const code = codes[i];\r\n if (!code) {\r\n logger.warn({ instruction: original.instruction }, 'AI returned empty code for step');\r\n continue;\r\n }\r\n\r\n let sanitized: string;\r\n try {\r\n sanitized = sanitizeGeneratedCode(code);\r\n } catch (err) {\r\n logger.warn({ instruction: original.instruction, err }, 'Skipping unsafe/invalid batch result');\r\n continue;\r\n }\r\n\r\n results.set(original.index, sanitized);\r\n\r\n // Cache for future use\r\n const cacheKey = this.cache.generateKey(\r\n original.instruction,\r\n original.context.url,\r\n );\r\n this.cache.set(cacheKey, sanitized, original.context.url);\r\n }\r\n\r\n return results;\r\n }\r\n}\r\n","import type { AIProvider, PageContext, GenerationResult, RouterStats } from './types.js';\r\nimport { TemplateEngine } from './template-engine.js';\r\nimport { CodeCache } from './code-cache.js';\r\nimport { ComplexityClassifier } from './complexity-classifier.js';\r\nimport { BatchProcessor, type BatchStep } from './batch-processor.js';\r\nimport { sanitizeGeneratedCode, fixAntiPatterns, fixButtonSelectors } from '../utils/sanitize.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { detectStepType } from '../engine/step-type-detector.js';\r\n\r\nconst logger = createChildLogger('smart-router');\r\n\r\nexport interface SmartRouterConfig {\r\n primaryProvider: AIProvider;\r\n fastProvider?: AIProvider; // null/undefined = tiered mode disabled\r\n cache?: CodeCache; // shared cache instance\r\n}\r\n\r\n/**\r\n * Smart Router — the central cost-optimisation brain.\r\n *\r\n * Every instruction passes through this 5-strategy pipeline:\r\n * 1. Template Engine — $0.00, <1ms (~60% of steps)\r\n * 2. Code Cache — $0.00, <1ms (~20% of steps)\r\n * 3. Batch Processor — used externally via batchGenerate()\r\n * 4. Tiered Model — cheap model for simple/medium instructions\r\n * 5. AI Call — primary model for complex instructions\r\n */\r\nexport class SmartRouter {\r\n private readonly templateEngine: TemplateEngine;\r\n private readonly cache: CodeCache;\r\n private readonly classifier: ComplexityClassifier;\r\n private readonly batchProcessor: BatchProcessor;\r\n private readonly primaryProvider: AIProvider;\r\n private readonly fastProvider: AIProvider | null;\r\n\r\n private readonly stats = {\r\n template: 0,\r\n cache: 0,\r\n batch: 0,\r\n fast: 0,\r\n primary: 0,\r\n total: 0,\r\n };\r\n\r\n constructor(config: SmartRouterConfig) {\r\n this.primaryProvider = config.primaryProvider;\r\n this.fastProvider = config.fastProvider ?? null;\r\n this.cache = config.cache ?? new CodeCache();\r\n this.templateEngine = new TemplateEngine();\r\n this.classifier = new ComplexityClassifier();\r\n this.batchProcessor = new BatchProcessor(this.templateEngine, this.cache);\r\n }\r\n\r\n // ─── Single step generation ───────────────────────────────────────────────\r\n\r\n async generate(instruction: string, pageContext: PageContext): Promise<GenerationResult> {\r\n this.stats.total++;\r\n\r\n const isApi = detectStepType(instruction) === 'api';\r\n\r\n // Strategy 1: Template ($0, <1ms) — UI steps only (templates are DOM-based)\r\n if (!isApi) {\r\n const templateCode = this.templateEngine.tryMatch(instruction);\r\n if (templateCode !== null) {\r\n this.stats.template++;\r\n logger.debug({ instruction }, 'Template match');\r\n return { code: fixAntiPatterns(templateCode), strategy: 'template', cost: 0, model: 'local' };\r\n }\r\n }\r\n\r\n // Strategy 2: Cache ($0, <1ms)\r\n const cacheKey = this.cache.generateKey(instruction, pageContext.url);\r\n const cached = this.cache.get(cacheKey);\r\n if (cached !== null) {\r\n this.stats.cache++;\r\n logger.debug({ instruction }, 'Cache hit');\r\n // Re-sanitize cached code — may have been stored before anti-pattern/selector fixes were added\r\n const fixed = fixButtonSelectors(instruction, fixAntiPatterns(cached.code));\r\n return { code: fixed, strategy: 'cache', cost: 0, model: 'local' };\r\n }\r\n\r\n // Strategy 3: Skipped for single step (only used in batchGenerate)\r\n\r\n // Strategy 4: Tiered model selection\r\n const complexity = this.classifier.classify(instruction);\r\n const usesFast = this.fastProvider !== null && complexity !== 'complex';\r\n const provider = usesFast ? (this.fastProvider as AIProvider) : this.primaryProvider;\r\n const strategy = usesFast ? 'fast' : 'primary';\r\n\r\n // Strategy 5: AI call\r\n // Note: provider.generateCode already returns sanitized + button-selector-fixed code\r\n logger.debug({ instruction, complexity, strategy }, 'AI call');\r\n const code = await provider.generateCode(instruction, pageContext);\r\n\r\n // Save to cache for future runs (code is already sanitized + fixed)\r\n this.cache.set(cacheKey, code, pageContext.url);\r\n\r\n if (usesFast) {\r\n this.stats.fast++;\r\n } else {\r\n this.stats.primary++;\r\n }\r\n\r\n return {\r\n code,\r\n strategy,\r\n cost: usesFast ? 0.0003 : 0.005,\r\n model: provider.model,\r\n };\r\n }\r\n\r\n // ─── Batch generation ─────────────────────────────────────────────────────\r\n\r\n async batchGenerate(steps: BatchStep[]): Promise<GenerationResult[]> {\r\n const resultMap = await this.batchProcessor.batchGenerate(steps, this.primaryProvider);\r\n this.stats.batch += steps.length;\r\n\r\n return steps.map((_step, i) => {\r\n const code = resultMap.get(i) ?? '';\r\n return {\r\n code,\r\n strategy: 'batch' as const,\r\n cost: 0.001,\r\n model: this.primaryProvider.model,\r\n };\r\n });\r\n }\r\n\r\n // ─── Cache feedback ───────────────────────────────────────────────────────\r\n\r\n recordPass(instruction: string, url: string): void {\r\n const key = this.cache.generateKey(instruction, url);\r\n this.cache.recordPass(key);\r\n }\r\n\r\n recordFail(instruction: string, url: string): void {\r\n const key = this.cache.generateKey(instruction, url);\r\n this.cache.recordFail(key);\r\n }\r\n\r\n // ─── Stats (shown in Studio dashboard) ───────────────────────────────────\r\n\r\n getStats(): RouterStats {\r\n const freeCalls = this.stats.template + this.stats.cache;\r\n return {\r\n ...this.stats,\r\n freeCalls,\r\n freePercent: (\r\n (freeCalls / Math.max(this.stats.total, 1)) *\r\n 100\r\n ).toFixed(1),\r\n cacheEntries: this.cache.size,\r\n };\r\n }\r\n\r\n /** Exposes the cache for persistence management. */\r\n getCache(): CodeCache {\r\n return this.cache;\r\n }\r\n\r\n /** Exposes the primary provider (e.g. for healing operations). */\r\n getPrimaryProvider(): AIProvider {\r\n return this.primaryProvider;\r\n }\r\n}\r\n","import { z } from 'zod';\r\nimport type { PageContext, AIProvider, GeneratedSuite, GenerationResult, RouterStats } from '../types/ai.js';\r\n\r\nexport type { PageContext, AIProvider, GeneratedSuite, GenerationResult, RouterStats };\r\n\r\n// ─── Internal AI layer types ──────────────────────────────────────────────────\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant';\r\n content: string;\r\n}\r\n\r\nexport interface ProviderConfig {\r\n model: string;\r\n timeoutMs: number;\r\n maxRetries: number;\r\n}\r\n\r\n// ─── Schemas for parsing AI responses ────────────────────────────────────────\r\n\r\nexport const AIGeneratedStepSchema = z.object({\r\n instruction: z.string().min(1),\r\n});\r\n\r\nexport const AIGeneratedCaseSchema = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n steps: z.array(AIGeneratedStepSchema),\r\n});\r\n\r\nexport const AIGeneratedSuiteSchema = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n cases: z.array(AIGeneratedCaseSchema),\r\n});\r\n\r\nexport type AIGeneratedStep = z.infer<typeof AIGeneratedStepSchema>;\r\nexport type AIGeneratedCase = z.infer<typeof AIGeneratedCaseSchema>;\r\nexport type AIGeneratedSuite = z.infer<typeof AIGeneratedSuiteSchema>;\r\n\r\n// Batch response item\r\nexport const BatchResultItemSchema = z.object({\r\n index: z.number().int().min(0),\r\n code: z.string(),\r\n});\r\n\r\nexport const BatchResultSchema = z.object({\r\n results: z.array(BatchResultItemSchema),\r\n});\r\n\r\nexport type BatchResultItem = z.infer<typeof BatchResultItemSchema>;\r\n\r\n// Two-pass generation schemas\r\nexport const AIOutlineCaseSchema = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n});\r\n\r\nexport const AIOutlineSchema = z.object({\r\n name: z.string().min(1),\r\n description: z.string().default(''),\r\n tags: z.array(z.string()).default([]),\r\n cases: z.array(AIOutlineCaseSchema),\r\n});\r\n\r\nexport const AIStepsResponseSchema = z.object({\r\n steps: z.array(AIGeneratedStepSchema),\r\n});\r\n\r\nexport type AIOutlineCase = z.infer<typeof AIOutlineCaseSchema>;\r\nexport type AIOutline = z.infer<typeof AIOutlineSchema>;\r\n\r\n// Screenshot analysis result\r\nexport const ScreenshotAnalysisSchema = z.object({\r\n x: z.number(),\r\n y: z.number(),\r\n action: z.string(),\r\n});\r\n\r\nexport type ScreenshotAnalysis = z.infer<typeof ScreenshotAnalysisSchema>;\r\n","import type { PageContext } from '../types.js';\r\n\r\nconst SYSTEM_PROMPT = `You are a Playwright test automation expert. Convert plain English test steps into executable Playwright TypeScript code.\r\n\r\n━━━ OUTPUT RULES ━━━\r\n1. Return ONLY raw executable code — no markdown, no \\`\\`\\`, no explanations\r\n2. Code runs as the body of: async (page, expect, context) => { <your code here> }\r\n3. Always await async Playwright operations\r\n4. Variable placeholders like {{VAR_NAME}} must be kept exactly as-is — they are substituted at runtime\r\n5. Return minimal code — one logical action unless the step explicitly requires multiple\r\n\r\n━━━ RUNTIME CONTEXT (shared across test cases) ━━━\r\nA \\`context\\` object is available for storing/retrieving values across steps and cases:\r\n context.setVariable('TOKEN', value) — save a value (persists for the entire run)\r\n context.getVariable('TOKEN') — retrieve a saved value (returns string or undefined)\r\n\r\nUse context.setVariable when the instruction says \"save\", \"store\", \"extract and save\", \"remember\".\r\nUse context.getVariable when the instruction references a previously extracted value.\r\n\r\nExample — extract token from API response and save:\r\n const res = await page.request.post('/api/login', { data: { email: '{{ADMIN_EMAIL}}', password: '{{DEFAULT_PASSWORD}}' } });\r\n const body = await res.json();\r\n context.setVariable('AUTH_TOKEN', body.token);\r\n\r\nExample — use saved token in a later step:\r\n const token = context.getVariable('AUTH_TOKEN');\r\n const res = await page.request.get('/api/profile', { headers: { Authorization: \\`Bearer \\${token}\\` } });\r\n\r\n━━━ API TESTING (Playwright Request API) ━━━\r\nFor API/HTTP steps, use Playwright's built-in request API:\r\n await page.request.get(url, options?)\r\n await page.request.post(url, options?)\r\n await page.request.put(url, options?)\r\n await page.request.delete(url, options?)\r\n await page.request.patch(url, options?)\r\n\r\nOptions: { headers: {...}, data: {...} (for JSON body), form: {...} (for form data) }\r\nResponse: res.status(), res.json(), res.text(), res.headers()\r\n\r\nAssert status: expect(res.status()).toBe(200)\r\nAssert body: const body = await res.json(); expect(body.name).toBe('Admin');\r\nAssert header: expect(res.headers()['content-type']).toContain('application/json');\r\n\r\n━━━ SELECTOR PRIORITY (use the FIRST that applies) ━━━\r\nPriority 1 — data-testid / data-cy / data-qa:\r\n page.getByTestId('submit-btn')\r\n\r\nPriority 2 — Role + name (BUTTONS, LINKS, CHECKBOXES, HEADINGS):\r\n page.getByRole('button', { name: 'Login' }) ← ANY button click — even \"Click Login button\"\r\n page.getByRole('link', { name: 'Dashboard' }) ← links / nav items\r\n page.getByRole('checkbox', { name: 'Remember' })\r\n ⚠️ If the instruction contains \"button\" → ALWAYS use getByRole('button', { name: '...' })\r\n\r\nPriority 3 — Label (inputs):\r\n page.getByLabel('Username') ← when a <label> is associated\r\n\r\nPriority 4 — Placeholder (inputs without label):\r\n page.getByPlaceholder('Enter password')\r\n\r\nPriority 5 — CSS / type selector (submit buttons with no visible text):\r\n page.locator('button[type=\"submit\"]').click()\r\n page.locator('#login-btn').click()\r\n\r\nPriority 6 — Visible text ONLY (non-interactive text, last resort):\r\n page.getByText('Welcome back') ← ONLY for assertions on plain text, NOT for clicking buttons\r\n\r\n━━━ ELEMENT NAME EXTRACTION (critical) ━━━\r\nExtract ONLY the target element name — NEVER use the full sentence as the locator name.\r\n ✓ \"Click Login button\" → page.getByRole('button', { name: 'Login' }).click()\r\n ✓ \"Click on Submit\" → page.getByRole('button', { name: 'Submit' }).click()\r\n ✓ \"Click on Login button\" → page.getByRole('button', { name: 'Login' }).click()\r\n ✓ \"Click Dashboard in sidebar\" → page.getByRole('link', { name: 'Dashboard' }).click()\r\n ✓ \"Enter username as Admin\" → page.getByLabel('Username').fill('Admin')\r\n → page.getByPlaceholder('Username').fill('Admin')\r\n ✗ page.getByText('Login').click() ← WRONG for buttons\r\n ✗ page.getByRole('button', { name: 'Click Login button' }) ← WRONG full sentence\r\n ✗ page.getByRole('button', { name: 'Admin in sidebar menu' }) ← WRONG full sentence\r\n\r\n━━━ ELEMENT TYPE RULES ━━━\r\n- Any \"...button\" step → getByRole('button', { name: 'ExactText' }) ← MANDATORY\r\n- Sidebar / nav links → getByRole('link', { name: '...' })\r\n- Form submit button → getByRole('button', { name: 'Submit' }) or page.locator('button[type=\"submit\"]')\r\n- Text inputs → getByLabel('...') or getByPlaceholder('...')\r\n- Dropdowns → page.getByLabel('...').selectOption('value')\r\n- Checkboxes → page.getByLabel('...').check()\r\n- NEVER use getByText() to click a button — always use getByRole('button')\r\n\r\n━━━ NAVIGATION ━━━\r\nAlways use { waitUntil: 'networkidle' } with page.goto() so the page fully loads before the next step:\r\n await page.goto('https://example.com', { waitUntil: 'networkidle' });\r\n\r\n━━━ ANTI-PATTERNS (NEVER generate these) ━━━\r\n- NEVER .or() chains: page.getByRole(...).or(page.getByText(...))\r\n- NEVER .first(): page.getByRole(...).first().click()\r\n- NEVER full sentence as name: { name: 'Click on Admin on sidebar menu' }\r\n- NEVER bare page.goto() without waitUntil: 'networkidle'\r\n\r\n━━━ ASSERTIONS GUIDE ━━━\r\nURL check: await expect(page).toHaveURL(/dashboard/)\r\n await expect(page).toHaveURL('https://example.com/home')\r\nTitle check: await expect(page).toHaveTitle(/Dashboard/)\r\nVisible text: await expect(page.getByText('Welcome')).toBeVisible()\r\nElement visible: await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()\r\nInput value: await expect(page.getByLabel('Email')).toHaveValue('user@example.com')\r\nNot visible: await expect(page.getByText('Error')).not.toBeVisible()\r\nCount: await expect(page.getByRole('listitem')).toHaveCount(5)\r\n\r\nFor \"verify user is on X page\" → use toHaveURL() or check for a heading/element specific to that page.`;\r\n\r\nexport function buildStepToCodePrompt(\r\n instruction: string,\r\n context: PageContext,\r\n): { system: string; user: string } {\r\n const prevSteps =\r\n context.previousSteps.length > 0\r\n ? context.previousSteps\r\n .slice(-5)\r\n .map((s, i) => ` ${i + 1}. \"${s.instruction}\"\\n ${s.code}`)\r\n .join('\\n')\r\n : ' None';\r\n\r\n const vars =\r\n Object.keys(context.variables).length > 0\r\n ? Object.entries(context.variables)\r\n .map(([k, v]) => ` {{${k}}} = ${v}`)\r\n .join('\\n')\r\n : ' None';\r\n\r\n const user = `Current page:\r\n URL: ${context.url}\r\n Title: ${context.title}\r\n\r\nInteractive elements on page (use these to pick selectors):\r\n${context.interactiveElements || ' None captured'}\r\n\r\nPrevious steps already done (for context):\r\n${prevSteps}\r\n\r\nRuntime variables:\r\n${vars}\r\n\r\nStep to implement: \"${instruction}\"`;\r\n\r\n return { system: SYSTEM_PROMPT, user };\r\n}\r\n","// ─── Pass 1: generate suite outline (case names + descriptions only) ─────────\r\n\r\nconst OUTLINE_SYSTEM = `You are a QA test planning expert.\r\nGiven a user story, produce a test suite outline — the suite metadata and a list of test cases.\r\nDo NOT include steps yet. Return ONLY valid JSON, no markdown, no code fences.`;\r\n\r\nconst OUTLINE_SCHEMA = `{\r\n \"name\": \"Suite name (e.g. Authentication)\",\r\n \"description\": \"What this suite covers\",\r\n \"tags\": [\"smoke\", \"regression\"],\r\n \"cases\": [\r\n {\r\n \"name\": \"Login with valid credentials\",\r\n \"description\": \"Verifies that a user with correct username/password can log in\",\r\n \"tags\": [\"smoke\"]\r\n }\r\n ]\r\n}`;\r\n\r\nexport function buildOutlinePrompt(story: string): { system: string; user: string } {\r\n return {\r\n system: OUTLINE_SYSTEM,\r\n user: `User story:\\n${story}\\n\\nGenerate the suite outline (no steps) following this schema:\\n${OUTLINE_SCHEMA}\\n\\nReturn only the JSON object.`,\r\n };\r\n}\r\n\r\n// ─── Pass 2: generate steps for one test case ─────────────────────────────────\r\n\r\nconst STEPS_SYSTEM = `You are a QA test automation expert.\r\nGiven a test case name and description, write the detailed plain-English steps needed to execute it.\r\nRules:\r\n1. Return ONLY valid JSON — no markdown, no code fences\r\n2. Each step must be a single atomic action or assertion\r\n3. Be concrete — reference actual UI elements by their visible labels or text\r\n4. Use {{VARIABLE}} tokens for sensitive values (e.g. {{PASSWORD}}, {{USERNAME}})`;\r\n\r\nconst STEPS_SCHEMA = `{\r\n \"steps\": [\r\n { \"instruction\": \"Navigate to the login page\" },\r\n { \"instruction\": \"Enter 'admin' in the Username field\" },\r\n { \"instruction\": \"Enter '{{PASSWORD}}' in the Password field\" },\r\n { \"instruction\": \"Click the 'Login' button\" },\r\n { \"instruction\": \"Verify the Dashboard heading is visible\" }\r\n ]\r\n}`;\r\n\r\nexport function buildStepsPrompt(\r\n suiteName: string,\r\n caseName: string,\r\n caseDescription: string,\r\n story: string,\r\n): { system: string; user: string } {\r\n return {\r\n system: STEPS_SYSTEM,\r\n user: `Suite: \"${suiteName}\"\\nTest case: \"${caseName}\"\\nDescription: \"${caseDescription}\"\\n\\nContext (original user story):\\n${story}\\n\\nGenerate the steps for this test case following this schema:\\n${STEPS_SCHEMA}\\n\\nReturn only the JSON object.`,\r\n };\r\n}\r\n\r\n// ─── Legacy single-pass prompt (kept for direct use / fallback) ───────────────\r\n\r\nconst SYSTEM_PROMPT = `You are a QA test planning expert. Convert user stories into structured test suites.\r\n\r\nRULES:\r\n1. Return ONLY valid JSON — no markdown, no explanations, no code fences\r\n2. Each step must be a plain English instruction (not Playwright code)\r\n3. Steps must be atomic — one action or assertion per step\r\n4. Cover the happy path, then common edge cases and negative scenarios\r\n5. Test case names must be descriptive and start with a verb (e.g. \"Login with valid credentials\")\r\n6. Steps should be concrete — reference actual UI elements by their labels or text`;\r\n\r\nconst SCHEMA_GUIDE = `{\r\n \"name\": \"Suite name (e.g. Authentication)\",\r\n \"description\": \"What this suite covers\",\r\n \"tags\": [\"smoke\", \"regression\"],\r\n \"cases\": [\r\n {\r\n \"name\": \"Test case name\",\r\n \"description\": \"What this specific test verifies\",\r\n \"tags\": [\"smoke\"],\r\n \"steps\": [\r\n { \"instruction\": \"Navigate to the login page\" },\r\n { \"instruction\": \"Enter 'user@example.com' in the Email field\" },\r\n { \"instruction\": \"Enter '{{PASSWORD}}' in the Password field\" },\r\n { \"instruction\": \"Click the 'Sign In' button\" },\r\n { \"instruction\": \"Verify that 'Welcome' is visible\" }\r\n ]\r\n }\r\n ]\r\n}`;\r\n\r\nexport function buildStoryToSuitePrompt(story: string): { system: string; user: string } {\r\n const user = `User story:\r\n${story}\r\n\r\nGenerate a JSON test suite following this exact schema:\r\n${SCHEMA_GUIDE}\r\n\r\nImportant: return only the JSON object, nothing else.`;\r\n\r\n return { system: SYSTEM_PROMPT, user };\r\n}\r\n","import type { PageContext } from '../types.js';\r\n\r\nconst SYSTEM_PROMPT = `You are a Playwright test self-healing expert. A test step has failed due to an infrastructure issue (broken selector, element moved, DOM changed) and you must generate new code that will work with the current page state.\r\n\r\nRULES:\r\n1. Return ONLY raw executable code — no markdown, no explanations, no code fences\r\n2. Analyse the error message carefully to understand WHY the original code failed\r\n3. Use the current page state (elements, HTML) to find the correct locator\r\n4. Prefer getByRole > getByLabel > getByPlaceholder > getByText > CSS selector\r\n5. Keep variable references like {{VAR_NAME}} as-is\r\n6. Return the minimal code that achieves the same intent as the original step\r\n7. CRITICAL: NEVER change expect() assertions or expected values. Only fix locators, selectors, and actions.\r\n If the original code has expect(status).toBe(200), keep it as toBe(200).\r\n If the original code has expect(text).toContain('Welcome'), keep it as toContain('Welcome').\r\n Assertions represent the TEST INTENT — changing them would hide real bugs.\r\n8. Only fix HOW the test interacts with the page (selectors, actions) — never WHAT it verifies`;\r\n\r\nexport function buildSelfHealPrompt(\r\n instruction: string,\r\n failedCode: string,\r\n error: string,\r\n context: PageContext,\r\n): { system: string; user: string } {\r\n const user = `A test step has failed. Generate replacement Playwright code.\r\n\r\nOriginal instruction: \"${instruction}\"\r\n\r\nFailed code:\r\n${failedCode}\r\n\r\nError message:\r\n${error}\r\n\r\nCurrent page state:\r\n URL: ${context.url}\r\n Title: ${context.title}\r\n\r\nCurrent interactive elements:\r\n${context.interactiveElements || ' None captured'}\r\n\r\nHTML snapshot (partial):\r\n${context.htmlSnapshot.slice(0, 3000)}\r\n\r\nGenerate new Playwright code that achieves: \"${instruction}\"`;\r\n\r\n return { system: SYSTEM_PROMPT, user };\r\n}\r\n\r\nconst MULTI_SELECTOR_SYSTEM = `You are a Playwright locator strategy expert. Generate 5 DIFFERENT selector strategies for the same element.\r\n\r\nRULES:\r\n1. Return ONLY valid JSON — no markdown, no explanations\r\n2. Return exactly 5 different approaches\r\n3. Each must be a complete, executable Playwright code line\r\n4. Use different locator types for each strategy`;\r\n\r\nexport function buildMultiSelectorPrompt(\r\n instruction: string,\r\n failedCode: string,\r\n context: PageContext,\r\n): { system: string; user: string } {\r\n const user = `Generate 5 different Playwright selector strategies to achieve: \"${instruction}\"\r\n\r\nFailed original code:\r\n${failedCode}\r\n\r\nCurrent page elements:\r\n${context.interactiveElements || 'None captured'}\r\n\r\nHTML snippet:\r\n${context.htmlSnapshot.slice(0, 2000)}\r\n\r\nReturn JSON:\r\n{\r\n \"strategies\": [\r\n \"await page.getByRole('button', { name: 'Sign In' }).click();\",\r\n \"await page.getByText('Sign In').click();\",\r\n \"await page.locator('#login-btn').click();\",\r\n \"await page.locator('[data-testid=\\\\\\\"login\\\\\\\"]').click();\",\r\n \"await page.locator('xpath=//button[contains(text(),\\\\'Sign In\\\\')]').click();\"\r\n ]\r\n}`;\r\n\r\n return { system: MULTI_SELECTOR_SYSTEM, user };\r\n}\r\n\r\nexport function buildDecomposePrompt(\r\n instruction: string,\r\n failedCode: string,\r\n context: PageContext,\r\n): { system: string; user: string } {\r\n const decomposeSys = `You are a Playwright test expert. Break a complex test step into 3-5 simpler micro-actions.\r\n\r\nRULES:\r\n1. Return ONLY valid JSON\r\n2. Each micro-action must be a complete, executable code line\r\n3. The sequence must achieve the same result as the original step`;\r\n\r\n const user = `Break this failing step into micro-actions: \"${instruction}\"\r\n\r\nFailed code: ${failedCode}\r\n\r\nPage: ${context.url} — ${context.title}\r\nElements: ${context.interactiveElements.slice(0, 1000)}\r\n\r\nReturn JSON:\r\n{\r\n \"actions\": [\r\n \"await page.locator('...')...\",\r\n \"await page.locator('...')...\"\r\n ]\r\n}`;\r\n\r\n return { system: decomposeSys, user };\r\n}\r\n","import type { PageContext } from '../types.js';\r\n\r\nconst SYSTEM_PROMPT = `You are a Playwright test automation expert. Generate executable Playwright code for multiple test steps in a single JSON response.\r\n\r\n━━━ OUTPUT FORMAT ━━━\r\n1. Return ONLY valid JSON — no markdown, no \\`\\`\\`, no explanations\r\n2. Each step result: { \"index\": N, \"code\": \"await ...\" }\r\n3. Each code snippet runs as: async (page, expect) => { <code> }\r\n4. Return ALL steps — never skip one\r\n5. Keep {{VAR_NAME}} placeholders exactly as-is — substituted at runtime\r\n\r\n━━━ SELECTOR PRIORITY (use the FIRST that applies) ━━━\r\nPriority 1 — data-testid / data-cy / data-qa:\r\n page.getByTestId('login-btn')\r\n\r\nPriority 2 — Role + name (BUTTONS, LINKS, CHECKBOXES):\r\n page.getByRole('button', { name: 'Login' }) ← ANY button click\r\n page.getByRole('link', { name: 'Dashboard' }) ← links / nav items\r\n ⚠️ If the instruction contains \"button\" → ALWAYS use getByRole('button', { name: '...' })\r\n\r\nPriority 3 — Associated label (inputs):\r\n page.getByLabel('Username')\r\n\r\nPriority 4 — Placeholder (inputs without label):\r\n page.getByPlaceholder('Enter your email')\r\n\r\nPriority 5 — CSS / type selector (submit buttons with no text):\r\n page.locator('button[type=\"submit\"]').click()\r\n\r\nPriority 6 — Visible text ONLY for assertions on plain text (NEVER for clicking buttons):\r\n page.getByText('Welcome back')\r\n\r\n━━━ ELEMENT NAME EXTRACTION (critical) ━━━\r\nAlways extract ONLY the target element name — NEVER use the full instruction as the name.\r\n ✓ \"Click Login button\" → page.getByRole('button', { name: 'Login' }).click()\r\n ✓ \"Click on Submit\" → page.getByRole('button', { name: 'Submit' }).click()\r\n ✓ \"Click on Admin in menu\" → page.getByRole('link', { name: 'Admin' }).click()\r\n ✓ \"Enter username as Admin\" → page.getByLabel('Username').fill('Admin')\r\n → page.getByPlaceholder('Username').fill('Admin')\r\n ✗ page.getByText('Login').click() ← WRONG for buttons\r\n ✗ { name: 'Click on Admin in the sidebar menu' } ← WRONG full sentence\r\n ✗ { name: 'Enter username as Admin' } ← WRONG full sentence\r\n\r\n━━━ ELEMENT TYPE RULES ━━━\r\n- Any \"...button\" step → getByRole('button', { name: 'ExactText' }) ← MANDATORY\r\n- Nav / sidebar / menu links → getByRole('link', { name: '...' })\r\n- Form submit (no text) → page.locator('button[type=\"submit\"]').click()\r\n- Text inputs (with label) → page.getByLabel('FieldName').fill('value')\r\n- Text inputs (placeholder) → page.getByPlaceholder('placeholder').fill('value')\r\n- Dropdowns → page.getByLabel('Label').selectOption('value')\r\n- Checkboxes / radios → page.getByLabel('Label').check()\r\n- NEVER use getByText() to click a button — always use getByRole('button')\r\n\r\n━━━ NAVIGATION ━━━\r\nAlways use { waitUntil: 'networkidle' } with page.goto() so the page fully loads:\r\n await page.goto('https://example.com', { waitUntil: 'networkidle' });\r\n\r\n━━━ ANTI-PATTERNS — NEVER generate ━━━\r\n- .or() chains: page.getByRole(...).or(page.getByText(...))\r\n- .first(): page.getByText(...).first().click()\r\n- Full sentence as role name: { name: 'Verify user should be on Dashboard' }\r\n- Bare page.goto() without waitUntil: 'networkidle'\r\n\r\n━━━ ASSERTIONS GUIDE ━━━\r\nURL check: await expect(page).toHaveURL(/dashboard/)\r\nTitle check: await expect(page).toHaveTitle(/Dashboard/)\r\nElement visible: await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()\r\nVisible text: await expect(page.getByText('Welcome')).toBeVisible()\r\nInput value: await expect(page.getByLabel('Email')).toHaveValue('user@test.com')\r\nNot visible: await expect(page.getByText('Error')).not.toBeVisible()\r\n\r\n\"Verify user is on X page\" → await expect(page).toHaveURL(/x-page-path/)\r\n OR await expect(page.getByRole('heading', { name: 'X' })).toBeVisible()`;\r\n\r\nexport interface BatchStep {\r\n index: number;\r\n instruction: string;\r\n}\r\n\r\nexport function buildBatchGeneratePrompt(\r\n steps: BatchStep[],\r\n context: PageContext,\r\n): { system: string; user: string } {\r\n const stepsList = steps\r\n .map((s) => ` ${s.index}. \"${s.instruction}\"`)\r\n .join('\\n');\r\n\r\n const vars =\r\n Object.keys(context.variables).length > 0\r\n ? Object.entries(context.variables)\r\n .map(([k, v]) => ` {{${k}}} = ${v}`)\r\n .join('\\n')\r\n : ' None';\r\n\r\n const user = `Generate Playwright code for these ${steps.length} test steps.\r\n\r\nCurrent page:\r\n URL: ${context.url}\r\n Title: ${context.title}\r\n\r\nInteractive elements on page (use to choose the right selector):\r\n${context.interactiveElements || ' None captured'}\r\n\r\nRuntime variables:\r\n${vars}\r\n\r\nSteps to implement:\r\n${stepsList}\r\n\r\nReturn JSON:\r\n{\r\n \"results\": [\r\n { \"index\": 0, \"code\": \"await page.goto('...');\" },\r\n { \"index\": 1, \"code\": \"await page.getByLabel('Username').fill('Admin');\" }\r\n ]\r\n}\r\n\r\nReturn one result per step. Include ALL ${steps.length} steps.`;\r\n\r\n return { system: SYSTEM_PROMPT, user };\r\n}\r\n","import type { AIProvider, GeneratedSuite, PageContext } from '../types.js';\r\nimport { AIGeneratedSuiteSchema, AIOutlineSchema, AIStepsResponseSchema, ScreenshotAnalysisSchema, type ChatMessage, type ScreenshotAnalysis } from '../types.js';\r\nimport { buildStepToCodePrompt } from '../prompts/step-to-code.js';\r\nimport { buildStoryToSuitePrompt, buildOutlinePrompt, buildStepsPrompt } from '../prompts/story-to-suite.js';\r\nimport { buildSelfHealPrompt } from '../prompts/self-heal.js';\r\nimport { buildBatchGeneratePrompt } from '../prompts/batch-generate.js';\r\nimport { sanitizeGeneratedCode, extractJsonBlock, fixButtonSelectors } from '../../utils/sanitize.js';\r\nimport { ProviderError, ValidationError } from '../../utils/errors.js';\r\nimport { BatchResultSchema } from '../types.js';\r\nimport { stripCodeFences } from '../../utils/sanitize.js';\r\n\r\nexport interface BaseProviderConfig {\r\n model: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n temperature?: number;\r\n}\r\n\r\n/**\r\n * Abstract base for all AI providers.\r\n * Implements all AIProvider methods using prompt builders + abstract chat().\r\n * Subclasses only need to implement: chat() and optionally chatWithVision().\r\n */\r\nexport abstract class BaseProvider implements AIProvider {\r\n abstract readonly name: string;\r\n abstract readonly model: string;\r\n abstract readonly supportsVision: boolean;\r\n\r\n protected readonly timeoutMs: number;\r\n protected readonly maxRetries: number;\r\n protected readonly temperature: number;\r\n\r\n constructor(config: BaseProviderConfig) {\r\n this.timeoutMs = config.timeoutMs ?? 30_000;\r\n this.maxRetries = config.maxRetries ?? 2;\r\n this.temperature = config.temperature ?? 0.1;\r\n }\r\n\r\n /** Send a chat request. Must be implemented by each provider. */\r\n protected abstract chat(messages: ChatMessage[]): Promise<string>;\r\n\r\n /** Optional — implement in providers that support vision. */\r\n protected chatWithVision?(prompt: string, image: Buffer): Promise<string>;\r\n\r\n // ─── High-level AIProvider methods ───────────────────────────────────────\r\n\r\n async generateCode(instruction: string, context: PageContext): Promise<string> {\r\n const { system, user } = buildStepToCodePrompt(instruction, context);\r\n const raw = await this.chatWithRetry([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n const code = sanitizeGeneratedCode(raw);\r\n // Deterministic fix: rewrite getByText().click() → getByRole('button') when\r\n // the instruction explicitly mentions a button (prompt rule the AI often ignores)\r\n return fixButtonSelectors(instruction, code);\r\n }\r\n\r\n async generateTestSuite(story: string): Promise<GeneratedSuite> {\r\n // ── Two-pass approach for scalability ─────────────────────────────────────\r\n // Pass 1: generate suite outline (name + case names only, no steps)\r\n // → tiny response, never truncated regardless of project size\r\n // Pass 2: generate steps for each case in parallel\r\n // → each call is focused on one case, scales to unlimited cases\r\n //\r\n // Falls back to legacy single-pass if outline parse fails.\r\n\r\n try {\r\n return await this.generateTestSuiteTwoPass(story);\r\n } catch {\r\n // Fallback: single-pass (works well for small stories)\r\n return await this.generateTestSuiteSinglePass(story);\r\n }\r\n }\r\n\r\n private async generateTestSuiteTwoPass(story: string): Promise<GeneratedSuite> {\r\n // ── Pass 1: suite outline ──────────────────────────────────────────────────\r\n const outlinePrompt = buildOutlinePrompt(story);\r\n const outlineRaw = await this.chatWithRetry([\r\n { role: 'system', content: outlinePrompt.system },\r\n { role: 'user', content: outlinePrompt.user },\r\n ]);\r\n\r\n // extractJsonBlock handles preamble text (e.g. \"Here is the outline:\") that\r\n // models add despite being told to return only JSON.\r\n const outlineExtracted = extractJsonBlock(outlineRaw);\r\n const outlineJson = tryRepairJson(outlineExtracted) ?? outlineExtracted;\r\n const outlineParsed = AIOutlineSchema.safeParse(JSON.parse(outlineJson));\r\n if (!outlineParsed.success) {\r\n throw new ValidationError('Outline parse failed', 'outline', 'INVALID_OUTLINE');\r\n }\r\n const outline = outlineParsed.data;\r\n\r\n // ── Pass 2: steps per case in parallel (up to 5 concurrent) ───────────────\r\n const caseSteps = await runWithLimit(\r\n outline.cases.map((c) => async () => {\r\n const stepsPrompt = buildStepsPrompt(outline.name, c.name, c.description, story);\r\n const stepsRaw = await this.chatWithRetry([\r\n { role: 'system', content: stepsPrompt.system },\r\n { role: 'user', content: stepsPrompt.user },\r\n ]);\r\n const stepsExtracted = extractJsonBlock(stepsRaw);\r\n const stepsJson = tryRepairJson(stepsExtracted) ?? stepsExtracted;\r\n const stepsParsed = AIStepsResponseSchema.safeParse(JSON.parse(stepsJson));\r\n return stepsParsed.success ? stepsParsed.data.steps : [];\r\n }),\r\n 5, // max 5 parallel AI calls\r\n );\r\n\r\n // ── Assemble final GeneratedSuite ─────────────────────────────────────────\r\n return {\r\n name: outline.name,\r\n description: outline.description,\r\n tags: outline.tags,\r\n cases: outline.cases.map((c, i) => ({\r\n name: c.name,\r\n description: c.description,\r\n tags: c.tags,\r\n steps: (caseSteps[i] ?? []).map((s) => ({\r\n instruction: s.instruction,\r\n generatedCode: '',\r\n strategy: 'primary' as const,\r\n })),\r\n })),\r\n };\r\n }\r\n\r\n private async generateTestSuiteSinglePass(story: string): Promise<GeneratedSuite> {\r\n const { system, user } = buildStoryToSuitePrompt(story);\r\n const messages: ChatMessage[] = [\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ];\r\n\r\n let raw = await this.chatWithRetry(messages);\r\n\r\n for (let cont = 0; cont < 2; cont++) {\r\n const repaired = tryRepairJson(raw);\r\n try {\r\n return this.parseGeneratedSuite(repaired ?? raw);\r\n } catch (parseErr) {\r\n const trimmed = raw.trimEnd();\r\n const isTruncated = !trimmed.endsWith('}') && !trimmed.endsWith(']}');\r\n if (!isTruncated) throw parseErr;\r\n\r\n messages.push({ role: 'assistant', content: raw });\r\n messages.push({\r\n role: 'user',\r\n content: 'Your JSON was cut off. Continue the JSON exactly from where you stopped — output only the continuation, no preamble.',\r\n });\r\n raw += await this.chatWithRetry(messages);\r\n }\r\n }\r\n\r\n return this.parseGeneratedSuite(tryRepairJson(raw) ?? raw);\r\n }\r\n\r\n async healSelector(\r\n instruction: string,\r\n failedCode: string,\r\n error: string,\r\n context: PageContext,\r\n ): Promise<string> {\r\n const { system, user } = buildSelfHealPrompt(instruction, failedCode, error, context);\r\n const raw = await this.chatWithRetry([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n return sanitizeGeneratedCode(raw);\r\n }\r\n\r\n async batchGenerateCode(\r\n steps: Array<{ instruction: string; context: PageContext }>,\r\n ): Promise<string[]> {\r\n if (steps.length === 0) return [];\r\n\r\n const batchSteps = steps.map((s, i) => ({ index: i, instruction: s.instruction }));\r\n const { system, user } = buildBatchGeneratePrompt(batchSteps, steps[0].context);\r\n\r\n const raw = await this.chatWithRetry([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n\r\n const codes = await this.parseBatchResponse(raw, steps.length);\r\n // Apply deterministic button-selector fix per step\r\n return codes.map((code, i) => fixButtonSelectors(steps[i]?.instruction ?? '', code));\r\n }\r\n\r\n async analyzeScreenshot(\r\n screenshot: Buffer,\r\n instruction: string,\r\n ): Promise<{ x: number; y: number; action: string }> {\r\n if (!this.supportsVision || !this.chatWithVision) {\r\n throw new ProviderError(\r\n `Provider \"${this.name}\" does not support vision. ` +\r\n `Use Claude, GPT-4o, or Gemini for visual/coordinate-based healing.`,\r\n this.name,\r\n 'VISION_NOT_SUPPORTED',\r\n );\r\n }\r\n\r\n const prompt =\r\n `Identify the UI element to interact with for this step: \"${instruction}\"\\n` +\r\n `Return JSON: { \"x\": <pixels from left>, \"y\": <pixels from top>, \"action\": \"click|fill|hover\" }`;\r\n\r\n const raw = await this.chatWithVision(prompt, screenshot);\r\n return this.parseScreenshotAnalysis(raw);\r\n }\r\n\r\n /**\r\n * Set-of-Marks visual analysis — uses an annotated screenshot with numbered\r\n * colored boxes (Browser-Use technique) to identify the correct element and\r\n * return a precise Playwright selector + action.\r\n *\r\n * Unlike analyzeScreenshot (which returns pixel coordinates), this returns\r\n * executable Playwright code using a real selector — inspectable and committable.\r\n */\r\n async analyzeWithSoM(\r\n annotatedScreenshot: Buffer,\r\n elementMap: string,\r\n instruction: string,\r\n ): Promise<string> {\r\n if (!this.supportsVision || !this.chatWithVision) {\r\n throw new ProviderError(\r\n `Provider \"${this.name}\" does not support vision.`,\r\n this.name,\r\n 'VISION_NOT_SUPPORTED',\r\n );\r\n }\r\n\r\n const prompt =\r\n `You are a Playwright test automation expert analyzing an annotated browser screenshot.\\n\\n` +\r\n `Each interactive element on the page has been highlighted with a colored numbered box.\\n\\n` +\r\n `ELEMENT MAP (index → Playwright selector):\\n${elementMap}\\n\\n` +\r\n `INSTRUCTION: \"${instruction}\"\\n\\n` +\r\n `Look at the screenshot to find which numbered element best matches the instruction.\\n` +\r\n `Then return ONLY a single line of executable Playwright code using the selector from the element map.\\n\\n` +\r\n `Rules:\\n` +\r\n `- Return raw code only — no markdown, no explanation\\n` +\r\n `- Use the exact selector from the element map for the matching element\\n` +\r\n `- For click: selector.click()\\n` +\r\n `- For fill: selector.fill('value')\\n` +\r\n `- For assertion: await expect(selector).toBeVisible()\\n` +\r\n `- Always prefix with: await \\n\\n` +\r\n `Examples:\\n` +\r\n ` await page.getByRole('link', { name: 'Admin' }).click()\\n` +\r\n ` await page.getByPlaceholder('Username').fill('Admin')\\n` +\r\n ` await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()`;\r\n\r\n const raw = await this.chatWithVision(prompt, annotatedScreenshot);\r\n return sanitizeGeneratedCode(raw);\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n try {\r\n await this.chat([{ role: 'user', content: 'Reply with the single word: ready' }]);\r\n return { valid: true };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return { valid: false, error: msg };\r\n }\r\n }\r\n\r\n // ─── Internal helpers ─────────────────────────────────────────────────────\r\n\r\n protected async chatWithRetry(\r\n messages: ChatMessage[],\r\n maxRetries = this.maxRetries,\r\n ): Promise<string> {\r\n let lastError: Error | undefined;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n try {\r\n return await this.chat(messages);\r\n } catch (err) {\r\n lastError = err instanceof Error ? err : new Error(String(err));\r\n if (attempt < maxRetries) {\r\n // Exponential backoff: 1s, 2s\r\n await new Promise<void>((r) => setTimeout(r, 1000 * (attempt + 1)));\r\n }\r\n }\r\n }\r\n\r\n throw new ProviderError(\r\n `Provider \"${this.name}\" failed after ${maxRetries + 1} attempt(s): ${lastError?.message ?? 'Unknown error'}`,\r\n this.name,\r\n 'PROVIDER_EXHAUSTED',\r\n );\r\n }\r\n\r\n private parseGeneratedSuite(raw: string): GeneratedSuite {\r\n const extracted = extractJsonBlock(raw);\r\n const repaired = tryRepairJson(extracted) ?? extracted;\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(repaired);\r\n } catch {\r\n throw new ValidationError(\r\n `Provider \"${this.name}\" returned invalid JSON for test suite generation. ` +\r\n `Raw response: ${extracted.slice(0, 200)}`,\r\n 'generatedSuite',\r\n 'INVALID_SUITE_JSON',\r\n );\r\n }\r\n\r\n const result = AIGeneratedSuiteSchema.safeParse(parsed);\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `AI-generated suite has invalid structure:\\n${issues}`,\r\n 'generatedSuite',\r\n 'INVALID_SUITE_SCHEMA',\r\n );\r\n }\r\n\r\n // Convert from AI format (instruction-only steps) to GeneratedSuite format\r\n return {\r\n name: result.data.name,\r\n description: result.data.description,\r\n tags: result.data.tags,\r\n cases: result.data.cases.map((c) => ({\r\n name: c.name,\r\n description: c.description,\r\n tags: c.tags,\r\n steps: c.steps.map((s) => ({\r\n instruction: s.instruction,\r\n generatedCode: '', // generated in batch after suite creation\r\n strategy: 'primary' as const,\r\n })),\r\n })),\r\n };\r\n }\r\n\r\n private parseBatchResponse(raw: string, expectedCount: number): string[] {\r\n // Strip outer markdown fences the model may wrap around the JSON\r\n let stripped = stripCodeFences(raw);\r\n\r\n // Some models embed the JSON inside a larger explanation — extract the first {...} block\r\n const jsonMatch = stripped.match(/\\{[\\s\\S]*\\}/);\r\n if (jsonMatch) stripped = jsonMatch[0];\r\n\r\n const results = new Array<string>(expectedCount).fill('');\r\n\r\n // ── Attempt 1: JSON parse against BatchResultSchema ──────────────────────\r\n let jsonParsed = false;\r\n try {\r\n const parsed = JSON.parse(stripped) as unknown;\r\n const validated = BatchResultSchema.safeParse(parsed);\r\n if (validated.success) {\r\n jsonParsed = true;\r\n for (const item of validated.data.results) {\r\n if (item.index < expectedCount) {\r\n try {\r\n results[item.index] = sanitizeGeneratedCode(item.code);\r\n } catch {\r\n // Individual step failed sanitization — leave as empty, don't abort others\r\n }\r\n }\r\n }\r\n return results;\r\n }\r\n } catch {\r\n // JSON.parse failed — fall through to fallback parser\r\n }\r\n\r\n if (jsonParsed) return results;\r\n\r\n // ── Attempt 2: split by // STEP_N markers ─────────────────────────────\r\n const stepPattern = /\\/\\/\\s*STEP[_\\s]?(\\d+)\\s*\\n([\\s\\S]*?)(?=\\/\\/\\s*STEP[_\\s]?\\d+|$)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = stepPattern.exec(stripped)) !== null) {\r\n const idx = parseInt(match[1], 10);\r\n if (idx < expectedCount) {\r\n try {\r\n results[idx] = sanitizeGeneratedCode(match[2].trim());\r\n } catch {\r\n // leave as empty string\r\n }\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n private parseScreenshotAnalysis(raw: string): ScreenshotAnalysis {\r\n const stripped = stripCodeFences(raw);\r\n try {\r\n const parsed = JSON.parse(stripped) as unknown;\r\n const result = ScreenshotAnalysisSchema.safeParse(parsed);\r\n if (result.success) return result.data;\r\n } catch {\r\n // fall through\r\n }\r\n throw new ValidationError(\r\n `Could not parse screenshot analysis response: ${stripped.slice(0, 200)}`,\r\n 'screenshotAnalysis',\r\n 'INVALID_SCREENSHOT_ANALYSIS',\r\n );\r\n }\r\n}\r\n\r\n// ─── Concurrency limiter ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Runs an array of async tasks with a maximum concurrency limit.\r\n * Used for Pass 2 of two-pass suite generation to parallelise step calls\r\n * without flooding the AI provider rate limits.\r\n */\r\nasync function runWithLimit<T>(\r\n tasks: Array<() => Promise<T>>,\r\n limit: number,\r\n): Promise<T[]> {\r\n const results: T[] = new Array(tasks.length);\r\n let index = 0;\r\n\r\n async function worker(): Promise<void> {\r\n while (index < tasks.length) {\r\n const i = index++;\r\n results[i] = await tasks[i]();\r\n }\r\n }\r\n\r\n const workers = Array.from({ length: Math.min(limit, tasks.length) }, worker);\r\n await Promise.all(workers);\r\n return results;\r\n}\r\n\r\n// ─── JSON repair helper ───────────────────────────────────────────────────────\r\n\r\n/**\r\n * Attempts to repair a truncated JSON string by counting unclosed brackets/braces\r\n * and appending the necessary closing characters.\r\n * Returns the repaired string if repair succeeded, or null if not needed / not fixable.\r\n */\r\nfunction tryRepairJson(raw: string): string | null {\r\n const stripped = stripCodeFences(raw).trim();\r\n\r\n // Already valid — nothing to repair\r\n try { JSON.parse(stripped); return null; } catch { /* continue */ }\r\n\r\n const stack: string[] = [];\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (const ch of stripped) {\r\n if (escape) { escape = false; continue; }\r\n if (ch === '\\\\' && inString) { escape = true; continue; }\r\n if (ch === '\"') { inString = !inString; continue; }\r\n if (inString) continue;\r\n if (ch === '{' || ch === '[') { stack.push(ch === '{' ? '}' : ']'); }\r\n else if (ch === '}' || ch === ']') { stack.pop(); }\r\n }\r\n\r\n if (stack.length === 0) return null; // balanced but still invalid — structural error\r\n\r\n // Close any open string, then close all open brackets/braces\r\n let repaired = stripped;\r\n if (inString) repaired += '\"';\r\n repaired += stack.reverse().join('');\r\n\r\n try {\r\n JSON.parse(repaired);\r\n return repaired;\r\n } catch {\r\n return null; // repair didn't help\r\n }\r\n}\r\n","import Anthropic from '@anthropic-ai/sdk';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface AnthropicConfig extends BaseProviderConfig {\r\n apiKey: string;\r\n}\r\n\r\nexport class AnthropicProvider extends BaseProvider {\r\n readonly name = 'anthropic';\r\n readonly model: string;\r\n readonly supportsVision = true;\r\n\r\n private readonly client: Anthropic;\r\n\r\n constructor(config: AnthropicConfig) {\r\n super(config);\r\n this.model = config.model;\r\n this.client = new Anthropic({\r\n apiKey: config.apiKey,\r\n timeout: this.timeoutMs,\r\n maxRetries: 0,\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n const system = messages.find((m) => m.role === 'system')?.content;\r\n const userMessages = messages.filter((m) => m.role !== 'system');\r\n\r\n try {\r\n const response = await this.client.messages.create({\r\n model: this.model,\r\n max_tokens: 8192,\r\n temperature: this.temperature,\r\n system: system,\r\n messages: userMessages.map((m) => ({\r\n role: m.role as 'user' | 'assistant',\r\n content: m.content,\r\n })),\r\n });\r\n\r\n const block = response.content[0];\r\n if (!block || block.type !== 'text') {\r\n throw new ProviderError(\r\n 'Anthropic returned an empty or non-text response.',\r\n this.name,\r\n 'EMPTY_RESPONSE',\r\n );\r\n }\r\n return block.text;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new ProviderError(`Anthropic API error: ${msg}`, this.name, 'API_ERROR');\r\n }\r\n }\r\n\r\n protected async chatWithVision(prompt: string, image: Buffer): Promise<string> {\r\n try {\r\n const response = await this.client.messages.create({\r\n model: this.model,\r\n max_tokens: 512,\r\n messages: [\r\n {\r\n role: 'user',\r\n content: [\r\n {\r\n type: 'image',\r\n source: {\r\n type: 'base64',\r\n media_type: 'image/png',\r\n data: image.toString('base64'),\r\n },\r\n },\r\n { type: 'text', text: prompt },\r\n ],\r\n },\r\n ],\r\n });\r\n\r\n const block = response.content[0];\r\n if (!block || block.type !== 'text') {\r\n throw new ProviderError('Anthropic vision returned empty response.', this.name);\r\n }\r\n return block.text;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `Anthropic vision error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'VISION_ERROR',\r\n );\r\n }\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.client.apiKey) {\r\n return { valid: false, error: 'ANTHROPIC_API_KEY is not set' };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import OpenAI from 'openai';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface OpenAIConfig extends BaseProviderConfig {\r\n apiKey: string;\r\n}\r\n\r\nexport class OpenAIProvider extends BaseProvider {\r\n readonly name = 'openai';\r\n readonly model: string;\r\n readonly supportsVision = true;\r\n\r\n private readonly client: OpenAI;\r\n\r\n constructor(config: OpenAIConfig) {\r\n super(config);\r\n this.model = config.model;\r\n this.client = new OpenAI({\r\n apiKey: config.apiKey,\r\n timeout: this.timeoutMs,\r\n maxRetries: 0,\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\r\n temperature: this.temperature,\r\n max_tokens: 8192,\r\n });\r\n\r\n const content = response.choices[0]?.message?.content;\r\n if (!content) {\r\n throw new ProviderError('OpenAI returned an empty response.', this.name, 'EMPTY_RESPONSE');\r\n }\r\n return content;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `OpenAI API error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'API_ERROR',\r\n );\r\n }\r\n }\r\n\r\n protected async chatWithVision(prompt: string, image: Buffer): Promise<string> {\r\n try {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n max_tokens: 512,\r\n messages: [\r\n {\r\n role: 'user',\r\n content: [\r\n {\r\n type: 'image_url',\r\n image_url: { url: `data:image/png;base64,${image.toString('base64')}` },\r\n },\r\n { type: 'text', text: prompt },\r\n ],\r\n },\r\n ],\r\n });\r\n\r\n const content = response.choices[0]?.message?.content;\r\n if (!content) {\r\n throw new ProviderError('OpenAI vision returned empty response.', this.name);\r\n }\r\n return content;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `OpenAI vision error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'VISION_ERROR',\r\n );\r\n }\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.client.apiKey) {\r\n return { valid: false, error: 'OPENAI_API_KEY is not set' };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import { GoogleGenerativeAI } from '@google/generative-ai';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface GoogleConfig extends BaseProviderConfig {\r\n apiKey: string;\r\n}\r\n\r\nexport class GoogleProvider extends BaseProvider {\r\n readonly name = 'google';\r\n readonly model: string;\r\n readonly supportsVision = true;\r\n\r\n private readonly genAI: GoogleGenerativeAI;\r\n\r\n constructor(config: GoogleConfig) {\r\n super(config);\r\n this.model = config.model;\r\n this.genAI = new GoogleGenerativeAI(config.apiKey);\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n const systemMsg = messages.find((m) => m.role === 'system');\r\n const userMessages = messages.filter((m) => m.role !== 'system');\r\n\r\n // Detect JSON-only calls (suite generation, step generation, healing).\r\n // For these, use responseMimeType:'application/json' so Gemini is forced\r\n // to output valid JSON with NO preamble text — prevents INVALID_SUITE_JSON errors.\r\n const lastUserMsg = userMessages.at(-1)?.content ?? '';\r\n const wantsJson =\r\n lastUserMsg.includes('Return only the JSON') ||\r\n lastUserMsg.includes('Return ONLY valid JSON') ||\r\n lastUserMsg.includes('return only the JSON') ||\r\n lastUserMsg.includes('Return only a single line') ||\r\n (systemMsg?.content?.includes('Return ONLY valid JSON') ?? false);\r\n\r\n const gemini = this.genAI.getGenerativeModel({\r\n model: this.model,\r\n systemInstruction: systemMsg?.content,\r\n generationConfig: {\r\n temperature: this.temperature,\r\n maxOutputTokens: 8192,\r\n ...(wantsJson ? { responseMimeType: 'application/json' } : {}),\r\n },\r\n });\r\n\r\n // Build conversation history for multi-turn\r\n const history = userMessages.slice(0, -1).map((m) => ({\r\n role: m.role === 'assistant' ? 'model' : 'user',\r\n parts: [{ text: m.content }],\r\n }));\r\n\r\n const lastMsg = userMessages.at(-1);\r\n if (!lastMsg) {\r\n throw new ProviderError('No user message provided.', this.name);\r\n }\r\n\r\n const chat = gemini.startChat({ history });\r\n const result = await chat.sendMessage(lastMsg.content);\r\n const text = result.response.text();\r\n\r\n if (!text) {\r\n throw new ProviderError('Google Gemini returned empty response.', this.name, 'EMPTY_RESPONSE');\r\n }\r\n return text;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `Google Gemini error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'API_ERROR',\r\n );\r\n }\r\n }\r\n\r\n protected async chatWithVision(prompt: string, image: Buffer): Promise<string> {\r\n try {\r\n const gemini = this.genAI.getGenerativeModel({ model: this.model });\r\n const result = await gemini.generateContent([\r\n prompt,\r\n { inlineData: { data: image.toString('base64'), mimeType: 'image/png' } },\r\n ]);\r\n return result.response.text();\r\n } catch (err) {\r\n throw new ProviderError(\r\n `Google vision error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'VISION_ERROR',\r\n );\r\n }\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.genAI) {\r\n return { valid: false, error: 'GOOGLE_API_KEY is not set' };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import OpenAI from 'openai';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface AzureOpenAIConfig extends BaseProviderConfig {\r\n apiKey: string;\r\n endpoint: string;\r\n deployment: string;\r\n apiVersion?: string;\r\n}\r\n\r\nexport class AzureOpenAIProvider extends BaseProvider {\r\n readonly name = 'azure-openai';\r\n readonly model: string;\r\n readonly supportsVision = true;\r\n\r\n private readonly client: OpenAI;\r\n\r\n constructor(config: AzureOpenAIConfig) {\r\n super(config);\r\n this.model = config.deployment; // Azure uses deployment name as model\r\n this.client = new OpenAI({\r\n apiKey: config.apiKey,\r\n baseURL: `${config.endpoint}/openai/deployments/${config.deployment}`,\r\n defaultQuery: { 'api-version': config.apiVersion ?? '2024-10-21' },\r\n defaultHeaders: { 'api-key': config.apiKey },\r\n timeout: this.timeoutMs,\r\n maxRetries: 0,\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\r\n temperature: this.temperature,\r\n max_tokens: 8192,\r\n });\r\n\r\n const content = response.choices[0]?.message?.content;\r\n if (!content) {\r\n throw new ProviderError('Azure OpenAI returned empty response.', this.name, 'EMPTY_RESPONSE');\r\n }\r\n return content;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `Azure OpenAI error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'API_ERROR',\r\n );\r\n }\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.client.apiKey) {\r\n return { valid: false, error: 'AZURE_OPENAI_API_KEY is not set' };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import {\r\n BedrockRuntimeClient,\r\n InvokeModelCommand,\r\n} from '@aws-sdk/client-bedrock-runtime';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface BedrockConfig extends BaseProviderConfig {\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n sessionToken?: string;\r\n region: string;\r\n}\r\n\r\ninterface ClaudeBedrockRequest {\r\n anthropic_version: string;\r\n max_tokens: number;\r\n temperature?: number;\r\n system?: string;\r\n messages: Array<{ role: string; content: string }>;\r\n}\r\n\r\ninterface ClaudeBedrockResponse {\r\n content: Array<{ type: string; text?: string }>;\r\n}\r\n\r\nexport class BedrockProvider extends BaseProvider {\r\n readonly name = 'bedrock';\r\n readonly model: string;\r\n readonly supportsVision = false;\r\n\r\n private readonly client: BedrockRuntimeClient;\r\n\r\n constructor(config: BedrockConfig) {\r\n super(config);\r\n this.model = config.model;\r\n this.client = new BedrockRuntimeClient({\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n ...(config.sessionToken ? { sessionToken: config.sessionToken } : {}),\r\n },\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n // Support Claude models on Bedrock (most common)\r\n const isClaudeModel = this.model.includes('claude');\r\n\r\n if (isClaudeModel) {\r\n return await this.chatClaude(messages);\r\n }\r\n\r\n // Fallback for non-Claude models — use Claude format as default\r\n return await this.chatClaude(messages);\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n throw new ProviderError(\r\n `Bedrock error: ${err instanceof Error ? err.message : String(err)}`,\r\n this.name,\r\n 'API_ERROR',\r\n );\r\n }\r\n }\r\n\r\n private async chatClaude(messages: ChatMessage[]): Promise<string> {\r\n const system = messages.find((m) => m.role === 'system')?.content;\r\n const userMessages = messages.filter((m) => m.role !== 'system');\r\n\r\n const body: ClaudeBedrockRequest = {\r\n anthropic_version: 'bedrock-2023-05-31',\r\n max_tokens: 8192,\r\n temperature: this.temperature,\r\n messages: userMessages.map((m) => ({ role: m.role, content: m.content })),\r\n };\r\n if (system) body.system = system;\r\n\r\n const command = new InvokeModelCommand({\r\n modelId: this.model,\r\n body: JSON.stringify(body),\r\n contentType: 'application/json',\r\n accept: 'application/json',\r\n });\r\n\r\n const response = await this.client.send(command);\r\n const raw = new TextDecoder().decode(response.body);\r\n const parsed = JSON.parse(raw) as ClaudeBedrockResponse;\r\n\r\n const text = parsed.content[0]?.text;\r\n if (!text) {\r\n throw new ProviderError('Bedrock returned empty response.', this.name, 'EMPTY_RESPONSE');\r\n }\r\n return text;\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.client.config.credentials) {\r\n return { valid: false, error: 'AWS credentials are not configured' };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import OpenAI from 'openai';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface OpenAICompatibleConfig extends BaseProviderConfig {\r\n apiKey: string;\r\n baseUrl: string;\r\n}\r\n\r\n/**\r\n * Base provider for OpenAI-compatible APIs.\r\n * Used directly for OpenAI, and extended by: DeepSeek, Groq, Together,\r\n * Qwen, Perplexity, Ollama, and custom endpoints.\r\n */\r\nexport class OpenAICompatibleProvider extends BaseProvider {\r\n readonly name: string;\r\n readonly model: string;\r\n readonly supportsVision = false;\r\n\r\n protected readonly client: OpenAI;\r\n\r\n constructor(\r\n name: string,\r\n config: OpenAICompatibleConfig,\r\n ) {\r\n super(config);\r\n this.name = name;\r\n this.model = config.model;\r\n this.client = new OpenAI({\r\n apiKey: config.apiKey,\r\n baseURL: config.baseUrl,\r\n timeout: this.timeoutMs,\r\n maxRetries: 0, // we handle retries in BaseProvider\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\r\n temperature: this.temperature,\r\n max_tokens: 8192,\r\n });\r\n\r\n const content = response.choices[0]?.message?.content;\r\n if (!content) {\r\n throw new ProviderError(\r\n `Provider \"${this.name}\" returned an empty response.`,\r\n this.name,\r\n 'EMPTY_RESPONSE',\r\n );\r\n }\r\n return content;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new ProviderError(\r\n `Provider \"${this.name}\" API error: ${msg}`,\r\n this.name,\r\n 'API_ERROR',\r\n );\r\n }\r\n }\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n if (!this.client.apiKey || this.client.apiKey === 'none') {\r\n return { valid: false, error: `API key is not configured for provider \"${this.name}\"` };\r\n }\r\n return super.validate();\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface DeepSeekConfig {\r\n apiKey: string;\r\n model?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class DeepSeekProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'deepseek';\r\n\r\n constructor(config: DeepSeekConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: 'https://api.deepseek.com/v1',\r\n model: config.model ?? 'deepseek-chat',\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('deepseek', full);\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface GroqConfig {\r\n apiKey: string;\r\n model?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class GroqProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'groq';\r\n\r\n constructor(config: GroqConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: 'https://api.groq.com/openai/v1',\r\n model: config.model ?? 'llama-3.3-70b-versatile',\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('groq', full);\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface TogetherConfig {\r\n apiKey: string;\r\n model?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class TogetherProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'together';\r\n\r\n constructor(config: TogetherConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: 'https://api.together.xyz/v1',\r\n model: config.model ?? 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('together', full);\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface QwenConfig {\r\n apiKey: string;\r\n model?: string;\r\n baseUrl?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class QwenProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'qwen';\r\n\r\n constructor(config: QwenConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: config.baseUrl ?? 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',\r\n model: config.model ?? 'qwen-max',\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('qwen', full);\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface PerplexityConfig {\r\n apiKey: string;\r\n model?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class PerplexityProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'perplexity';\r\n\r\n constructor(config: PerplexityConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: 'https://api.perplexity.ai',\r\n model: config.model ?? 'sonar-pro',\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('perplexity', full);\r\n }\r\n}\r\n","/**\r\n * Ollama provider — locally-hosted LLMs via the Ollama REST API.\r\n *\r\n * Ollama exposes an OpenAI-compatible /v1 endpoint so we extend\r\n * OpenAICompatibleProvider. Key differences from cloud providers:\r\n *\r\n * 1. No API key required (we pass \"ollama\" as a dummy value)\r\n * 2. max_tokens is omitted — each model has its own context limit and\r\n * Ollama returns an error if the requested value exceeds it\r\n * 3. validate() skips the API-key check and just pings the server\r\n * 4. Default timeout is 120 s — local inference is much slower than APIs\r\n *\r\n * Supported models (examples):\r\n * llama3.3, llama3.2, llama3.1, llama3.2:1b, llama3.2:3b\r\n * mistral, mistral-nemo, mistral-small\r\n * phi4, phi3.5, phi3, phi3:mini\r\n * gemma3, gemma2, gemma2:2b\r\n * qwen2.5, qwen2.5-coder, qwen2.5:7b\r\n * deepseek-r1, deepseek-r1:8b\r\n * codellama, starcoder2\r\n * nomic-embed-text (embedding — not suitable for this use case)\r\n *\r\n * Run any model with: `ollama pull <model>` then set OLLAMA_MODEL=<model>\r\n */\r\nimport OpenAI from 'openai';\r\nimport { BaseProvider, type BaseProviderConfig } from './base.js';\r\nimport type { ChatMessage } from '../types.js';\r\nimport { ProviderError } from '../../utils/errors.js';\r\n\r\nexport interface OllamaConfig extends Omit<BaseProviderConfig, never> {\r\n model?: string;\r\n baseUrl?: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class OllamaProvider extends BaseProvider {\r\n override readonly name = 'ollama';\r\n readonly model: string;\r\n readonly supportsVision = false;\r\n readonly baseUrl: string;\r\n\r\n private readonly client: OpenAI;\r\n\r\n constructor(config: OllamaConfig = {}) {\r\n super({\r\n model: config.model ?? 'llama3.3',\r\n timeoutMs: config.timeoutMs ?? 120_000,\r\n maxRetries: config.maxRetries ?? 1,\r\n });\r\n this.model = config.model ?? 'llama3.3';\r\n this.baseUrl = `${config.baseUrl ?? 'http://localhost:11434'}/v1`;\r\n this.client = new OpenAI({\r\n apiKey: 'ollama', // Ollama ignores the key — required field for the SDK only\r\n baseURL: this.baseUrl,\r\n timeout: this.timeoutMs,\r\n maxRetries: 0,\r\n });\r\n }\r\n\r\n protected async chat(messages: ChatMessage[]): Promise<string> {\r\n try {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\r\n temperature: this.temperature,\r\n // NOTE: max_tokens intentionally omitted for Ollama.\r\n // Each model has its own context window and Ollama will error if the\r\n // requested value exceeds the model's limit (common with phi3:mini, gemma2:2b).\r\n // Omitting it lets Ollama use the full context window automatically.\r\n });\r\n\r\n const content = response.choices[0]?.message?.content;\r\n if (!content) {\r\n throw new ProviderError('Ollama returned an empty response.', this.name, 'EMPTY_RESPONSE');\r\n }\r\n return content;\r\n } catch (err) {\r\n if (err instanceof ProviderError) throw err;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n\r\n // Give actionable help for the most common Ollama errors\r\n if (msg.includes('ECONNREFUSED') || msg.includes('fetch failed')) {\r\n throw new ProviderError(\r\n `Cannot connect to Ollama at ${this.baseUrl}. ` +\r\n `Make sure Ollama is running: start it with \"ollama serve\" and confirm it's on port 11434.`,\r\n this.name,\r\n 'CONNECTION_REFUSED',\r\n );\r\n }\r\n if (msg.includes('model') && (msg.includes('not found') || msg.includes('pull'))) {\r\n throw new ProviderError(\r\n `Ollama model \"${this.model}\" is not available locally. ` +\r\n `Pull it first: ollama pull ${this.model}`,\r\n this.name,\r\n 'MODEL_NOT_FOUND',\r\n );\r\n }\r\n throw new ProviderError(`Ollama error: ${msg}`, this.name, 'API_ERROR');\r\n }\r\n }\r\n\r\n override async validate(): Promise<{ valid: boolean; error?: string }> {\r\n // Skip the API-key check from OpenAICompatibleProvider — Ollama needs none.\r\n // Just attempt a tiny real call to confirm the server is reachable and the model is loaded.\r\n try {\r\n await this.chat([{ role: 'user', content: 'Reply with the single word: ready' }]);\r\n return { valid: true };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return { valid: false, error: msg };\r\n }\r\n }\r\n}\r\n","import { OpenAICompatibleProvider, type OpenAICompatibleConfig } from './openai-compatible.js';\r\n\r\nexport interface CustomConfig {\r\n apiKey: string;\r\n baseUrl: string;\r\n model: string;\r\n timeoutMs?: number;\r\n maxRetries?: number;\r\n}\r\n\r\nexport class CustomProvider extends OpenAICompatibleProvider {\r\n override readonly name = 'custom';\r\n\r\n constructor(config: CustomConfig) {\r\n const full: OpenAICompatibleConfig = {\r\n apiKey: config.apiKey,\r\n baseUrl: config.baseUrl,\r\n model: config.model,\r\n timeoutMs: config.timeoutMs,\r\n maxRetries: config.maxRetries,\r\n };\r\n super('custom', full);\r\n }\r\n}\r\n","/**\r\n * Provider Router — reads validated env config and returns the correct AIProvider.\r\n * Also exposes top-level helpers used by the CLI (generate command).\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport type { AIProvider } from './types.js';\r\nimport { validateEnv } from '../utils/env.js';\r\nimport { ConfigError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { SmartRouter } from './smart-router.js';\r\nimport { CodeCache } from './code-cache.js';\r\nimport { createCase, listCasePaths, readCase, updateCase } from '../storage/case-store.js';\r\nimport { createSuite } from '../storage/suite-store.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\nimport { resolveVariables } from '../storage/variable-store.js';\r\nimport { toSlug } from '../utils/sanitize.js';\r\nimport { detectStepType } from '../engine/step-type-detector.js';\r\nimport type { GeneratedSuite } from '../types/ai.js';\r\n\r\nconst logger = createChildLogger('router');\r\n\r\n// ─── Provider factory ─────────────────────────────────────────────────────────\r\n\r\nexport interface ProviderOptions {\r\n temperature?: number;\r\n}\r\n\r\nexport function createProvider(overrideProvider?: string, options?: ProviderOptions): AIProvider {\r\n const env = validateEnv();\r\n const providerName = overrideProvider ?? String(env.AI_PROVIDER);\r\n const timeoutMs = (env.AI_TIMEOUT as number) * 1000;\r\n const maxRetries = env.AI_MAX_RETRIES as number;\r\n const temperature = options?.temperature;\r\n\r\n switch (providerName) {\r\n case 'anthropic': {\r\n const { AnthropicProvider } = require('./providers/anthropic.js') as typeof import('./providers/anthropic.js');\r\n return new AnthropicProvider({\r\n apiKey: String(env.ANTHROPIC_API_KEY ?? ''),\r\n model: String(env.ANTHROPIC_MODEL ?? 'claude-sonnet-4-20250514'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'openai': {\r\n const { OpenAIProvider } = require('./providers/openai.js') as typeof import('./providers/openai.js');\r\n return new OpenAIProvider({\r\n apiKey: String(env.OPENAI_API_KEY ?? ''),\r\n model: String(env.OPENAI_MODEL ?? 'gpt-4o'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'google': {\r\n const { GoogleProvider } = require('./providers/google.js') as typeof import('./providers/google.js');\r\n return new GoogleProvider({\r\n apiKey: String(env.GOOGLE_API_KEY ?? ''),\r\n model: String(env.GOOGLE_MODEL ?? 'gemini-2.5-flash'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'azure-openai': {\r\n const { AzureOpenAIProvider } = require('./providers/azure-openai.js') as typeof import('./providers/azure-openai.js');\r\n return new AzureOpenAIProvider({\r\n apiKey: String(env.AZURE_OPENAI_API_KEY ?? ''),\r\n endpoint: String(env.AZURE_OPENAI_ENDPOINT ?? ''),\r\n deployment: String(env.AZURE_OPENAI_DEPLOYMENT ?? ''),\r\n apiVersion: String(env.AZURE_OPENAI_API_VERSION ?? '2024-10-21'),\r\n model: String(env.AZURE_OPENAI_DEPLOYMENT ?? ''),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'bedrock': {\r\n const { BedrockProvider } = require('./providers/bedrock.js') as typeof import('./providers/bedrock.js');\r\n return new BedrockProvider({\r\n accessKeyId: String(env.AWS_ACCESS_KEY_ID ?? ''),\r\n secretAccessKey: String(env.AWS_SECRET_ACCESS_KEY ?? ''),\r\n ...(env.AWS_SESSION_TOKEN ? { sessionToken: String(env.AWS_SESSION_TOKEN) } : {}),\r\n region: String(env.AWS_REGION ?? 'us-east-1'),\r\n model: String(env.BEDROCK_MODEL ?? 'anthropic.claude-sonnet-4-20250514-v1:0'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'deepseek': {\r\n const { DeepSeekProvider } = require('./providers/deepseek.js') as typeof import('./providers/deepseek.js');\r\n return new DeepSeekProvider({\r\n apiKey: String(env.DEEPSEEK_API_KEY ?? ''),\r\n model: String(env.DEEPSEEK_MODEL ?? 'deepseek-chat'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'groq': {\r\n const { GroqProvider } = require('./providers/groq.js') as typeof import('./providers/groq.js');\r\n return new GroqProvider({\r\n apiKey: String(env.GROQ_API_KEY ?? ''),\r\n model: String(env.GROQ_MODEL ?? 'llama-3.3-70b-versatile'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'together': {\r\n const { TogetherProvider } = require('./providers/together.js') as typeof import('./providers/together.js');\r\n return new TogetherProvider({\r\n apiKey: String(env.TOGETHER_API_KEY ?? ''),\r\n model: String(env.TOGETHER_MODEL ?? 'meta-llama/Llama-3.3-70B-Instruct-Turbo'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'qwen': {\r\n const { QwenProvider } = require('./providers/qwen.js') as typeof import('./providers/qwen.js');\r\n return new QwenProvider({\r\n apiKey: String(env.QWEN_API_KEY ?? ''),\r\n model: String(env.QWEN_MODEL ?? 'qwen-max'),\r\n baseUrl: env.QWEN_BASE_URL as string | undefined,\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'perplexity': {\r\n const { PerplexityProvider } = require('./providers/perplexity.js') as typeof import('./providers/perplexity.js');\r\n return new PerplexityProvider({\r\n apiKey: String(env.PERPLEXITY_API_KEY ?? ''),\r\n model: String(env.PERPLEXITY_MODEL ?? 'sonar-pro'),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'ollama': {\r\n const { OllamaProvider } = require('./providers/ollama.js') as typeof import('./providers/ollama.js');\r\n return new OllamaProvider({\r\n model: String(env.OLLAMA_MODEL ?? 'llama3.3'),\r\n baseUrl: env.OLLAMA_BASE_URL as string | undefined,\r\n // Local LLMs are much slower than cloud APIs — enforce a 2-minute floor\r\n // regardless of what AI_TIMEOUT is set to (default 30 s is far too short).\r\n timeoutMs: Math.max(timeoutMs, 120_000),\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n case 'custom': {\r\n const { CustomProvider } = require('./providers/custom.js') as typeof import('./providers/custom.js');\r\n return new CustomProvider({\r\n apiKey: String(env.CUSTOM_API_KEY ?? ''),\r\n baseUrl: String(env.CUSTOM_BASE_URL ?? ''),\r\n model: String(env.CUSTOM_MODEL ?? ''),\r\n timeoutMs,\r\n maxRetries,\r\n ...(temperature !== undefined ? { temperature } : {}),\r\n });\r\n }\r\n default:\r\n throw new ConfigError(\r\n `Unknown AI provider: \"${providerName}\". ` +\r\n `Supported: anthropic, openai, google, azure-openai, bedrock, deepseek, groq, together, qwen, perplexity, ollama, custom`,\r\n 'UNKNOWN_PROVIDER',\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Creates a SmartRouter instance with the configured primary (and optional fast) provider.\r\n */\r\nexport function createSmartRouter(rootDir?: string): SmartRouter {\r\n const env = validateEnv();\r\n const primary = createProvider();\r\n\r\n let fast: AIProvider | undefined;\r\n if (env.AI_TIERED_ENABLED) {\r\n const fastProviderName = env.AI_TIERED_FAST_PROVIDER as string | undefined;\r\n if (fastProviderName) {\r\n try {\r\n fast = createProvider(fastProviderName);\r\n logger.info({ fast: fastProviderName, primary: String(env.AI_PROVIDER) }, 'Tiered mode active');\r\n } catch (err) {\r\n logger.warn({ err }, 'Failed to create fast provider — tiered mode disabled');\r\n }\r\n }\r\n }\r\n\r\n const cachePath = rootDir\r\n ? path.join(rootDir, 'results', '.code-cache.json')\r\n : undefined;\r\n\r\n const cache = new CodeCache(cachePath);\r\n\r\n return new SmartRouter({ primaryProvider: primary, fastProvider: fast, cache });\r\n}\r\n\r\n// ─── CLI-level helper: generate suite from story ─────────────────────────────\r\n\r\nexport interface GenerateOptions {\r\n rootDir: string;\r\n outputDir: string;\r\n suiteName?: string;\r\n type?: 'ui' | 'api';\r\n}\r\n\r\nexport async function generateSuiteFromStory(\r\n story: string,\r\n options: GenerateOptions,\r\n): Promise<{ suiteId: string; suiteName: string }> {\r\n const provider = createProvider();\r\n\r\n logger.info({ provider: provider.name, model: provider.model }, 'Generating suite from story');\r\n\r\n const generated: GeneratedSuite = await provider.generateTestSuite(story);\r\n\r\n const suiteName = options.suiteName ?? generated.name;\r\n const { suiteDir, suiteId } = await createSuite(options.outputDir, {\r\n name: suiteName,\r\n description: generated.description,\r\n tags: generated.tags,\r\n type: options.type ?? 'ui',\r\n });\r\n\r\n logger.info({ suiteDir, suiteId, cases: generated.cases.length }, 'Suite directory created');\r\n\r\n // Save each generated case with its plain-English steps\r\n for (const genCase of generated.cases) {\r\n await createCase(suiteDir, {\r\n name: genCase.name,\r\n description: genCase.description,\r\n tags: genCase.tags,\r\n priority: 'medium',\r\n steps: genCase.steps.map((s, idx) => ({\r\n id: `step-${idx + 1}`,\r\n order: idx + 1,\r\n instruction: s.instruction,\r\n generatedCode: s.generatedCode || '',\r\n strategy: s.strategy ?? 'primary',\r\n stepType: detectStepType(s.instruction),\r\n lastHealed: null,\r\n })),\r\n });\r\n }\r\n\r\n // ── Auto-generate code for all steps ─────────────────────────────────────\r\n logger.info({ suiteId, cases: generated.cases.length }, 'Auto-generating code for all steps');\r\n\r\n try {\r\n const config = await readConfig(options.rootDir);\r\n const variables = await resolveVariables(options.rootDir).catch(() => ({}));\r\n const router = createSmartRouter(options.rootDir);\r\n\r\n const casePaths = await listCasePaths(suiteDir);\r\n\r\n for (const casePath of casePaths) {\r\n const tc = await readCase(casePath);\r\n const emptySteps = tc.steps.filter((s) => !s.generatedCode.trim());\r\n if (emptySteps.length === 0) continue;\r\n\r\n const batchSteps = emptySteps.map((s) => ({\r\n instruction: s.instruction,\r\n context: {\r\n url: config.baseUrl,\r\n title: '',\r\n interactiveElements: '',\r\n htmlSnapshot: '',\r\n previousSteps: tc.steps\r\n .filter((ps) => ps.order < s.order && ps.generatedCode)\r\n .map((ps) => ({ instruction: ps.instruction, code: ps.generatedCode })),\r\n variables,\r\n },\r\n }));\r\n\r\n const results = await router.batchGenerate(batchSteps);\r\n const codeMap = new Map(emptySteps.map((s, i) => [s.id, results[i]]));\r\n let codeGenCount = 0;\r\n\r\n const updatedSteps = tc.steps.map((s) => {\r\n const r = codeMap.get(s.id);\r\n if (r && r.code.trim()) {\r\n codeGenCount++;\r\n return { ...s, generatedCode: r.code, strategy: r.strategy };\r\n }\r\n return s;\r\n });\r\n\r\n if (codeGenCount > 0) {\r\n await updateCase(casePath, { steps: updatedSteps });\r\n logger.info({ caseName: tc.name, generated: codeGenCount, total: tc.steps.length }, 'Code generated for case');\r\n }\r\n }\r\n\r\n await router.getCache().persist();\r\n logger.info({ suiteId }, 'Auto code generation complete');\r\n } catch (codeGenErr) {\r\n // Code generation failure is non-fatal — steps still have instructions\r\n logger.warn({ err: codeGenErr, suiteId }, 'Auto code generation failed — steps saved without code');\r\n }\r\n\r\n // Save the generated suite info for reference\r\n const reportPath = path.join(options.rootDir, 'results', `generated-suite-${toSlug(suiteName)}.json`);\r\n await fs.ensureDir(path.dirname(reportPath));\r\n await fs.writeJson(reportPath, { story, generated, suiteDir, suiteId }, { spaces: 2 });\r\n\r\n logger.info({ reportPath, suiteId }, 'Generation complete');\r\n return { suiteId, suiteName };\r\n}\r\n\r\n// ─── Bulk generation ───────────────────────────────────────────────────────────\r\n\r\nexport interface BulkStoryItem {\r\n story: string;\r\n suiteName?: string;\r\n}\r\n\r\nexport interface BulkProgressEvent {\r\n jobId: string;\r\n total: number;\r\n completed: number;\r\n failed: number;\r\n currentIndex: number;\r\n currentStory: string;\r\n}\r\n\r\nexport interface BulkDoneEvent {\r\n jobId: string;\r\n total: number;\r\n completed: number;\r\n failed: number;\r\n failedItems: Array<{ index: number; story: string; error: string }>;\r\n}\r\n\r\ninterface WsBroadcaster {\r\n broadcast(event: string, data: unknown): void;\r\n}\r\n\r\n/**\r\n * Generates test suites from multiple user stories in a controlled queue.\r\n *\r\n * - Processes stories with a concurrency limit (default 3) to avoid API rate limits\r\n * - Adds a 300 ms delay between stories to stay under per-minute quotas\r\n * - Broadcasts WebSocket progress events so the UI can show a live progress bar\r\n * - Individual failures are logged and skipped — the batch continues\r\n */\r\nexport async function generateSuitesFromStories(\r\n stories: BulkStoryItem[],\r\n options: GenerateOptions,\r\n ws?: WsBroadcaster,\r\n concurrency = 3,\r\n): Promise<BulkDoneEvent> {\r\n const { randomUUID } = await import('crypto');\r\n const jobId = randomUUID();\r\n const total = stories.length;\r\n let completed = 0;\r\n let failed = 0;\r\n const failedItems: BulkDoneEvent['failedItems'] = [];\r\n\r\n ws?.broadcast('story:bulk-start', { jobId, total });\r\n logger.info({ jobId, total, concurrency }, 'Bulk story generation started');\r\n\r\n // Semaphore for concurrency control\r\n let active = 0;\r\n const queue = [...stories.entries()]; // [index, item]\r\n const results: Promise<void>[] = [];\r\n\r\n async function processNext(): Promise<void> {\r\n while (queue.length > 0) {\r\n const entry = queue.shift();\r\n if (!entry) break;\r\n const [index, item] = entry;\r\n\r\n ws?.broadcast('story:bulk-progress', {\r\n jobId, total, completed, failed,\r\n currentIndex: index,\r\n currentStory: item.story.slice(0, 80),\r\n } satisfies BulkProgressEvent);\r\n\r\n try {\r\n await generateSuiteFromStory(item.story, {\r\n rootDir: options.rootDir,\r\n outputDir: options.outputDir,\r\n suiteName: item.suiteName,\r\n });\r\n completed++;\r\n logger.info({ jobId, index, completed, total }, 'Story processed');\r\n } catch (err) {\r\n failed++;\r\n const error = err instanceof Error ? err.message : String(err);\r\n failedItems.push({ index, story: item.story.slice(0, 120), error });\r\n logger.warn({ jobId, index, error }, 'Story generation failed — continuing batch');\r\n }\r\n\r\n // Broadcast updated progress after each story\r\n ws?.broadcast('story:bulk-progress', {\r\n jobId, total, completed, failed,\r\n currentIndex: index,\r\n currentStory: item.story.slice(0, 80),\r\n } satisfies BulkProgressEvent);\r\n\r\n // Small delay between stories to respect API rate limits\r\n if (queue.length > 0) {\r\n await new Promise<void>((r) => setTimeout(r, 350));\r\n }\r\n }\r\n }\r\n\r\n // Launch `concurrency` parallel workers\r\n for (let i = 0; i < Math.min(concurrency, total); i++) {\r\n results.push(processNext());\r\n }\r\n await Promise.all(results);\r\n\r\n const doneEvent: BulkDoneEvent = { jobId, total, completed, failed, failedItems };\r\n ws?.broadcast('story:bulk-done', doneEvent);\r\n logger.info({ jobId, completed, failed, total }, 'Bulk story generation finished');\r\n\r\n return doneEvent;\r\n}\r\n","/**\r\n * Step routes — add, remove, reorder, and generate code for steps.\r\n *\r\n * POST /api/suites/:suiteId/cases/:caseId/steps — add step\r\n * DELETE /api/suites/:suiteId/cases/:caseId/steps/:stepId — delete step\r\n * POST /api/suites/:suiteId/cases/:caseId/steps/:stepId/generate — (re)generate code\r\n * POST /api/suites/:suiteId/cases/:caseId/steps/generate-all — generate all empty steps\r\n * PATCH /api/suites/:suiteId/cases/:caseId/steps/reorder — reorder steps\r\n */\r\nimport path from 'path';\r\nimport { randomUUID } from 'crypto';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { readCase, updateCase, findCasePathById } from '../../storage/case-store.js';\r\nimport { findSuiteDirById } from '../../storage/suite-store.js';\r\nimport { resolveVariables } from '../../storage/variable-store.js';\r\nimport { createSmartRouter } from '../../ai/router.js';\r\nimport { sendError } from '../utils.js';\r\nimport type { TestStep } from '../../types/suite.js';\r\n\r\nconst AddStepBody = z.object({\r\n instruction: z.string().min(1),\r\n order: z.number().int().positive().optional(),\r\n});\r\n\r\nconst ReorderBody = z.object({\r\n stepIds: z.array(z.string().min(1)),\r\n});\r\n\r\nconst UpdateStepBody = z.object({\r\n instruction: z.string().min(1).optional(),\r\n timeout: z.number().int().positive().optional().nullable(),\r\n stepType: z.enum(['ui', 'api', 'mock']).optional(),\r\n retries: z.number().int().min(0).optional(),\r\n mockUrl: z.string().optional(),\r\n mockResponse: z.string().optional(),\r\n mockStatus: z.number().int().optional(),\r\n auditUrl: z.string().optional(),\r\n lighthouseCategories: z.array(z.enum(['performance', 'accessibility', 'seo'])).optional(),\r\n runAudit: z.boolean().optional(),\r\n});\r\n\r\ntype StepParams = { suiteId: string; caseId: string; stepId: string };\r\ntype CaseParams = { suiteId: string; caseId: string };\r\n\r\nexport async function stepRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n const testsDir = path.join(rootDir, 'tests');\r\n\r\n // Helper: resolve suiteId + caseId UUIDs → actual case file path\r\n async function resolveCasePath(suiteId: string, caseId: string): Promise<string | null> {\r\n const suiteDir = await findSuiteDirById(testsDir, suiteId);\r\n if (!suiteDir) return null;\r\n return findCasePathById(suiteDir, caseId);\r\n }\r\n\r\n // POST /api/suites/:suiteId/cases/:caseId/steps\r\n fastify.post<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId/steps', async (req, reply) => {\r\n const parsed = AddStepBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid step data', details: parsed.error.issues });\r\n }\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const insertOrder = parsed.data.order ?? tc.steps.length + 1;\r\n const newStep: TestStep = {\r\n id: `step-${randomUUID().slice(0, 8)}`,\r\n order: insertOrder,\r\n instruction: parsed.data.instruction,\r\n generatedCode: '',\r\n strategy: 'primary',\r\n lastHealed: null,\r\n };\r\n\r\n // Re-number steps after insertion point\r\n const updatedSteps = [\r\n ...tc.steps.map((s) => s.order >= insertOrder ? { ...s, order: s.order + 1 } : s),\r\n newStep,\r\n ].sort((a, b) => a.order - b.order);\r\n\r\n const updated = await updateCase(caseDir, { steps: updatedSteps });\r\n return reply.status(201).send(updated);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to add step', err);\r\n }\r\n });\r\n\r\n // DELETE /api/suites/:suiteId/cases/:caseId/steps/:stepId\r\n fastify.delete<{ Params: StepParams }>('/suites/:suiteId/cases/:caseId/steps/:stepId', async (req, reply) => {\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const remaining = tc.steps\r\n .filter((s) => s.id !== req.params.stepId)\r\n .map((s, idx) => ({ ...s, order: idx + 1 }));\r\n\r\n const updated = await updateCase(caseDir, { steps: remaining });\r\n return reply.send(updated);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete step', err);\r\n }\r\n });\r\n\r\n // POST /api/suites/:suiteId/cases/:caseId/steps/:stepId/generate\r\n fastify.post<{ Params: StepParams }>('/suites/:suiteId/cases/:caseId/steps/:stepId/generate', async (req, reply) => {\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const step = tc.steps.find((s) => s.id === req.params.stepId);\r\n if (!step) {\r\n return reply.status(404).send({ error: `Step \"${req.params.stepId}\" not found` });\r\n }\r\n\r\n const variables = await resolveVariables(rootDir).catch(() => ({}));\r\n const router = createSmartRouter(rootDir);\r\n const config = await import('../../storage/config-store.js').then((m) =>\r\n m.readConfig(rootDir),\r\n );\r\n\r\n const result = await router.generate(step.instruction, {\r\n url: config.baseUrl,\r\n title: '',\r\n interactiveElements: '',\r\n htmlSnapshot: '',\r\n previousSteps: tc.steps\r\n .filter((s) => s.order < step.order && s.generatedCode)\r\n .map((s) => ({ instruction: s.instruction, code: s.generatedCode })),\r\n variables,\r\n });\r\n\r\n const updatedSteps = tc.steps.map((s) =>\r\n s.id === step.id\r\n ? { ...s, generatedCode: result.code, strategy: result.strategy }\r\n : s,\r\n );\r\n\r\n await router.getCache().persist();\r\n const updated = await updateCase(caseDir, { steps: updatedSteps });\r\n return reply.send({ step: updated.steps.find((s) => s.id === step.id), strategy: result.strategy, cost: result.cost });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate code for step', err);\r\n }\r\n });\r\n\r\n // POST /api/suites/:suiteId/cases/:caseId/steps/generate-all\r\n fastify.post<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId/steps/generate-all', async (req, reply) => {\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const emptySteps = tc.steps.filter((s) => !s.generatedCode.trim());\r\n if (emptySteps.length === 0) {\r\n return reply.send({ message: 'All steps already have code', generated: 0 });\r\n }\r\n\r\n const variables = await resolveVariables(rootDir).catch(() => ({}));\r\n const config = await import('../../storage/config-store.js').then((m) =>\r\n m.readConfig(rootDir),\r\n );\r\n const router = createSmartRouter(rootDir);\r\n\r\n const batchSteps = emptySteps.map((s) => ({\r\n instruction: s.instruction,\r\n context: {\r\n url: config.baseUrl,\r\n title: '',\r\n interactiveElements: '',\r\n htmlSnapshot: '',\r\n previousSteps: tc.steps\r\n .filter((ps) => ps.order < s.order && ps.generatedCode)\r\n .map((ps) => ({ instruction: ps.instruction, code: ps.generatedCode })),\r\n variables,\r\n },\r\n }));\r\n\r\n const results = await router.batchGenerate(batchSteps);\r\n await router.getCache().persist();\r\n\r\n // Count steps that actually received non-empty generated code\r\n const codeMap = new Map(emptySteps.map((s, i) => [s.id, results[i]]));\r\n let actuallyGenerated = 0;\r\n const updatedSteps = tc.steps.map((s) => {\r\n const r = codeMap.get(s.id);\r\n if (r && r.code.trim()) {\r\n actuallyGenerated++;\r\n return { ...s, generatedCode: r.code, strategy: r.strategy };\r\n }\r\n return s;\r\n });\r\n\r\n if (actuallyGenerated === 0) {\r\n return reply.status(500).send({\r\n error: 'AI code generation produced no results',\r\n detail:\r\n 'The AI provider responded but returned empty code for all steps. ' +\r\n 'Check your API key, model name, and server terminal logs for details.',\r\n code: 'GENERATION_EMPTY',\r\n });\r\n }\r\n\r\n const updated = await updateCase(caseDir, { steps: updatedSteps });\r\n return reply.send({ generated: actuallyGenerated, case: updated });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate code for steps', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:suiteId/cases/:caseId/steps/reorder\r\n // NOTE: static route (/reorder) MUST be registered before parametric (/:stepId)\r\n // so Fastify's radix-tree router matches the literal segment first.\r\n fastify.patch<{ Params: CaseParams }>('/suites/:suiteId/cases/:caseId/steps/reorder', async (req, reply) => {\r\n const parsed = ReorderBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid reorder data', details: parsed.error.issues });\r\n }\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const stepMap = new Map(tc.steps.map((s) => [s.id, s]));\r\n const reordered = parsed.data.stepIds\r\n .map((id, idx) => {\r\n const s = stepMap.get(id);\r\n return s ? { ...s, order: idx + 1 } : null;\r\n })\r\n .filter((s): s is TestStep => s !== null);\r\n\r\n const updated = await updateCase(caseDir, { steps: reordered });\r\n return reply.send(updated);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to reorder steps', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:suiteId/cases/:caseId/steps/:stepId — update step instruction\r\n // Registered AFTER the static /reorder route so Fastify always matches literals first.\r\n fastify.patch<{ Params: StepParams }>('/suites/:suiteId/cases/:caseId/steps/:stepId', async (req, reply) => {\r\n const parsed = UpdateStepBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid step data', details: parsed.error.issues });\r\n }\r\n try {\r\n const caseDir = await resolveCasePath(req.params.suiteId, req.params.caseId);\r\n if (!caseDir) return reply.status(404).send({ error: `Case \"${req.params.caseId}\" not found` });\r\n const tc = await readCase(caseDir);\r\n\r\n const step = tc.steps.find((s) => s.id === req.params.stepId);\r\n if (!step) return reply.status(404).send({ error: `Step \"${req.params.stepId}\" not found` });\r\n\r\n const updatedSteps = tc.steps.map((s) => {\r\n if (s.id !== req.params.stepId) return s;\r\n const patch: Record<string, unknown> = {};\r\n if (parsed.data.instruction !== undefined) patch.instruction = parsed.data.instruction;\r\n if (parsed.data.timeout !== undefined) patch.timeout = parsed.data.timeout ?? undefined;\r\n if (parsed.data.stepType !== undefined) patch.stepType = parsed.data.stepType;\r\n if (parsed.data.retries !== undefined) patch.retries = parsed.data.retries;\r\n if (parsed.data.mockUrl !== undefined) patch.mockUrl = parsed.data.mockUrl;\r\n if (parsed.data.mockResponse !== undefined) patch.mockResponse = parsed.data.mockResponse;\r\n if (parsed.data.mockStatus !== undefined) patch.mockStatus = parsed.data.mockStatus;\r\n if (parsed.data.auditUrl !== undefined) patch.auditUrl = parsed.data.auditUrl;\r\n if (parsed.data.lighthouseCategories !== undefined) patch.lighthouseCategories = parsed.data.lighthouseCategories;\r\n if (parsed.data.runAudit !== undefined) patch.runAudit = parsed.data.runAudit;\r\n return { ...s, ...patch };\r\n });\r\n const updated = await updateCase(caseDir, { steps: updatedSteps });\r\n return reply.send(updated);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to update step', err);\r\n }\r\n });\r\n}\r\n","/**\r\n * Hooks storage — read/write suite lifecycle hooks (before_all, before_each, etc.)\r\n *\r\n * Stored as `hooks.json` in each suite directory alongside `suite.json`.\r\n * If the file doesn't exist, returns empty hooks (all arrays empty).\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { randomUUID } from 'crypto';\r\nimport { SuiteHooksSchema, type SuiteHooks, type HookType, type TestStep } from '../types/suite.js';\r\nimport { ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('hooks-store');\r\n\r\nconst HOOKS_FILE = 'hooks.json';\r\n\r\nconst EMPTY_HOOKS: SuiteHooks = {\r\n before_all: [],\r\n before_each: [],\r\n after_each: [],\r\n after_all: [],\r\n};\r\n\r\n/**\r\n * Reads hooks.json from the given suite directory.\r\n * Returns empty hooks if file doesn't exist (hooks are optional).\r\n */\r\nexport async function readHooks(suiteDir: string): Promise<SuiteHooks> {\r\n const filePath = path.join(suiteDir, HOOKS_FILE);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n return { ...EMPTY_HOOKS };\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = SuiteHooksSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n logger.warn({ path: filePath, errors: result.error.issues }, 'Invalid hooks.json — returning defaults');\r\n return { ...EMPTY_HOOKS };\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes hooks.json atomically to the given suite directory.\r\n */\r\nexport async function writeHooks(suiteDir: string, hooks: SuiteHooks): Promise<void> {\r\n await fs.ensureDir(suiteDir);\r\n const filePath = path.join(suiteDir, HOOKS_FILE);\r\n\r\n const result = SuiteHooksSchema.safeParse(hooks);\r\n if (!result.success) {\r\n const issues = result.error.issues.map((i) => ` • ${i.path.join('.')}: ${i.message}`).join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid hooks to \"${filePath}\":\\n${issues}`,\r\n 'hooks',\r\n 'INVALID_HOOKS',\r\n );\r\n }\r\n\r\n await atomicWriteJson(filePath, result.data);\r\n logger.debug({ path: filePath }, 'Hooks written');\r\n}\r\n\r\n/**\r\n * Adds a step to a specific hook type. Returns updated hooks.\r\n */\r\nexport async function addHookStep(\r\n suiteDir: string,\r\n hookType: HookType,\r\n instruction: string,\r\n order?: number,\r\n): Promise<SuiteHooks> {\r\n const hooks = await readHooks(suiteDir);\r\n const steps = hooks[hookType];\r\n\r\n const insertOrder = order ?? steps.length + 1;\r\n const newStep: TestStep = {\r\n id: `step-${randomUUID().slice(0, 8)}`,\r\n order: insertOrder,\r\n instruction,\r\n generatedCode: '',\r\n strategy: 'primary',\r\n lastHealed: null,\r\n };\r\n\r\n const updatedSteps = [\r\n ...steps.map((s) => s.order >= insertOrder ? { ...s, order: s.order + 1 } : s),\r\n newStep,\r\n ].sort((a, b) => a.order - b.order);\r\n\r\n hooks[hookType] = updatedSteps;\r\n await writeHooks(suiteDir, hooks);\r\n return hooks;\r\n}\r\n\r\n/**\r\n * Deletes a step from a specific hook type. Returns updated hooks.\r\n */\r\nexport async function deleteHookStep(\r\n suiteDir: string,\r\n hookType: HookType,\r\n stepId: string,\r\n): Promise<SuiteHooks> {\r\n const hooks = await readHooks(suiteDir);\r\n hooks[hookType] = hooks[hookType]\r\n .filter((s) => s.id !== stepId)\r\n .map((s, idx) => ({ ...s, order: idx + 1 }));\r\n\r\n await writeHooks(suiteDir, hooks);\r\n return hooks;\r\n}\r\n\r\n/**\r\n * Reorders steps within a specific hook type. Returns updated hooks.\r\n */\r\nexport async function reorderHookSteps(\r\n suiteDir: string,\r\n hookType: HookType,\r\n stepIds: string[],\r\n): Promise<SuiteHooks> {\r\n const hooks = await readHooks(suiteDir);\r\n const stepMap = new Map(hooks[hookType].map((s) => [s.id, s]));\r\n\r\n hooks[hookType] = stepIds\r\n .map((id, idx) => {\r\n const s = stepMap.get(id);\r\n return s ? { ...s, order: idx + 1 } : null;\r\n })\r\n .filter((s): s is TestStep => s !== null);\r\n\r\n await writeHooks(suiteDir, hooks);\r\n return hooks;\r\n}\r\n\r\n/**\r\n * Updates a single step's instruction or timeout within a hook. Returns updated hooks.\r\n */\r\nexport async function updateHookStep(\r\n suiteDir: string,\r\n hookType: HookType,\r\n stepId: string,\r\n patch: { instruction?: string; timeout?: number | null },\r\n): Promise<SuiteHooks> {\r\n const hooks = await readHooks(suiteDir);\r\n\r\n hooks[hookType] = hooks[hookType].map((s) => {\r\n if (s.id !== stepId) return s;\r\n const updates: Record<string, unknown> = {};\r\n if (patch.instruction !== undefined) updates.instruction = patch.instruction;\r\n if (patch.timeout !== undefined) updates.timeout = patch.timeout ?? undefined;\r\n return { ...s, ...updates };\r\n });\r\n\r\n await writeHooks(suiteDir, hooks);\r\n return hooks;\r\n}\r\n","/**\r\n * Hook routes — CRUD for suite lifecycle hooks (before_all, before_each, after_each, after_all).\r\n *\r\n * GET /api/suites/:suiteId/hooks — get all hooks\r\n * POST /api/suites/:suiteId/hooks/:hookType/steps — add step\r\n * POST /api/suites/:suiteId/hooks/:hookType/steps/generate-all — generate code for all empty steps\r\n * DELETE /api/suites/:suiteId/hooks/:hookType/steps/:stepId — delete step\r\n * PATCH /api/suites/:suiteId/hooks/:hookType/steps/reorder — reorder steps\r\n * PATCH /api/suites/:suiteId/hooks/:hookType/steps/:stepId — update step\r\n * POST /api/suites/:suiteId/hooks/:hookType/steps/:stepId/generate — generate code for step\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { findSuiteDirById } from '../../storage/suite-store.js';\r\nimport {\r\n readHooks,\r\n addHookStep,\r\n deleteHookStep,\r\n reorderHookSteps,\r\n updateHookStep,\r\n writeHooks,\r\n} from '../../storage/hooks-store.js';\r\nimport { resolveVariables } from '../../storage/variable-store.js';\r\nimport { createSmartRouter } from '../../ai/router.js';\r\nimport { sendError } from '../utils.js';\r\nimport { HookTypeEnum, type HookType } from '../../types/suite.js';\r\n\r\nconst AddStepBody = z.object({\r\n instruction: z.string().min(1),\r\n order: z.number().int().positive().optional(),\r\n});\r\n\r\nconst ReorderBody = z.object({\r\n stepIds: z.array(z.string().min(1)),\r\n});\r\n\r\nconst UpdateStepBody = z.object({\r\n instruction: z.string().min(1).optional(),\r\n timeout: z.number().int().positive().optional().nullable(),\r\n});\r\n\r\ntype SuiteParams = { suiteId: string };\r\ntype HookParams = { suiteId: string; hookType: string };\r\ntype StepParams = { suiteId: string; hookType: string; stepId: string };\r\n\r\nfunction parseHookType(raw: string): HookType | null {\r\n const result = HookTypeEnum.safeParse(raw);\r\n return result.success ? result.data : null;\r\n}\r\n\r\nexport async function hookRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n const testsDir = path.join(rootDir, 'tests');\r\n\r\n async function resolveSuiteDir(suiteId: string): Promise<string | null> {\r\n return findSuiteDirById(testsDir, suiteId);\r\n }\r\n\r\n // ── GET /api/suites/:suiteId/hooks ────────────────────────────────────────\r\n fastify.get<{ Params: SuiteParams }>('/suites/:suiteId/hooks', async (req, reply) => {\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n const hooks = await readHooks(suiteDir);\r\n return reply.send(hooks);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to read hooks', err);\r\n }\r\n });\r\n\r\n // ── POST /api/suites/:suiteId/hooks/:hookType/steps — add step ───────────\r\n fastify.post<{ Params: HookParams }>('/suites/:suiteId/hooks/:hookType/steps', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n const parsed = AddStepBody.safeParse(req.body);\r\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid step data', details: parsed.error.issues });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n const hooks = await addHookStep(suiteDir, hookType, parsed.data.instruction, parsed.data.order);\r\n return reply.status(201).send(hooks);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to add hook step', err);\r\n }\r\n });\r\n\r\n // ── Static routes MUST come before parametric /:stepId routes ─────────────\r\n\r\n // POST /api/suites/:suiteId/hooks/:hookType/steps/generate-all\r\n fastify.post<{ Params: HookParams }>('/suites/:suiteId/hooks/:hookType/steps/generate-all', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n\r\n const hooks = await readHooks(suiteDir);\r\n const steps = hooks[hookType];\r\n const emptySteps = steps.filter((s) => !s.generatedCode.trim());\r\n\r\n if (emptySteps.length === 0) {\r\n return reply.send({ message: 'All steps already have code', generated: 0, hooks });\r\n }\r\n\r\n const variables = await resolveVariables(rootDir).catch(() => ({}));\r\n const config = await import('../../storage/config-store.js').then((m) => m.readConfig(rootDir));\r\n const router = createSmartRouter(rootDir);\r\n\r\n const batchSteps = emptySteps.map((s) => ({\r\n instruction: s.instruction,\r\n context: {\r\n url: config.baseUrl,\r\n title: '',\r\n interactiveElements: '',\r\n htmlSnapshot: '',\r\n previousSteps: steps\r\n .filter((ps) => ps.order < s.order && ps.generatedCode)\r\n .map((ps) => ({ instruction: ps.instruction, code: ps.generatedCode })),\r\n variables,\r\n },\r\n }));\r\n\r\n const results = await router.batchGenerate(batchSteps);\r\n await router.getCache().persist();\r\n\r\n const codeMap = new Map(emptySteps.map((s, i) => [s.id, results[i]]));\r\n let actuallyGenerated = 0;\r\n hooks[hookType] = steps.map((s) => {\r\n const r = codeMap.get(s.id);\r\n if (r && r.code.trim()) {\r\n actuallyGenerated++;\r\n return { ...s, generatedCode: r.code, strategy: r.strategy };\r\n }\r\n return s;\r\n });\r\n\r\n if (actuallyGenerated === 0) {\r\n return reply.status(500).send({\r\n error: 'AI code generation produced no results',\r\n code: 'GENERATION_EMPTY',\r\n });\r\n }\r\n\r\n await writeHooks(suiteDir, hooks);\r\n return reply.send({ generated: actuallyGenerated, hooks });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate code for hook steps', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:suiteId/hooks/:hookType/steps/reorder\r\n fastify.patch<{ Params: HookParams }>('/suites/:suiteId/hooks/:hookType/steps/reorder', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n const parsed = ReorderBody.safeParse(req.body);\r\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid reorder data', details: parsed.error.issues });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n const hooks = await reorderHookSteps(suiteDir, hookType, parsed.data.stepIds);\r\n return reply.send(hooks);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to reorder hook steps', err);\r\n }\r\n });\r\n\r\n // ── Parametric /:stepId routes ────────────────────────────────────────────\r\n\r\n // DELETE /api/suites/:suiteId/hooks/:hookType/steps/:stepId\r\n fastify.delete<{ Params: StepParams }>('/suites/:suiteId/hooks/:hookType/steps/:stepId', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n const hooks = await deleteHookStep(suiteDir, hookType, req.params.stepId);\r\n return reply.send(hooks);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete hook step', err);\r\n }\r\n });\r\n\r\n // PATCH /api/suites/:suiteId/hooks/:hookType/steps/:stepId\r\n fastify.patch<{ Params: StepParams }>('/suites/:suiteId/hooks/:hookType/steps/:stepId', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n const parsed = UpdateStepBody.safeParse(req.body);\r\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid step data', details: parsed.error.issues });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n const hooks = await updateHookStep(suiteDir, hookType, req.params.stepId, parsed.data);\r\n return reply.send(hooks);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to update hook step', err);\r\n }\r\n });\r\n\r\n // POST /api/suites/:suiteId/hooks/:hookType/steps/:stepId/generate\r\n fastify.post<{ Params: StepParams }>('/suites/:suiteId/hooks/:hookType/steps/:stepId/generate', async (req, reply) => {\r\n const hookType = parseHookType(req.params.hookType);\r\n if (!hookType) return reply.status(400).send({ error: `Invalid hook type: ${req.params.hookType}` });\r\n\r\n try {\r\n const suiteDir = await resolveSuiteDir(req.params.suiteId);\r\n if (!suiteDir) return reply.status(404).send({ error: 'Suite not found' });\r\n\r\n const hooks = await readHooks(suiteDir);\r\n const steps = hooks[hookType];\r\n const step = steps.find((s) => s.id === req.params.stepId);\r\n if (!step) return reply.status(404).send({ error: `Step \"${req.params.stepId}\" not found` });\r\n\r\n const variables = await resolveVariables(rootDir).catch(() => ({}));\r\n const router = createSmartRouter(rootDir);\r\n const config = await import('../../storage/config-store.js').then((m) => m.readConfig(rootDir));\r\n\r\n const result = await router.generate(step.instruction, {\r\n url: config.baseUrl,\r\n title: '',\r\n interactiveElements: '',\r\n htmlSnapshot: '',\r\n previousSteps: steps\r\n .filter((s) => s.order < step.order && s.generatedCode)\r\n .map((s) => ({ instruction: s.instruction, code: s.generatedCode })),\r\n variables,\r\n });\r\n\r\n hooks[hookType] = steps.map((s) =>\r\n s.id === step.id\r\n ? { ...s, generatedCode: result.code, strategy: result.strategy }\r\n : s,\r\n );\r\n\r\n await router.getCache().persist();\r\n await writeHooks(suiteDir, hooks);\r\n\r\n return reply.send({\r\n step: hooks[hookType].find((s) => s.id === step.id),\r\n strategy: result.strategy,\r\n cost: result.cost,\r\n });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate code for hook step', err);\r\n }\r\n });\r\n}\r\n","/**\r\n * Variable routes — manage test variables.\r\n *\r\n * GET /api/variables — get resolved global variables\r\n * PUT /api/variables/:key — set a global variable\r\n * DELETE /api/variables/:key — delete a global variable\r\n * GET /api/variables/env/:env — get env-specific variables\r\n */\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport {\r\n resolveVariables,\r\n readGlobalVariables,\r\n setGlobalVariable,\r\n deleteGlobalVariable,\r\n readEnvVariables,\r\n} from '../../storage/variable-store.js';\r\nimport { readConfig } from '../../storage/config-store.js';\r\nimport { sendError } from '../utils.js';\r\n\r\nconst SetVariableBody = z.object({\r\n value: z.union([\r\n z.string(),\r\n z.object({ value: z.string(), secret: z.literal(true) }),\r\n ]),\r\n});\r\n\r\nexport async function variableRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n\r\n // GET /api/variables — returns RAW variables (with secret objects intact for UI display)\r\n fastify.get('/variables', async (_req, reply) => {\r\n try {\r\n const vars = await readGlobalVariables(rootDir);\r\n // Inject BASE_URL from Settings (environment config) — not from variable files.\r\n // This ensures {{BASE_URL}} always reflects the active environment's URL.\r\n try {\r\n const config = await readConfig(rootDir);\r\n const activeEnv = config.environment ?? 'stage';\r\n const envUrl = config.environmentUrls?.[activeEnv as keyof typeof config.environmentUrls];\r\n const baseUrl = envUrl || config.baseUrl;\r\n // Remove any user-defined BASE_URL and replace with config-derived value\r\n delete vars['BASE_URL'];\r\n return reply.send({ BASE_URL: baseUrl, ...vars, _system: { BASE_URL: { source: 'settings', environment: activeEnv, readOnly: true } } });\r\n } catch {\r\n return reply.send(vars);\r\n }\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to read variables', err);\r\n }\r\n });\r\n\r\n // GET /api/variables/env/:env\r\n fastify.get<{ Params: { env: string } }>('/variables/env/:env', async (req, reply) => {\r\n try {\r\n const vars = await readEnvVariables(rootDir, req.params.env);\r\n return reply.send(vars);\r\n } catch (err) {\r\n return sendError(reply, 500, `Failed to read variables for env \"${req.params.env}\"`, err);\r\n }\r\n });\r\n\r\n // PUT /api/variables/:key\r\n fastify.put<{ Params: { key: string } }>('/variables/:key', async (req, reply) => {\r\n if (req.params.key === 'BASE_URL') {\r\n return reply.status(400).send({ error: 'BASE_URL is managed in Settings → Environment. Update it there.' });\r\n }\r\n const parsed = SetVariableBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid variable value', details: parsed.error.issues });\r\n }\r\n try {\r\n await setGlobalVariable(rootDir, req.params.key, parsed.data.value);\r\n return reply.send({ key: req.params.key, value: parsed.data.value });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to set variable', err);\r\n }\r\n });\r\n\r\n // DELETE /api/variables/:key\r\n fastify.delete<{ Params: { key: string } }>('/variables/:key', async (req, reply) => {\r\n if (req.params.key === 'BASE_URL') {\r\n return reply.status(400).send({ error: 'BASE_URL is managed in Settings → Environment. It cannot be deleted.' });\r\n }\r\n try {\r\n await deleteGlobalVariable(rootDir, req.params.key);\r\n return reply.status(204).send();\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete variable', err);\r\n }\r\n });\r\n}\r\n","import { z } from 'zod';\r\n\r\nexport const HealingStatusSchema = z.enum(['pending', 'accepted', 'rejected']);\r\nexport const HealingStrategySchema = z.enum([\r\n 'retry',\r\n 'regenerate',\r\n 'multi-selector',\r\n 'visual',\r\n 'decompose',\r\n 'manual',\r\n]);\r\n\r\nexport type HealingStatus = z.infer<typeof HealingStatusSchema>;\r\nexport type HealingStrategy = z.infer<typeof HealingStrategySchema>;\r\n\r\nexport const HealingEventSchema = z.object({\r\n id: z.string(),\r\n runId: z.string(),\r\n suiteId: z.string(),\r\n caseId: z.string(),\r\n stepId: z.string(),\r\n stepInstruction: z.string(),\r\n failedCode: z.string(),\r\n healedCode: z.string(),\r\n error: z.string(),\r\n strategy: HealingStrategySchema,\r\n level: z.number().int().min(1).max(6),\r\n status: HealingStatusSchema,\r\n pageUrl: z.string(),\r\n timestamp: z.string().datetime(),\r\n acceptedAt: z.string().datetime().optional(),\r\n rejectedAt: z.string().datetime().optional(),\r\n});\r\n\r\nexport const HealingReportSchema = z.object({\r\n runId: z.string(),\r\n generatedAt: z.string().datetime(),\r\n totalHeals: z.number().int(),\r\n accepted: z.number().int(),\r\n rejected: z.number().int(),\r\n pending: z.number().int(),\r\n events: z.array(HealingEventSchema),\r\n});\r\n\r\nexport type HealingEvent = z.infer<typeof HealingEventSchema>;\r\nexport type HealingReport = z.infer<typeof HealingReportSchema>;\r\n\r\nexport interface HealingDecision {\r\n heal: boolean;\r\n strategy?: 'individual' | 'batch';\r\n reason: string;\r\n}\r\n\r\nexport type FailureKind = 'assertion' | 'infra';\r\n\r\nexport interface StepFailure {\r\n stepId: string;\r\n instruction: string;\r\n error: string;\r\n pageUrl: string;\r\n failedCode: string;\r\n failureKind: FailureKind;\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { HealingEvent, HealingEventSchema, HealingReport, HealingReportSchema } from '../types/healing.js';\r\nimport { StorageError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('healing-store');\r\n\r\nconst HEALING_DIR = path.join('results', 'healing');\r\nconst PENDING_FILE = 'pending.json';\r\nconst REPORT_PREFIX = 'healing-report-';\r\n\r\nfunction reportFilePath(healingDir: string, runId: string): string {\r\n return path.join(healingDir, `${REPORT_PREFIX}${runId}.json`);\r\n}\r\n\r\nfunction pendingFilePath(healingDir: string): string {\r\n return path.join(healingDir, PENDING_FILE);\r\n}\r\n\r\n/**\r\n * Saves a complete healing report for a run.\r\n */\r\nexport async function writeHealingReport(\r\n rootDir: string,\r\n report: HealingReport,\r\n): Promise<void> {\r\n const schema = HealingReportSchema.safeParse(report);\r\n if (!schema.success) {\r\n const issues = schema.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid healing report:\\n${issues}`,\r\n 'healingReport',\r\n 'INVALID_HEALING_REPORT',\r\n );\r\n }\r\n\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n const filePath = reportFilePath(healingDir, report.runId);\r\n await atomicWriteJson(filePath, schema.data);\r\n logger.info({ runId: report.runId, totalHeals: report.totalHeals }, 'Healing report saved');\r\n}\r\n\r\n/**\r\n * Reads a healing report for a specific run.\r\n */\r\nexport async function readHealingReport(rootDir: string, runId: string): Promise<HealingReport> {\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n const filePath = reportFilePath(healingDir, runId);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new StorageError(\r\n `Healing report not found for runId \"${runId}\".`,\r\n filePath,\r\n 'HEALING_REPORT_NOT_FOUND',\r\n );\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = HealingReportSchema.safeParse(raw);\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Invalid healing report at \"${filePath}\":\\n${issues}`,\r\n 'healingReport',\r\n 'INVALID_HEALING_REPORT',\r\n );\r\n }\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Reads all pending healing events across all runs.\r\n */\r\nexport async function readPendingEvents(rootDir: string): Promise<HealingEvent[]> {\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n const filePath = pendingFilePath(healingDir);\r\n if (!(await fs.pathExists(filePath))) return [];\r\n\r\n const raw = await readJson(filePath);\r\n const result = HealingEventSchema.array().safeParse(raw);\r\n if (!result.success) {\r\n logger.warn({ path: filePath }, 'Pending healing file is malformed — resetting');\r\n return [];\r\n }\r\n return result.data;\r\n}\r\n\r\nconst MAX_HEALING_EVENTS = 50;\r\n\r\n/**\r\n * Priority order for auto-pruning when the cap is exceeded.\r\n * Lower index = deleted first.\r\n */\r\nconst PRUNE_PRIORITY: HealingEvent['status'][] = ['pending', 'rejected', 'accepted'];\r\n\r\n/**\r\n * Trims events to MAX_HEALING_EVENTS, removing by PRUNE_PRIORITY (oldest first\r\n * within the same status group) until the list fits.\r\n */\r\nfunction pruneToLimit(events: HealingEvent[]): HealingEvent[] {\r\n if (events.length <= MAX_HEALING_EVENTS) return events;\r\n\r\n // Build a mutable copy sorted so oldest entries of lower-priority statuses come first\r\n const byPriority = [...events].sort((a, b) => {\r\n const pa = PRUNE_PRIORITY.indexOf(a.status);\r\n const pb = PRUNE_PRIORITY.indexOf(b.status);\r\n if (pa !== pb) return pa - pb; // lower priority (pending) first\r\n return a.timestamp < b.timestamp ? -1 : 1; // oldest first within same status\r\n });\r\n\r\n const excess = events.length - MAX_HEALING_EVENTS;\r\n const toDelete = new Set(byPriority.slice(0, excess).map((e) => e.id));\r\n\r\n logger.info(\r\n { excess, deleted: toDelete.size },\r\n 'Auto-pruning healing events to enforce cap',\r\n );\r\n\r\n return events.filter((e) => !toDelete.has(e.id));\r\n}\r\n\r\n/**\r\n * Appends a new healing event to the pending list, then enforces the 50-event cap.\r\n */\r\nexport async function appendPendingEvent(rootDir: string, event: HealingEvent): Promise<void> {\r\n const schema = HealingEventSchema.safeParse(event);\r\n if (!schema.success) {\r\n throw new ValidationError(\r\n `Invalid healing event: ${schema.error.message}`,\r\n 'healingEvent',\r\n 'INVALID_HEALING_EVENT',\r\n );\r\n }\r\n\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await fs.ensureDir(healingDir);\r\n\r\n const existing = await readPendingEvents(rootDir);\r\n existing.push(schema.data);\r\n await atomicWriteJson(pendingFilePath(healingDir), pruneToLimit(existing));\r\n}\r\n\r\n/**\r\n * Accepts a pending healing event: updates status and persists.\r\n */\r\nexport async function acceptHealingEvent(rootDir: string, eventId: string): Promise<HealingEvent> {\r\n const pending = await readPendingEvents(rootDir);\r\n const idx = pending.findIndex((e) => e.id === eventId);\r\n\r\n if (idx === -1) {\r\n throw new StorageError(\r\n `Healing event \"${eventId}\" not found in pending list.`,\r\n eventId,\r\n 'HEALING_EVENT_NOT_FOUND',\r\n );\r\n }\r\n\r\n pending[idx] = {\r\n ...pending[idx],\r\n status: 'accepted',\r\n acceptedAt: new Date().toISOString(),\r\n } as HealingEvent;\r\n\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), pending);\r\n logger.info({ eventId }, 'Healing event accepted');\r\n\r\n return pending[idx];\r\n}\r\n\r\n/**\r\n * Rejects a pending healing event.\r\n */\r\nexport async function rejectHealingEvent(rootDir: string, eventId: string): Promise<HealingEvent> {\r\n const pending = await readPendingEvents(rootDir);\r\n const idx = pending.findIndex((e) => e.id === eventId);\r\n\r\n if (idx === -1) {\r\n throw new StorageError(\r\n `Healing event \"${eventId}\" not found in pending list.`,\r\n eventId,\r\n 'HEALING_EVENT_NOT_FOUND',\r\n );\r\n }\r\n\r\n pending[idx] = {\r\n ...pending[idx],\r\n status: 'rejected',\r\n rejectedAt: new Date().toISOString(),\r\n } as HealingEvent;\r\n\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), pending);\r\n logger.info({ eventId }, 'Healing event rejected');\r\n\r\n return pending[idx];\r\n}\r\n\r\n/**\r\n * Deletes a single healing event by ID.\r\n */\r\nexport async function deleteHealingEvent(rootDir: string, eventId: string): Promise<void> {\r\n const events = await readPendingEvents(rootDir);\r\n const filtered = events.filter((e) => e.id !== eventId);\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), filtered);\r\n logger.info({ eventId }, 'Healing event deleted');\r\n}\r\n\r\n/**\r\n * Deletes multiple healing events by their IDs.\r\n * Returns the number of events actually deleted.\r\n */\r\nexport async function deleteHealingEvents(rootDir: string, eventIds: string[]): Promise<number> {\r\n const events = await readPendingEvents(rootDir);\r\n const idSet = new Set(eventIds);\r\n const filtered = events.filter((e) => !idSet.has(e.id));\r\n const deleted = events.length - filtered.length;\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), filtered);\r\n logger.info({ count: deleted }, 'Healing events bulk-deleted');\r\n return deleted;\r\n}\r\n\r\n/**\r\n * Deletes ALL healing events.\r\n * Returns the number of events deleted.\r\n */\r\nexport async function clearAllHealingEvents(rootDir: string): Promise<number> {\r\n const events = await readPendingEvents(rootDir);\r\n const count = events.length;\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), []);\r\n logger.info({ count }, 'All healing events cleared');\r\n return count;\r\n}\r\n\r\n/**\r\n * Removes accepted and rejected events older than retentionDays from the pending file.\r\n */\r\nexport async function pruneResolvedEvents(\r\n rootDir: string,\r\n retentionDays = 30,\r\n): Promise<number> {\r\n const pending = await readPendingEvents(rootDir);\r\n const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\r\n const before = pending.length;\r\n\r\n const kept = pending.filter((e) => {\r\n if (e.status === 'pending') return true;\r\n const resolvedAt = e.acceptedAt ?? e.rejectedAt;\r\n if (!resolvedAt) return true;\r\n return new Date(resolvedAt).getTime() > cutoff;\r\n });\r\n\r\n if (kept.length < before) {\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n await atomicWriteJson(pendingFilePath(healingDir), kept);\r\n }\r\n\r\n return before - kept.length;\r\n}\r\n\r\n/**\r\n * Returns summary statistics for the healing store.\r\n */\r\nexport async function getHealingStats(rootDir: string): Promise<{\r\n pending: number;\r\n accepted: number;\r\n rejected: number;\r\n total: number;\r\n}> {\r\n const events = await readPendingEvents(rootDir);\r\n const pending = events.filter((e) => e.status === 'pending').length;\r\n const accepted = events.filter((e) => e.status === 'accepted').length;\r\n const rejected = events.filter((e) => e.status === 'rejected').length;\r\n return { pending, accepted, rejected, total: events.length };\r\n}\r\n\r\n/**\r\n * Lists all healing report runIds (newest-first by mtime).\r\n */\r\nexport async function listHealingReportIds(rootDir: string): Promise<string[]> {\r\n const healingDir = path.join(rootDir, HEALING_DIR);\r\n if (!(await fs.pathExists(healingDir))) return [];\r\n\r\n const entries = await fs.readdir(healingDir, { withFileTypes: true });\r\n const ids = entries\r\n .filter((e) => e.isFile() && e.name.startsWith(REPORT_PREFIX) && e.name.endsWith('.json'))\r\n .map((e) => e.name.slice(REPORT_PREFIX.length, -'.json'.length));\r\n\r\n const withStats = await Promise.all(\r\n ids.map(async (id) => {\r\n const stat = await fs.stat(path.join(healingDir, `${REPORT_PREFIX}${id}.json`));\r\n return { id, mtime: stat.mtimeMs };\r\n }),\r\n );\r\n\r\n return withStats.sort((a, b) => b.mtime - a.mtime).map((x) => x.id);\r\n}\r\n","/**\r\n * Healing routes — exactly as specified.\r\n *\r\n * GET /api/healing — list all healing events\r\n * GET /api/healing/pending — list only pending heals\r\n * PATCH /api/healing/:id/accept — accept heal → update .test.json\r\n * PATCH /api/healing/:id/reject — reject heal\r\n * POST /api/healing/accept-all — accept all pending heals\r\n * POST /api/healing/apply-from-report — apply heals from CI report file\r\n * GET /api/healing/stats — statistics\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport {\r\n readPendingEvents,\r\n acceptHealingEvent,\r\n rejectHealingEvent,\r\n getHealingStats,\r\n listHealingReportIds,\r\n readHealingReport,\r\n deleteHealingEvent,\r\n deleteHealingEvents,\r\n clearAllHealingEvents,\r\n} from '../../storage/healing-store.js';\r\nimport { readCase, updateCase, findCasePathById } from '../../storage/case-store.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('routes/healing');\r\n\r\nconst ApplyFromReportBody = z.object({\r\n reportPath: z.string().min(1),\r\n});\r\n\r\nconst DeleteBulkBody = z.object({\r\n ids: z.array(z.string().min(1)).min(1),\r\n});\r\n\r\nexport async function healingRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n const testsDir = path.join(rootDir, 'tests');\r\n\r\n // GET /api/healing\r\n fastify.get('/healing', async (_req, reply) => {\r\n try {\r\n const reportIds = await listHealingReportIds(rootDir);\r\n const allEvents = [];\r\n for (const id of reportIds) {\r\n const report = await readHealingReport(rootDir, id);\r\n allEvents.push(...report.events);\r\n }\r\n return reply.send(allEvents);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to list healing events', err);\r\n }\r\n });\r\n\r\n // GET /api/healing/pending\r\n fastify.get('/healing/pending', async (_req, reply) => {\r\n try {\r\n const events = await readPendingEvents(rootDir);\r\n return reply.send(events);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to read pending healing events', err);\r\n }\r\n });\r\n\r\n // GET /api/healing/stats\r\n fastify.get('/healing/stats', async (_req, reply) => {\r\n try {\r\n const stats = await getHealingStats(rootDir);\r\n return reply.send(stats);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get healing stats', err);\r\n }\r\n });\r\n\r\n // PATCH /api/healing/:id/accept\r\n fastify.patch<{ Params: { id: string } }>('/healing/:id/accept', async (req, reply) => {\r\n try {\r\n const event = await acceptHealingEvent(rootDir, req.params.id);\r\n\r\n // Apply the healed code to the .test.json file\r\n await applyHealToCase(testsDir, event.caseId, event.stepId, event.healedCode);\r\n\r\n logger.info({ id: req.params.id, caseId: event.caseId, stepId: event.stepId }, 'Healing accepted and applied');\r\n return reply.send(event);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to accept healing event', err);\r\n }\r\n });\r\n\r\n // PATCH /api/healing/:id/reject\r\n fastify.patch<{ Params: { id: string } }>('/healing/:id/reject', async (req, reply) => {\r\n try {\r\n const event = await rejectHealingEvent(rootDir, req.params.id);\r\n return reply.send(event);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to reject healing event', err);\r\n }\r\n });\r\n\r\n // POST /api/healing/accept-all\r\n fastify.post('/healing/accept-all', async (_req, reply) => {\r\n try {\r\n const pending = await readPendingEvents(rootDir);\r\n const results = [];\r\n\r\n for (const event of pending) {\r\n try {\r\n await acceptHealingEvent(rootDir, event.id);\r\n await applyHealToCase(testsDir, event.caseId, event.stepId, event.healedCode);\r\n results.push({ id: event.id, status: 'accepted' });\r\n logger.info({ id: event.id }, 'Bulk healing accepted');\r\n } catch (err) {\r\n results.push({ id: event.id, status: 'failed', error: err instanceof Error ? err.message : String(err) });\r\n }\r\n }\r\n\r\n return reply.send({ accepted: results.filter((r) => r.status === 'accepted').length, results });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to accept all healing events', err);\r\n }\r\n });\r\n\r\n // POST /api/healing/clear-all — delete all events (static path — must be before /:id)\r\n fastify.post('/healing/clear-all', async (_req, reply) => {\r\n try {\r\n const deleted = await clearAllHealingEvents(rootDir);\r\n return reply.send({ deleted });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to clear healing events', err);\r\n }\r\n });\r\n\r\n // POST /api/healing/delete-bulk — delete multiple events by id (static path — must be before /:id)\r\n fastify.post('/healing/delete-bulk', async (req, reply) => {\r\n const parsed = DeleteBulkBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n try {\r\n const deleted = await deleteHealingEvents(rootDir, parsed.data.ids);\r\n return reply.send({ deleted });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete healing events', err);\r\n }\r\n });\r\n\r\n // DELETE /api/healing/:id — delete single event (parametric — must be after all static routes)\r\n fastify.delete<{ Params: { id: string } }>('/healing/:id', async (req, reply) => {\r\n try {\r\n await deleteHealingEvent(rootDir, req.params.id);\r\n return reply.status(204).send();\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to delete healing event', err);\r\n }\r\n });\r\n\r\n // POST /api/healing/apply-from-report\r\n fastify.post('/healing/apply-from-report', async (req, reply) => {\r\n const parsed = ApplyFromReportBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n try {\r\n const { default: fs } = await import('fs-extra');\r\n const report = await fs.readJson(parsed.data.reportPath) as { events?: Array<{ id: string; caseId: string; stepId: string; healedCode: string }> };\r\n\r\n if (!Array.isArray(report.events)) {\r\n return reply.status(400).send({ error: 'Invalid healing report format' });\r\n }\r\n\r\n const results = [];\r\n for (const event of report.events) {\r\n try {\r\n await applyHealToCase(testsDir, event.caseId, event.stepId, event.healedCode);\r\n results.push({ id: event.id, status: 'applied' });\r\n } catch (err) {\r\n results.push({ id: event.id, status: 'failed', error: err instanceof Error ? err.message : String(err) });\r\n }\r\n }\r\n\r\n return reply.send({ applied: results.filter((r) => r.status === 'applied').length, results });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to apply healing report', err);\r\n }\r\n });\r\n}\r\n\r\n// ─── Helper: apply healed code to a case file ─────────────────────────────────\r\n\r\nasync function applyHealToCase(\r\n testsDir: string,\r\n caseId: string,\r\n stepId: string,\r\n healedCode: string,\r\n): Promise<void> {\r\n // Search all suites for the case\r\n const casePath = await findCasePath(testsDir, caseId);\r\n if (!casePath) {\r\n throw new Error(`Case \"${caseId}\" not found in tests directory`);\r\n }\r\n\r\n const tc = await readCase(casePath);\r\n const step = tc.steps.find((s) => s.id === stepId);\r\n if (!step) {\r\n throw new Error(`Step \"${stepId}\" not found in case \"${caseId}\"`);\r\n }\r\n\r\n const updatedSteps = tc.steps.map((s) =>\r\n s.id === stepId\r\n ? { ...s, generatedCode: healedCode, lastHealed: new Date().toISOString() }\r\n : s,\r\n );\r\n\r\n await updateCase(casePath, { steps: updatedSteps });\r\n}\r\n\r\n/**\r\n * Searches every suite directory for a case whose UUID matches `caseId`.\r\n * Mirrors listSuiteDirs: scans tests/ui/, tests/api/, and tests/ (legacy root).\r\n * Uses findCasePathById (reads each .test.json and checks the `id` field)\r\n * so it works regardless of the file's slug name.\r\n */\r\nasync function findCasePath(testsDir: string, caseId: string): Promise<string | null> {\r\n const { default: fs } = await import('fs-extra');\r\n const { listSuiteDirs } = await import('../../storage/suite-store.js');\r\n\r\n const suiteDirs = await listSuiteDirs(testsDir);\r\n for (const suiteDir of suiteDirs) {\r\n const casePath = await findCasePathById(suiteDir, caseId);\r\n if (casePath) return casePath;\r\n }\r\n return null;\r\n}\r\n","import { z } from 'zod';\r\n\r\nexport const RunStatusSchema = z.enum(['pending', 'running', 'passed', 'failed', 'skipped']);\r\nexport type RunStatus = z.infer<typeof RunStatusSchema>;\r\n\r\nexport interface RunConfig {\r\n all?: boolean;\r\n type?: string; // Filter suites by suite type (ui, api, audit, performance)\r\n suite?: string;\r\n tag?: string;\r\n test?: string;\r\n browsers?: string[];\r\n env?: string;\r\n parallel?: number;\r\n headed?: boolean;\r\n ci?: boolean;\r\n reporter?: string[];\r\n noHealing?: boolean;\r\n screenshot?: 'off' | 'on' | 'only-on-failure';\r\n video?: 'off' | 'on' | 'on-first-retry' | 'retain-on-failure';\r\n trace?: 'off' | 'on' | 'on-first-retry' | 'retain-on-failure';\r\n /** Playwright device descriptor name (e.g. 'iPhone 15 Pro') — undefined = no emulation. */\r\n device?: string;\r\n}\r\n\r\nexport const ApiRequestSchema = z.object({\r\n method: z.string(),\r\n url: z.string(),\r\n headers: z.record(z.string()).optional(),\r\n body: z.string().optional(),\r\n}).optional();\r\n\r\nexport const ApiResponseSchema = z.object({\r\n status: z.number(),\r\n statusText: z.string(),\r\n headers: z.record(z.string()).optional(),\r\n body: z.string().optional(),\r\n duration: z.number(),\r\n}).optional();\r\n\r\n// Helper: accept number | null | undefined, always store as number | undefined\r\nconst optionalNum = z.number().nullish().transform((v) => v ?? undefined);\r\n\r\n// Individual Lighthouse audit result (pass / partial / fail / not-applicable)\r\nexport const AuditItemSchema = z.object({\r\n id: z.string(),\r\n title: z.string(),\r\n passed: z.boolean(), // true = score === 1\r\n partial: z.boolean().optional(), // true = 0 < score < 1 (needs work)\r\n na: z.boolean().optional(), // true = score === null (not applicable)\r\n});\r\nexport type AuditItem = z.infer<typeof AuditItemSchema>;\r\n\r\nexport const PageLoadMetricSchema = z.object({\r\n url: z.string(),\r\n stepIndex: z.number().int(),\r\n stepInstruction: z.string(),\r\n score: optionalNum, // Performance score 0-100 (pre-multiplied in runner)\r\n a11yScore: optionalNum, // Accessibility score 0-100 (pre-multiplied in runner)\r\n seoScore: optionalNum, // SEO score 0-100 (pre-multiplied in runner)\r\n fcp: optionalNum, // First Contentful Paint (ms)\r\n lcp: optionalNum, // Largest Contentful Paint (ms)\r\n cls: optionalNum, // Cumulative Layout Shift (score)\r\n ttfb: optionalNum, // Time to First Byte (ms)\r\n tbt: optionalNum, // Total Blocking Time (ms)\r\n si: optionalNum, // Speed Index (ms)\r\n tti: optionalNum, // Time to Interactive (ms)\r\n inp: optionalNum, // Interaction to Next Paint (ms)\r\n // Individual audit items for Accessibility and SEO categories\r\n a11yAudits: z.array(AuditItemSchema).optional(),\r\n seoAudits: z.array(AuditItemSchema).optional(),\r\n lighthouseError: z.string().optional(),\r\n});\r\nexport type PageLoadMetric = z.infer<typeof PageLoadMetricSchema>;\r\n\r\nexport const StepResultSchema = z.object({\r\n stepId: z.string(),\r\n instruction: z.string(),\r\n status: RunStatusSchema,\r\n code: z.string(),\r\n error: z.string().optional(),\r\n duration: z.number(),\r\n screenshotPath: z.string().optional(),\r\n healed: z.boolean().optional(),\r\n healedCode: z.string().optional(),\r\n stepType: z.enum(['ui', 'api', 'mock']).optional(),\r\n apiRequest: ApiRequestSchema,\r\n apiResponse: ApiResponseSchema,\r\n navigatedToUrl: z.string().optional(),\r\n auditUrl: z.string().optional(), // URL captured when step has runAudit=true (may not have navigated)\r\n});\r\n\r\nexport const TestCaseResultSchema = z.object({\r\n caseId: z.string(),\r\n caseName: z.string(),\r\n status: RunStatusSchema,\r\n steps: z.array(StepResultSchema),\r\n duration: z.number(),\r\n browser: z.string(),\r\n /** Playwright device descriptor used for this case (undefined = no emulation). */\r\n device: z.string().optional(),\r\n startedAt: z.string().datetime(),\r\n finishedAt: z.string().datetime(),\r\n videoPath: z.string().optional(),\r\n tracePath: z.string().optional(),\r\n dataRowIndex: z.number().int().optional(),\r\n dataRow: z.record(z.string()).optional(),\r\n pageLoads: z.array(PageLoadMetricSchema).default([]),\r\n});\r\n\r\nexport const SuiteResultSchema = z.object({\r\n suiteId: z.string(),\r\n suiteName: z.string(),\r\n suiteType: z.enum(['ui', 'api', 'audit', 'performance']).optional(),\r\n status: RunStatusSchema,\r\n cases: z.array(TestCaseResultSchema),\r\n duration: z.number(),\r\n browser: z.string(),\r\n startedAt: z.string().datetime(),\r\n finishedAt: z.string().datetime(),\r\n});\r\n\r\nexport const RunResultSchema = z.object({\r\n runId: z.string(),\r\n status: RunStatusSchema,\r\n environment: z.string().optional(),\r\n suites: z.array(SuiteResultSchema),\r\n duration: z.number(),\r\n startedAt: z.string().datetime(),\r\n finishedAt: z.string().datetime(),\r\n totalTests: z.number().int(),\r\n passed: z.number().int(),\r\n failed: z.number().int(),\r\n skipped: z.number().int(),\r\n logFilePath: z.string().optional(),\r\n});\r\n\r\nexport type StepResult = z.infer<typeof StepResultSchema>;\r\nexport type TestCaseResult = z.infer<typeof TestCaseResultSchema>;\r\nexport type SuiteResult = z.infer<typeof SuiteResultSchema>;\r\nexport type RunResult = z.infer<typeof RunResultSchema>;\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { RunResult, RunResultSchema } from '../types/run.js';\r\nimport { StorageError, ValidationError } from '../utils/errors.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\n\r\nconst logger = createChildLogger('result-store');\r\n\r\nconst RESULTS_DIR = 'results';\r\nconst RUNS_DIR = 'runs';\r\n\r\nfunction runFilePath(resultsDir: string, runId: string): string {\r\n return path.join(resultsDir, RUNS_DIR, `${runId}.json`);\r\n}\r\n\r\n/**\r\n * Saves a run result to results/runs/{runId}.json.\r\n */\r\nexport async function writeResult(rootDir: string, result: RunResult): Promise<void> {\r\n const schema = RunResultSchema.safeParse(result);\r\n if (!schema.success) {\r\n const issues = schema.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Cannot write invalid run result:\\n${issues}`,\r\n 'result',\r\n 'INVALID_RESULT',\r\n );\r\n }\r\n\r\n const filePath = runFilePath(path.join(rootDir, RESULTS_DIR), result.runId);\r\n await atomicWriteJson(filePath, schema.data);\r\n logger.info({ runId: result.runId, status: result.status }, 'Run result saved');\r\n}\r\n\r\n/**\r\n * Reads a run result by runId.\r\n */\r\nexport async function readResult(rootDir: string, runId: string): Promise<RunResult> {\r\n const filePath = runFilePath(path.join(rootDir, RESULTS_DIR), runId);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new StorageError(\r\n `Run result not found for runId \"${runId}\".`,\r\n filePath,\r\n 'RESULT_NOT_FOUND',\r\n );\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = RunResultSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n const issues = result.error.issues\r\n .map((i) => ` • ${i.path.join('.')}: ${i.message}`)\r\n .join('\\n');\r\n throw new ValidationError(\r\n `Invalid run result at \"${filePath}\":\\n${issues}`,\r\n 'result',\r\n 'INVALID_RESULT',\r\n );\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Lists all run result IDs, sorted newest-first.\r\n */\r\nexport async function listResultIds(rootDir: string): Promise<string[]> {\r\n const runsDir = path.join(rootDir, RESULTS_DIR, RUNS_DIR);\r\n if (!(await fs.pathExists(runsDir))) return [];\r\n\r\n const entries = await fs.readdir(runsDir, { withFileTypes: true });\r\n const ids = entries\r\n .filter((e) => e.isFile() && e.name.endsWith('.json'))\r\n .map((e) => e.name.replace('.json', ''));\r\n\r\n // Sort newest-first by reading mtime\r\n const withStats = await Promise.all(\r\n ids.map(async (id) => {\r\n const stat = await fs.stat(path.join(runsDir, `${id}.json`));\r\n return { id, mtime: stat.mtimeMs };\r\n }),\r\n );\r\n\r\n return withStats.sort((a, b) => b.mtime - a.mtime).map((x) => x.id);\r\n}\r\n\r\n/**\r\n * Lists run results (metadata only — no step details) for dashboard display.\r\n */\r\nexport async function listResults(\r\n rootDir: string,\r\n limit = 20,\r\n): Promise<(Pick<RunResult, 'runId' | 'status' | 'environment' | 'startedAt' | 'finishedAt' | 'totalTests' | 'passed' | 'failed' | 'skipped' | 'duration'> & { suiteIds: string[] })[]> {\r\n const ids = await listResultIds(rootDir);\r\n const results = [];\r\n\r\n for (const id of ids.slice(0, limit)) {\r\n try {\r\n const result = await readResult(rootDir, id);\r\n results.push({\r\n runId: result.runId,\r\n status: result.status,\r\n environment: result.environment,\r\n startedAt: result.startedAt,\r\n finishedAt: result.finishedAt,\r\n totalTests: result.totalTests,\r\n passed: result.passed,\r\n failed: result.failed,\r\n skipped: result.skipped,\r\n duration: result.duration,\r\n suiteIds: result.suites.map((s) => s.suiteId),\r\n });\r\n } catch (err) {\r\n logger.warn({ runId: id, err }, 'Failed to read run result — skipping');\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Deletes a run result file.\r\n */\r\nexport async function deleteResult(rootDir: string, runId: string): Promise<void> {\r\n const filePath = runFilePath(path.join(rootDir, RESULTS_DIR), runId);\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new StorageError(\r\n `Run result not found for runId \"${runId}\".`,\r\n filePath,\r\n 'RESULT_NOT_FOUND',\r\n );\r\n }\r\n await fs.remove(filePath);\r\n logger.info({ runId }, 'Run result deleted');\r\n}\r\n\r\n/**\r\n * Returns the screenshots directory path for a run.\r\n */\r\nexport function screenshotsDir(rootDir: string): string {\r\n return path.join(rootDir, RESULTS_DIR, 'screenshots');\r\n}\r\n\r\n/**\r\n * Returns the videos directory path.\r\n */\r\nexport function videosDir(rootDir: string): string {\r\n return path.join(rootDir, RESULTS_DIR, 'videos');\r\n}\r\n\r\n/**\r\n * Returns the traces directory path.\r\n */\r\nexport function tracesDir(rootDir: string): string {\r\n return path.join(rootDir, RESULTS_DIR, 'traces');\r\n}\r\n","/**\r\n * Browser Manager — Playwright browser lifecycle management.\r\n * Launches browsers, creates contexts with the right config,\r\n * and ensures clean teardown on error or process exit.\r\n */\r\nimport { chromium, firefox, webkit, request as pwRequest, devices } from 'playwright';\r\nimport type { Browser, BrowserContext, Page, APIRequestContext } from 'playwright';\r\nimport type { AutotestConfig } from '../types/config.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('browser-manager');\r\n\r\n/** Extended Page type with console log buffer attached. */\r\ninterface PageWithLogs extends Page {\r\n __consoleLogs?: Array<{ type: string; text: string; timestamp: number }>;\r\n}\r\n\r\nexport class BrowserManager {\r\n private readonly browsers = new Map<string, Browser>();\r\n\r\n // ─── Launch ───────────────────────────────────────────────────────────────\r\n\r\n async launchBrowser(browserName: string, config: AutotestConfig): Promise<Browser> {\r\n const existing = this.browsers.get(browserName);\r\n if (existing) return existing;\r\n\r\n const launcher =\r\n browserName === 'firefox' ? firefox : browserName === 'webkit' ? webkit : chromium;\r\n\r\n const browser = await launcher.launch({ headless: config.headless });\r\n this.browsers.set(browserName, browser);\r\n logger.info({ browser: browserName, headless: config.headless }, 'Browser launched');\r\n return browser;\r\n }\r\n\r\n // ─── Context ──────────────────────────────────────────────────────────────\r\n\r\n async newContext(\r\n browser: Browser,\r\n config: AutotestConfig,\r\n videosDir?: string,\r\n ): Promise<BrowserContext> {\r\n // ── Device emulation ──────────────────────────────────────────────────────\r\n // When a device name is configured, merge the full Playwright device descriptor\r\n // (viewport, userAgent, deviceScaleFactor, isMobile, hasTouch) into context options.\r\n const deviceDescriptor = config.device && devices[config.device] ? devices[config.device] : null;\r\n if (config.device && !deviceDescriptor) {\r\n logger.warn({ device: config.device }, 'Unknown Playwright device — falling back to configured viewport');\r\n }\r\n\r\n const contextOptions: Parameters<Browser['newContext']>[0] = {\r\n // Do NOT set baseURL here — it causes Playwright to pre-navigate the page\r\n // before the first step runs, resulting in the URL loading twice.\r\n // Each test's first step is responsible for navigating to the URL.\r\n ...(deviceDescriptor ?? {}),\r\n // Device descriptor may override viewport; fall back to configured viewport\r\n viewport: deviceDescriptor?.viewport ?? config.viewport ?? { width: 1280, height: 720 },\r\n // Ensure each test context starts completely clean (no shared cookies/storage)\r\n storageState: undefined,\r\n };\r\n\r\n if (config.video !== 'off' && videosDir) {\r\n contextOptions.recordVideo = { dir: videosDir };\r\n }\r\n\r\n const context = await browser.newContext(contextOptions);\r\n\r\n // Inject element highlighter for all modes — visible in headed runs and\r\n // captured in screenshots/videos in headless runs.\r\n await context.addInitScript(() => {\r\n const STYLE = `\r\n outline: 3px solid #3b82f6 !important;\r\n outline-offset: 3px !important;\r\n box-shadow: 0 0 0 6px rgba(59,130,246,0.20) !important;\r\n transition: outline 0.08s ease, box-shadow 0.08s ease !important;\r\n `;\r\n let lastEl: HTMLElement | null = null;\r\n function clearHighlight() {\r\n if (lastEl) {\r\n lastEl.style.cssText = lastEl.style.cssText\r\n .replace(/outline[^;]*;?/g, '')\r\n .replace(/box-shadow[^;]*;?/g, '')\r\n .replace(/transition[^;]*;?/g, '');\r\n lastEl = null;\r\n }\r\n }\r\n function applyHighlight(el: Element | null) {\r\n if (!el || !(el instanceof HTMLElement)) return;\r\n clearHighlight();\r\n lastEl = el;\r\n lastEl.style.cssText += STYLE;\r\n setTimeout(clearHighlight, 1800);\r\n }\r\n // focus fires on fill/type; mousedown fires on click\r\n document.addEventListener('focus', (e) => applyHighlight(e.target as Element), true);\r\n document.addEventListener('mousedown', (e) => applyHighlight(e.target as Element), true);\r\n });\r\n\r\n if (config.trace !== 'off') {\r\n await context.tracing.start({ screenshots: true, snapshots: true, sources: false });\r\n }\r\n\r\n return context;\r\n }\r\n\r\n async newPage(context: BrowserContext): Promise<Page> {\r\n const page = await context.newPage();\r\n\r\n // ── Capture console logs from the page for live streaming to UI ──\r\n // Filter out noisy browser network errors that come from the target site, not our code\r\n const IGNORED_CONSOLE_PATTERNS = [\r\n /Failed to load resource/i,\r\n /net::ERR_/i,\r\n /the server responded with a status of/i,\r\n /Access to .* has been blocked by CORS/i,\r\n /Mixed Content:/i,\r\n /favicon\\.ico/i,\r\n ];\r\n const consoleLogs: Array<{ type: string; text: string; timestamp: number }> = [];\r\n page.on('console', (msg) => {\r\n const text = msg.text();\r\n if (IGNORED_CONSOLE_PATTERNS.some((p) => p.test(text))) return;\r\n consoleLogs.push({\r\n type: msg.type(),\r\n text,\r\n timestamp: Date.now(),\r\n });\r\n });\r\n page.on('pageerror', (err) => {\r\n // Filter out highlighter-injected script noise\r\n if (err.message?.includes('appendChild') && err.message?.includes('null')) return;\r\n consoleLogs.push({\r\n type: 'error',\r\n text: `[PageError] ${err.message}`,\r\n timestamp: Date.now(),\r\n });\r\n });\r\n // Attach logs to the page for retrieval by the runner\r\n (page as PageWithLogs).__consoleLogs = consoleLogs;\r\n\r\n return page;\r\n }\r\n\r\n /** Drain and return accumulated console logs from a page, then clear the buffer. */\r\n drainConsoleLogs(page: Page): Array<{ type: string; text: string; timestamp: number }> {\r\n const logs = (page as PageWithLogs).__consoleLogs;\r\n if (!logs) return [];\r\n const drained = [...logs];\r\n logs.length = 0;\r\n return drained;\r\n }\r\n\r\n // ─── API-only (no browser at all) ──────────────────────────────────────────\r\n\r\n private apiContexts: APIRequestContext[] = [];\r\n\r\n /**\r\n * Creates a standalone Playwright APIRequestContext — NO browser process.\r\n * Returns a fake Page-like object with only { request } so that generated\r\n * API code (`page.request.get(...)`) works without any browser overhead.\r\n */\r\n async createApiOnlyPage(baseUrl?: string): Promise<Page> {\r\n const apiCtx = await pwRequest.newContext({\r\n baseURL: baseUrl || undefined,\r\n });\r\n this.apiContexts.push(apiCtx);\r\n\r\n // Build a thin proxy that satisfies `page.request.*` calls from generated code\r\n const fakePage = {\r\n request: apiCtx,\r\n // Stubs for common page methods that might be called but are irrelevant for API tests\r\n url: () => baseUrl ?? '',\r\n title: async () => '',\r\n goto: async () => null,\r\n waitForLoadState: async () => {},\r\n setDefaultTimeout: () => {},\r\n setDefaultNavigationTimeout: () => {},\r\n screenshot: async () => Buffer.alloc(0),\r\n video: () => null,\r\n close: async () => {},\r\n } as unknown as Page;\r\n\r\n logger.info('Created API-only request context (zero browser)');\r\n return fakePage;\r\n }\r\n\r\n /** Closes all API request contexts. */\r\n async closeApiContexts(): Promise<void> {\r\n for (const ctx of this.apiContexts) {\r\n await ctx.dispose().catch(() => {});\r\n }\r\n this.apiContexts = [];\r\n }\r\n\r\n // ─── Teardown ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Stops tracing (if active) and closes the context.\r\n * Pass tracePath only when the trace should be saved.\r\n */\r\n async closeContext(\r\n context: BrowserContext,\r\n config: AutotestConfig,\r\n tracePath?: string,\r\n ): Promise<void> {\r\n if (config.trace !== 'off') {\r\n try {\r\n if (tracePath) {\r\n await context.tracing.stop({ path: tracePath });\r\n } else {\r\n await context.tracing.stop();\r\n }\r\n } catch (err) {\r\n logger.debug({ err }, 'Tracing stop failed — ignoring');\r\n }\r\n }\r\n await context.close().catch((err: unknown) => {\r\n logger.debug({ err }, 'Context close failed — ignoring');\r\n });\r\n }\r\n\r\n /** Closes all open browsers and API contexts. Called at the end of every run. */\r\n async closeAll(): Promise<void> {\r\n await this.closeApiContexts();\r\n for (const [name, browser] of this.browsers) {\r\n try {\r\n await browser.close();\r\n logger.debug({ browser: name }, 'Browser closed');\r\n } catch (err) {\r\n logger.warn({ err, browser: name }, 'Error closing browser');\r\n }\r\n }\r\n this.browsers.clear();\r\n }\r\n\r\n get openBrowserCount(): number {\r\n return this.browsers.size;\r\n }\r\n}\r\n","/**\r\n * Healing Budget Controller — decides whether a failing step should be healed,\r\n * and tracks daily AI spend to stay within the configured budget.\r\n *\r\n * From the spec:\r\n * - Skip if daily budget exhausted\r\n * - Skip if same step has failed healing 3+ times (needs human)\r\n * - Skip if error is environmental (timeout / network / DNS)\r\n * - Batch if 3+ tests failing on the same page URL\r\n * - Otherwise heal individually\r\n */\r\nimport type { StepFailure, HealingDecision } from '../types/healing.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('healing-budget');\r\n\r\n/** Patterns that indicate infrastructure / environment problems, not selector issues. */\r\nconst ENVIRONMENTAL_PATTERNS: ReadonlyArray<RegExp> = [\r\n /timeout/i,\r\n /ECONNREFUSED/i,\r\n /ENOTFOUND/i,\r\n /ETIMEDOUT/i,\r\n /net::ERR/i,\r\n /ERR_NAME_NOT_RESOLVED/i,\r\n /DNS/i,\r\n /socket hang up/i,\r\n];\r\n\r\nexport class HealingBudget {\r\n private spent = 0;\r\n /** stepId → number of times healing itself has failed for that step */\r\n private readonly healFailures = new Map<string, number>();\r\n /** pageUrl → list of failures on that page (for batch detection) */\r\n private readonly pageFailures = new Map<string, StepFailure[]>();\r\n\r\n constructor(private readonly dailyBudget: number) {}\r\n\r\n // ─── Main decision ────────────────────────────────────────────────────────\r\n\r\n shouldHeal(failure: StepFailure): HealingDecision {\r\n // 1. Budget exhausted\r\n if (this.spent >= this.dailyBudget) {\r\n logger.warn(\r\n { spent: this.spent, budget: this.dailyBudget },\r\n 'Daily healing budget exhausted',\r\n );\r\n return { heal: false, reason: 'Daily budget exhausted' };\r\n }\r\n\r\n // 2. Persistent failure — gave up after 3 heal attempts\r\n const failCount = this.healFailures.get(failure.stepId) ?? 0;\r\n if (failCount >= 3) {\r\n return {\r\n heal: false,\r\n reason: `Persistent failure — step \"${failure.stepId}\" has failed healing ${failCount} times. Needs manual fix.`,\r\n };\r\n }\r\n\r\n // 3. Environmental error — no point sending to AI\r\n if (this.isEnvironmental(failure.error)) {\r\n return { heal: false, reason: 'Environmental error — retry instead' };\r\n }\r\n\r\n // 4. Track page-level failures\r\n const pageFails = this.pageFailures.get(failure.pageUrl) ?? [];\r\n if (!pageFails.some((f) => f.stepId === failure.stepId)) {\r\n pageFails.push(failure);\r\n this.pageFailures.set(failure.pageUrl, pageFails);\r\n }\r\n\r\n // 5. Batch heal when 3+ steps fail on the same page\r\n if (pageFails.length >= 3) {\r\n return {\r\n heal: true,\r\n strategy: 'batch',\r\n reason: `Batch heal — ${pageFails.length} failures on ${failure.pageUrl}, fix once for all`,\r\n };\r\n }\r\n\r\n // 6. Standard individual heal\r\n return { heal: true, strategy: 'individual', reason: 'Standard heal' };\r\n }\r\n\r\n // ─── Tracking ─────────────────────────────────────────────────────────────\r\n\r\n /** Call after each AI healing call with the estimated cost. */\r\n recordSpend(amountUsd: number): void {\r\n this.spent += amountUsd;\r\n logger.debug({ spend: amountUsd, total: this.spent }, 'Healing budget spend recorded');\r\n }\r\n\r\n /** Call when a healing attempt itself fails (AI returned bad code, etc.). */\r\n recordHealFailure(stepId: string): void {\r\n this.healFailures.set(stepId, (this.healFailures.get(stepId) ?? 0) + 1);\r\n }\r\n\r\n // ─── Accessors ────────────────────────────────────────────────────────────\r\n\r\n get totalSpent(): number {\r\n return this.spent;\r\n }\r\n\r\n get remainingBudget(): number {\r\n return Math.max(0, this.dailyBudget - this.spent);\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────────\r\n\r\n private isEnvironmental(error: string): boolean {\r\n return ENVIRONMENTAL_PATTERNS.some((p) => p.test(error));\r\n }\r\n}\r\n","/**\r\n * Healing Reporter — collects HealingEvents during a run and persists them.\r\n *\r\n * During execution healing events are kept in memory only.\r\n * At run-end they are:\r\n * 1. Appended to the run-specific healing report JSON (results/healing/)\r\n * 2. Appended to the pending-events list (for apply-healing CLI / Studio UI)\r\n */\r\nimport { randomUUID } from 'crypto';\r\nimport type { HealingEvent, HealingReport } from '../types/healing.js';\r\nimport { appendPendingEvent, writeHealingReport } from '../storage/healing-store.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('healing-report');\r\n\r\nexport interface HealEventInput {\r\n runId: string;\r\n suiteId: string;\r\n caseId: string;\r\n stepId: string;\r\n stepInstruction: string;\r\n failedCode: string;\r\n healedCode: string;\r\n error: string;\r\n strategy: HealingEvent['strategy'];\r\n level: number;\r\n pageUrl: string;\r\n}\r\n\r\nexport class HealingReporter {\r\n private readonly events: HealingEvent[] = [];\r\n\r\n /** Records a successful healing event (called by executor after each healed step). */\r\n record(input: HealEventInput): void {\r\n const event: HealingEvent = {\r\n id: randomUUID(),\r\n runId: input.runId,\r\n suiteId: input.suiteId,\r\n caseId: input.caseId,\r\n stepId: input.stepId,\r\n stepInstruction: input.stepInstruction,\r\n failedCode: input.failedCode,\r\n healedCode: input.healedCode,\r\n error: input.error,\r\n strategy: input.strategy,\r\n level: input.level,\r\n status: 'pending',\r\n pageUrl: input.pageUrl,\r\n timestamp: new Date().toISOString(),\r\n };\r\n\r\n this.events.push(event);\r\n logger.info(\r\n { stepId: input.stepId, strategy: input.strategy, level: input.level },\r\n 'Healing event recorded',\r\n );\r\n }\r\n\r\n get eventCount(): number {\r\n return this.events.length;\r\n }\r\n\r\n /**\r\n * Persists all collected events at run-end:\r\n * - Writes the full HealingReport to results/healing/\r\n * - Appends each event to the pending list for UI / CLI review\r\n */\r\n async flush(rootDir: string, runId: string): Promise<void> {\r\n if (this.events.length === 0) return;\r\n\r\n const report: HealingReport = {\r\n runId,\r\n generatedAt: new Date().toISOString(),\r\n totalHeals: this.events.length,\r\n accepted: 0,\r\n rejected: 0,\r\n pending: this.events.length,\r\n events: [...this.events],\r\n };\r\n\r\n try {\r\n await writeHealingReport(rootDir, report);\r\n logger.info({ runId, count: this.events.length }, 'Healing report written');\r\n } catch (err) {\r\n logger.error({ err, runId }, 'Failed to write healing report');\r\n }\r\n\r\n // Append each event to the pending queue for Studio / apply-healing\r\n for (const event of this.events) {\r\n try {\r\n await appendPendingEvent(rootDir, event);\r\n } catch (err) {\r\n logger.warn({ err, eventId: event.id }, 'Failed to append pending healing event');\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Allure Reporter — writes allure-compatible result JSON files.\r\n *\r\n * allure-js-commons v3 dropped the class-based AllureRuntime API.\r\n * We write the standard Allure result JSON format directly, which is the\r\n * most reliable approach and avoids SDK version churn.\r\n *\r\n * Result files go to results/allure-results/ — run `allure generate` to\r\n * produce the HTML report.\r\n */\r\nimport path from 'path';\r\nimport { randomUUID } from 'crypto';\r\nimport fs from 'fs-extra';\r\nimport type { StepResult, TestCaseResult, SuiteResult, RunResult, PageLoadMetric } from '../types/run.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('allure-reporter');\r\n\r\n// ─── Allure result JSON types (subset of the Allure2 spec) ───────────────────\r\n\r\ninterface AllureAttachment {\r\n name: string;\r\n source: string;\r\n type: string;\r\n}\r\n\r\ninterface AllureStepResult {\r\n name: string;\r\n status: string;\r\n stage: string;\r\n start: number;\r\n stop: number;\r\n attachments: AllureAttachment[];\r\n parameters: unknown[];\r\n steps: AllureStepResult[];\r\n}\r\n\r\ninterface AllureTestResult {\r\n uuid: string;\r\n historyId: string;\r\n testCaseId: string;\r\n fullName: string;\r\n name: string;\r\n status: string;\r\n stage: string;\r\n start: number;\r\n stop: number;\r\n labels: Array<{ name: string; value: string }>;\r\n links: unknown[];\r\n parameters: unknown[];\r\n attachments: AllureAttachment[];\r\n steps: AllureStepResult[];\r\n statusDetails?: { message?: string; trace?: string };\r\n}\r\n\r\nexport class AllureReporter {\r\n private readonly resultsDir: string;\r\n private readonly environment: string;\r\n\r\n constructor(rootDir: string, runId: string, environment = 'dev') {\r\n // Per-run subdirectory so each run generates its own isolated allure report\r\n this.resultsDir = path.join(rootDir, 'results', 'allure-results', runId);\r\n this.environment = environment;\r\n }\r\n\r\n /** Writes one allure result JSON per test case + environment.properties. */\r\n async writeResults(runResult: RunResult): Promise<void> {\r\n await fs.ensureDir(this.resultsDir);\r\n\r\n // Write environment.properties for Allure \"Environment\" widget\r\n const envProps = [\r\n `Environment=${this.environment.toUpperCase()}`,\r\n `Framework=AutoMind`,\r\n ].join('\\n');\r\n await fs.writeFile(path.join(this.resultsDir, 'environment.properties'), envProps, 'utf-8');\r\n\r\n // Copy the run log file into allure results so it's attached to every test case\r\n let logFileName: string | undefined;\r\n if (runResult.logFilePath) {\r\n try {\r\n logFileName = path.basename(runResult.logFilePath);\r\n await this.copyAttachment(runResult.logFilePath).catch(() => {});\r\n logger.debug({ logFile: logFileName }, 'Log file copied to Allure results');\r\n } catch {\r\n logger.debug('Failed to copy log file to Allure results');\r\n }\r\n }\r\n\r\n let written = 0;\r\n for (const suite of runResult.suites) {\r\n for (const tc of suite.cases) {\r\n await this.writeTestResult(suite, tc, logFileName);\r\n written++;\r\n }\r\n }\r\n\r\n logger.info({ dir: this.resultsDir, written }, 'Allure results written');\r\n }\r\n\r\n // ─── Internal ─────────────────────────────────────────────────────────────\r\n\r\n private async writeTestResult(suite: SuiteResult, tc: TestCaseResult, logFileName?: string): Promise<void> {\r\n const uuid = randomUUID();\r\n const start = new Date(tc.startedAt).getTime();\r\n const stop = new Date(tc.finishedAt).getTime();\r\n\r\n const failedStep = tc.steps.find((s) => s.status === 'failed');\r\n\r\n // Build test-level attachments (video + trace + log file)\r\n const testAttachments: AllureAttachment[] = [];\r\n if (tc.videoPath) {\r\n const videoName = path.basename(tc.videoPath);\r\n const ext = path.extname(videoName).toLowerCase();\r\n const mime = ext === '.mp4' ? 'video/mp4' : 'video/webm';\r\n testAttachments.push({ name: 'Video Recording', source: videoName, type: mime });\r\n }\r\n if (tc.tracePath) {\r\n const traceName = path.basename(tc.tracePath);\r\n testAttachments.push({ name: 'Playwright Trace', source: traceName, type: 'application/zip' });\r\n }\r\n if (logFileName) {\r\n testAttachments.push({ name: 'Run Log', source: logFileName, type: 'text/plain' });\r\n }\r\n\r\n // ── Lighthouse audit attachments — one per category ─────────────────────\r\n const pageLoads = tc.pageLoads ?? [];\r\n if (pageLoads.length > 0) {\r\n const hasPerf = pageLoads.some(p => !p.lighthouseError && p.score != null);\r\n const hasA11y = pageLoads.some(p => !p.lighthouseError && (p.a11yScore != null || (p.a11yAudits?.length ?? 0) > 0));\r\n const hasSeo = pageLoads.some(p => !p.lighthouseError && (p.seoScore != null || (p.seoAudits?.length ?? 0) > 0));\r\n\r\n if (hasPerf) {\r\n const html = buildCategoryHtml(tc.caseName, pageLoads, 'performance');\r\n const file = `${uuid}-perf.html`;\r\n await fs.writeFile(path.join(this.resultsDir, file), html, 'utf-8');\r\n testAttachments.push({ name: '⚡ Performance Report', source: file, type: 'text/html' });\r\n }\r\n if (hasA11y) {\r\n const html = buildCategoryHtml(tc.caseName, pageLoads, 'accessibility');\r\n const file = `${uuid}-a11y.html`;\r\n await fs.writeFile(path.join(this.resultsDir, file), html, 'utf-8');\r\n testAttachments.push({ name: '♿ Accessibility Report', source: file, type: 'text/html' });\r\n }\r\n if (hasSeo) {\r\n const html = buildCategoryHtml(tc.caseName, pageLoads, 'seo');\r\n const file = `${uuid}-seo.html`;\r\n await fs.writeFile(path.join(this.resultsDir, file), html, 'utf-8');\r\n testAttachments.push({ name: '🔍 SEO Report', source: file, type: 'text/html' });\r\n }\r\n }\r\n\r\n const result: AllureTestResult = {\r\n uuid,\r\n historyId: `${suite.suiteId}::${tc.caseId}::${suite.browser}`,\r\n testCaseId: `${suite.suiteId}::${tc.caseId}`,\r\n fullName: `${suite.suiteName} > ${tc.caseName}`,\r\n name: tc.caseName,\r\n status: mapStatus(tc.status),\r\n stage: 'finished',\r\n start,\r\n stop,\r\n labels: [\r\n { name: 'suite', value: suite.suiteName },\r\n { name: 'browser', value: suite.browser },\r\n { name: 'framework', value: 'assuremind' },\r\n { name: 'tag', value: `ENV: ${this.environment.toUpperCase()}` },\r\n ],\r\n links: [],\r\n parameters: [],\r\n attachments: testAttachments,\r\n steps: tc.steps.map((s) => this.buildStepResult(s, start)),\r\n ...(failedStep?.error && {\r\n statusDetails: { message: failedStep.error },\r\n }),\r\n };\r\n\r\n const filePath = path.join(this.resultsDir, `${uuid}-result.json`);\r\n await fs.writeJson(filePath, result, { spaces: 2 });\r\n\r\n // Copy screenshots as allure attachments\r\n for (const step of tc.steps) {\r\n if (step.screenshotPath) {\r\n await this.copyAttachment(step.screenshotPath).catch(() => {});\r\n }\r\n }\r\n\r\n // Copy video as allure attachment\r\n if (tc.videoPath) {\r\n await this.copyAttachment(tc.videoPath).catch(() => {});\r\n }\r\n\r\n // Copy trace zip as allure attachment\r\n if (tc.tracePath) {\r\n await this.copyAttachment(tc.tracePath).catch(() => {});\r\n }\r\n }\r\n\r\n private buildStepResult(step: StepResult, caseStart: number): AllureStepResult {\r\n const stepStart = caseStart;\r\n const stepStop = caseStart + step.duration;\r\n const attachments: AllureAttachment[] = [];\r\n\r\n if (step.screenshotPath) {\r\n const name = path.basename(step.screenshotPath);\r\n attachments.push({ name: 'Screenshot', source: name, type: 'image/png' });\r\n }\r\n\r\n return {\r\n name: step.instruction,\r\n status: mapStatus(step.status),\r\n stage: 'finished',\r\n start: stepStart,\r\n stop: stepStop,\r\n attachments,\r\n parameters: [],\r\n steps: [],\r\n };\r\n }\r\n\r\n private async copyAttachment(screenshotPath: string): Promise<void> {\r\n const dest = path.join(this.resultsDir, path.basename(screenshotPath));\r\n await fs.copy(screenshotPath, dest, { overwrite: true });\r\n }\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────────────\r\n\r\nfunction mapStatus(status: string): string {\r\n switch (status) {\r\n case 'passed': return 'passed';\r\n case 'failed': return 'failed';\r\n case 'skipped': return 'skipped';\r\n default: return 'broken';\r\n }\r\n}\r\n\r\nfunction fmtMs(v: number | undefined): string {\r\n if (v == null) return '—';\r\n if (v < 1000) return `${Math.round(v)}ms`;\r\n return `${(v / 1000).toFixed(2)}s`;\r\n}\r\n\r\ntype MetricKey = 'fcp' | 'lcp' | 'cls' | 'ttfb' | 'tbt' | 'si' | 'tti' | 'inp';\r\n\r\nfunction rateMetric(key: MetricKey, v: number | undefined): 'good' | 'average' | 'poor' | 'na' {\r\n if (v == null) return 'na';\r\n const thresholds: Record<MetricKey, [number, number]> = {\r\n fcp: [1800, 3000], lcp: [2500, 4000], cls: [0.10, 0.25],\r\n ttfb: [800, 1800], tbt: [200, 600], si: [3400, 5800],\r\n tti: [3800, 7300], inp: [200, 500],\r\n };\r\n const [good, poor] = thresholds[key];\r\n return v < good ? 'good' : v < poor ? 'average' : 'poor';\r\n}\r\n\r\nfunction scoreColor(score: number | undefined): string {\r\n if (score == null) return '#94a3b8';\r\n if (score >= 90) return '#10b981';\r\n if (score >= 50) return '#f59e0b';\r\n return '#ef4444';\r\n}\r\n\r\nfunction buildCategoryHtml(caseName: string, pageLoads: PageLoadMetric[], category: 'performance' | 'accessibility' | 'seo'): string {\r\n const COLORS = { good: '#10b981', average: '#f59e0b', poor: '#ef4444', na: '#94a3b8' };\r\n\r\n const METRICS_DEF: Array<{ key: MetricKey; abbr: string; label: string }> = [\r\n { key: 'fcp', abbr: 'FCP', label: 'First Contentful Paint' },\r\n { key: 'lcp', abbr: 'LCP', label: 'Largest Contentful Paint' },\r\n { key: 'cls', abbr: 'CLS', label: 'Cumulative Layout Shift' },\r\n { key: 'ttfb', abbr: 'TTFB', label: 'Time to First Byte' },\r\n { key: 'tbt', abbr: 'TBT', label: 'Total Blocking Time' },\r\n { key: 'si', abbr: 'SI', label: 'Speed Index' },\r\n { key: 'tti', abbr: 'TTI', label: 'Time to Interactive' },\r\n { key: 'inp', abbr: 'INP', label: 'Interaction to Next Paint' },\r\n ];\r\n\r\n const fmtVal = (key: MetricKey, v: number | undefined) =>\r\n key === 'cls' && v != null ? v.toFixed(3) : fmtMs(v);\r\n\r\n /** Render one SVG score circle */\r\n const scoreCircleHtml = (score: number | undefined, label: string) => {\r\n const color = scoreColor(score);\r\n const circ = 2 * Math.PI * 24;\r\n const fill = score != null ? (score / 100) * circ : 0;\r\n const ratingLabel = score == null ? '—' : score >= 90 ? 'Good' : score >= 50 ? 'Needs Work' : 'Poor';\r\n return `\r\n <div style=\"flex:1;display:flex;flex-direction:column;align-items:center;padding:10px 8px;border-radius:10px;background:${color}12;border:2px solid ${color}44;\">\r\n <div style=\"position:relative;width:58px;height:58px;\">\r\n <svg width=\"58\" height=\"58\" viewBox=\"0 0 60 60\" style=\"transform:rotate(-90deg)\">\r\n <circle cx=\"30\" cy=\"30\" r=\"24\" fill=\"none\" stroke=\"${color}\" stroke-width=\"5\" stroke-opacity=\".15\"/>\r\n <circle cx=\"30\" cy=\"30\" r=\"24\" fill=\"none\" stroke=\"${color}\" stroke-width=\"5\"\r\n stroke-dasharray=\"${circ.toFixed(2)}\" stroke-dashoffset=\"${(circ - fill).toFixed(2)}\" stroke-linecap=\"round\"/>\r\n </svg>\r\n <div style=\"position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:15px;font-weight:900;color:${color};\">${score ?? '—'}</div>\r\n </div>\r\n <div style=\"font-size:9px;font-weight:700;color:${color};margin-top:4px;\">${ratingLabel}</div>\r\n <div style=\"font-size:9px;color:#64748b;margin-top:1px;text-align:center;\">${label}</div>\r\n </div>`;\r\n };\r\n\r\n const pageCards = pageLoads.map((load) => {\r\n const errHtml = load.lighthouseError\r\n ? `<div style=\"padding:12px 16px;background:#fef3c7;color:#92400e;font-size:12px;\">⚠ ${load.lighthouseError}</div>`\r\n : '';\r\n\r\n const metricsHtml = !load.lighthouseError ? METRICS_DEF.map(({ key, abbr }) => {\r\n const rating = rateMetric(key, load[key]);\r\n const bg = rating === 'good' ? '#ecfdf5' : rating === 'average' ? '#fffbeb' : rating === 'poor' ? '#fef2f2' : '#f8fafc';\r\n const color = COLORS[rating];\r\n return `<div style=\"flex:1;min-width:90px;background:${bg};border:1px solid ${color}33;border-radius:8px;padding:8px 10px;text-align:center;\">\r\n <div style=\"font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:${color};opacity:.8;margin-bottom:3px;\">${abbr}</div>\r\n <div style=\"font-size:14px;font-weight:800;color:${color};font-variant-numeric:tabular-nums;\">${fmtVal(key, load[key])}</div>\r\n </div>`;\r\n }).join('') : '';\r\n\r\n // Per-metric colored dot legend\r\n const legendHtml = !load.lighthouseError ? `\r\n <div style=\"border-top:1px solid #f1f5f9;padding:10px 16px;display:grid;grid-template-columns:1fr 1fr;gap:3px 24px;\">\r\n ${METRICS_DEF.map(({ key, abbr, label }) => {\r\n const rating = rateMetric(key, load[key]);\r\n const dotColor = rating === 'good' ? '#10b981' : rating === 'average' ? '#f59e0b' : rating === 'poor' ? '#ef4444' : '#94a3b8';\r\n return `<div style=\"display:flex;align-items:center;gap:5px;font-size:9px;color:#64748b;padding:1px 0;\">\r\n <span style=\"color:${dotColor};font-size:11px;line-height:1;flex-shrink:0;\">●</span>\r\n <span style=\"font-weight:700;color:#475569;\">${abbr}</span>\r\n <span style=\"opacity:.7;\">${label}</span>\r\n </div>`;\r\n }).join('')}\r\n </div>` : '';\r\n\r\n // Accessibility & SEO audit breakdown\r\n const auditSectionHtml = (items: Array<{id:string;title:string;passed:boolean;na?:boolean}> | undefined, sectionLabel: string) => {\r\n if (!items || items.length === 0) return '';\r\n const rows = items.map(a => {\r\n const color = a.na ? '#94a3b8' : a.passed ? '#10b981' : '#ef4444';\r\n const symbol = a.na ? '–' : a.passed ? '✓' : '✗';\r\n return `<div style=\"display:flex;align-items:center;gap:5px;font-size:9px;color:${color};padding:1px 0;\">\r\n <span style=\"font-weight:700;flex-shrink:0;\">${symbol}</span>\r\n <span style=\"color:#475569;\">${a.title}</span>\r\n </div>`;\r\n }).join('');\r\n return `<div>\r\n <div style=\"font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;margin-bottom:4px;\">${sectionLabel}</div>\r\n ${rows}\r\n </div>`;\r\n };\r\n\r\n const perfContent = category === 'performance' && !load.lighthouseError ? `\r\n <div style=\"padding:16px;\">\r\n <div style=\"display:flex;gap:10px;margin-bottom:14px;\">${scoreCircleHtml(load.score, 'Performance')}</div>\r\n <div style=\"font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#94a3b8;margin-bottom:8px;\">Core Web Vitals</div>\r\n <div style=\"display:flex;flex-wrap:wrap;gap:6px;\">${metricsHtml}</div>\r\n </div>\r\n ${legendHtml}` : '';\r\n\r\n const a11yContent = category === 'accessibility' && !load.lighthouseError ? `\r\n <div style=\"padding:16px;\">\r\n <div style=\"display:flex;gap:10px;margin-bottom:14px;\">${scoreCircleHtml(load.a11yScore, 'Accessibility')}</div>\r\n ${auditSectionHtml(load.a11yAudits, 'Accessibility Audits')}\r\n </div>` : '';\r\n\r\n const seoContent = category === 'seo' && !load.lighthouseError ? `\r\n <div style=\"padding:16px;\">\r\n <div style=\"display:flex;gap:10px;margin-bottom:14px;\">${scoreCircleHtml(load.seoScore, 'SEO')}</div>\r\n ${auditSectionHtml(load.seoAudits, 'SEO Audits')}\r\n </div>` : '';\r\n\r\n return `\r\n <div style=\"background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:20px;box-shadow:0 1px 3px rgba(0,0,0,.06);\">\r\n <div style=\"background:#f8fafc;padding:12px 16px;border-bottom:1px solid #e2e8f0;\">\r\n <div style=\"font-size:9px;font-weight:700;color:#94a3b8;text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px;\">Step ${load.stepIndex + 1}</div>\r\n <div style=\"font-size:11px;color:#475569;margin-bottom:4px;\">${load.stepInstruction}</div>\r\n <div style=\"font-size:11px;font-family:monospace;color:#6366f1;font-weight:600;\">${load.url}</div>\r\n </div>\r\n ${errHtml}\r\n ${perfContent}${a11yContent}${seoContent}\r\n </div>`;\r\n }).join('');\r\n\r\n const generated = new Date().toLocaleString();\r\n const catMeta = {\r\n performance: { icon: '⚡', color: '#7c3aed', title: 'Performance Report', subtitle: 'Core Web Vitals · Speed Metrics' },\r\n accessibility: { icon: '♿', color: '#2563eb', title: 'Accessibility Report', subtitle: 'WCAG Audit Checks' },\r\n seo: { icon: '🔍', color: '#059669', title: 'SEO Report', subtitle: 'Search Engine Optimisation Checks' },\r\n }[category];\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\"/>\r\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\r\n <title>${catMeta.title} — ${caseName}</title>\r\n <style>\r\n *{box-sizing:border-box;margin:0;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;}\r\n body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#f1f5f9;color:#1e293b;padding:24px;}\r\n .dot{font-size:12px;line-height:1;margin-right:4px;}\r\n @media print{\r\n *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;}\r\n body{background:#fff!important;padding:12px;}\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div style=\"max-width:820px;margin:0 auto;\">\r\n <div style=\"display:flex;align-items:center;gap:12px;margin-bottom:20px;\">\r\n <div style=\"background:${catMeta.color};width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;\">${catMeta.icon}</div>\r\n <div>\r\n <h1 style=\"font-size:16px;font-weight:800;color:#1e293b;\">${catMeta.title}</h1>\r\n <p style=\"font-size:11px;color:#94a3b8;\">${caseName} · ${catMeta.subtitle} · Generated ${generated}</p>\r\n </div>\r\n </div>\r\n <div style=\"background:#fff;border:1px solid #e2e8f0;border-radius:10px;padding:10px 16px;margin-bottom:20px;display:flex;align-items:center;gap:20px;\">\r\n <p style=\"font-size:10px;font-weight:700;color:#94a3b8;text-transform:uppercase;letter-spacing:.06em;flex-shrink:0;\">Score Guide</p>\r\n <div style=\"display:flex;gap:16px;font-size:11px;\">\r\n <span><span class=\"dot\" style=\"color:#10b981;\">●</span>90-100 Good</span>\r\n <span><span class=\"dot\" style=\"color:#f59e0b;\">●</span>50-89 Needs Work</span>\r\n <span><span class=\"dot\" style=\"color:#ef4444;\">●</span>0-49 Poor</span>\r\n <span><span class=\"dot\" style=\"color:#94a3b8;\">●</span>N/A</span>\r\n </div>\r\n <p style=\"font-size:10px;color:#94a3b8;margin-left:auto;\">${pageLoads.length} page${pageLoads.length !== 1 ? 's' : ''} audited</p>\r\n </div>\r\n ${pageCards}\r\n <p style=\"font-size:9px;color:#cbd5e1;text-align:center;margin-top:16px;\">Powered by Google Lighthouse · Desktop preset · Assuremind Studio</p>\r\n </div>\r\n</body>\r\n</html>`;\r\n}\r\n","/**\r\n * Allure HTML Report Generator\r\n * Runs `allure generate` after each test run to produce a self-contained HTML report\r\n * served at /allure/<runId> by the studio server.\r\n *\r\n * Requires Java to be installed (allure-commandline bundles the CLI but not the JVM).\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { execFile } from 'child_process';\r\nimport { promisify } from 'util';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst execFileAsync = promisify(execFile);\r\nconst logger = createChildLogger('allure-generator');\r\n\r\n// On Windows, .bin/allure is a bash symlink that execFile can't run.\r\n// Use the actual .bat file from allure-commandline instead.\r\nconst isWindows = process.platform === 'win32';\r\nconst alluireBin = path.resolve(\r\n __dirname,\r\n isWindows\r\n ? '../../node_modules/allure-commandline/dist/bin/allure.bat'\r\n : '../../node_modules/.bin/allure',\r\n);\r\n\r\n/**\r\n * Generates a per-run Allure HTML report from the run-specific results directory.\r\n * Results dir: <rootDir>/results/allure-results/<runId>/\r\n * Report dir: <rootDir>/results/allure-report/<runId>/index.html\r\n * Served at: /allure/<runId>\r\n * Returns true on success, false if generation failed (e.g. no Java installed).\r\n */\r\nexport async function generateAllureReport(rootDir: string, runId: string): Promise<boolean> {\r\n const resultsDir = path.join(rootDir, 'results', 'allure-results', runId);\r\n const reportDir = path.join(rootDir, 'results', 'allure-report', runId);\r\n\r\n if (!(await fs.pathExists(resultsDir))) {\r\n logger.debug({ resultsDir }, 'No allure-results dir for run — skipping report generation');\r\n return false;\r\n }\r\n\r\n const files = await fs.readdir(resultsDir);\r\n if (files.length === 0) {\r\n logger.debug({ runId }, 'allure-results is empty — skipping report generation');\r\n return false;\r\n }\r\n\r\n try {\r\n await execFileAsync(\r\n alluireBin,\r\n ['generate', resultsDir, '--output', reportDir, '--clean', '--single-file'],\r\n isWindows ? { shell: true } : {},\r\n );\r\n logger.info({ reportDir, runId }, 'Allure HTML report generated');\r\n return true;\r\n } catch (err: unknown) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n if (msg.includes('java') || msg.includes('Java') || msg.includes('JAVA')) {\r\n logger.warn(\r\n 'Allure report generation skipped — Java is not installed. ' +\r\n 'Install Java (https://adoptium.net) to enable Allure HTML reports.',\r\n );\r\n } else {\r\n logger.warn({ err: msg, runId }, 'Allure report generation failed');\r\n }\r\n return false;\r\n }\r\n}\r\n","/**\n * Faker — lightweight random test-data generator.\n * No external dependencies — uses Math.random() only.\n *\n * Tokens supported in step instructions:\n * {{FAKE_FIRST_NAME}} → random first name\n * {{FAKE_LAST_NAME}} → random last name\n * {{FAKE_AGE}} → random age between 18 and 80\n * {{FAKE_EMAIL}} → random email address\n * {{FAKE_PHONE}} → random phone number (e.g. 415-782-3901)\n * {{FAKE_NUMBER_<N>}} → random N-digit integer (e.g. {{FAKE_NUMBER_6}})\n * {{FAKE_PASSWORD}} → random strong password (e.g. Xk9#mP2$qL)\n */\n\nconst FIRST_NAMES = [\n 'Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry',\n 'Iris', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Paul',\n 'Quinn', 'Rachel', 'Sam', 'Tara', 'Uma', 'Victor', 'Wendy', 'Xander',\n 'Yara', 'Zoe', 'Aaron', 'Bella', 'Carlos', 'Daisy', 'Ethan', 'Fiona',\n];\n\nconst LAST_NAMES = [\n 'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller', 'Davis',\n 'Garcia', 'Wilson', 'Martinez', 'Anderson', 'Taylor', 'Thomas',\n 'Jackson', 'White', 'Harris', 'Martin', 'Thompson', 'Robinson', 'Clark',\n 'Lewis', 'Lee', 'Walker', 'Hall', 'Allen', 'Young', 'King', 'Wright',\n];\n\nconst EMAIL_DOMAINS = ['example.com', 'test.io', 'mail.net', 'demo.org', 'qa.dev'];\n\nfunction pick<T>(arr: T[]): T {\n return arr[Math.floor(Math.random() * arr.length)];\n}\n\nexport function fakeFirstName(): string {\n return pick(FIRST_NAMES);\n}\n\nexport function fakeLastName(): string {\n return pick(LAST_NAMES);\n}\n\nexport function fakeAge(): string {\n return String(Math.floor(Math.random() * 63) + 18); // 18–80\n}\n\nexport function fakeEmail(): string {\n const first = fakeFirstName().toLowerCase();\n const last = fakeLastName().toLowerCase();\n const rand = Math.floor(Math.random() * 900) + 100;\n return `${first}.${last}${rand}@${pick(EMAIL_DOMAINS)}`;\n}\n\nexport function fakePhone(): string {\n const area = Math.floor(Math.random() * 800) + 200; // 200–999\n const prefix = Math.floor(Math.random() * 800) + 200;\n const line = Math.floor(Math.random() * 9000) + 1000;\n return `${area}-${prefix}-${line}`;\n}\n\nexport function fakePassword(): string {\n const upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ';\n const lower = 'abcdefghjkmnpqrstuvwxyz';\n const digits = '23456789';\n const special = '!@#$%^&*';\n const all = upper + lower + digits + special;\n const len = Math.floor(Math.random() * 5) + 10; // 10–14 chars\n // Ensure at least one of each required class\n let pwd = pick([...upper]) + pick([...lower]) + pick([...digits]) + pick([...special]);\n for (let i = pwd.length; i < len; i++) pwd += pick([...all]);\n // Shuffle\n return pwd.split('').sort(() => Math.random() - 0.5).join('');\n}\n\nexport function fakeNumber(digits: number): string {\n const d = Math.max(1, digits);\n const min = d === 1 ? 0 : Math.pow(10, d - 1);\n const max = Math.pow(10, d) - 1;\n return String(Math.floor(Math.random() * (max - min + 1)) + min);\n}\n\n/**\n * Resolves a single FAKE_* token name to a generated value.\n * Returns null if the token is not a fake-data token.\n */\nexport function resolveFakeToken(tokenName: string): string | null {\n switch (tokenName) {\n case 'FAKE_FIRST_NAME': return fakeFirstName();\n case 'FAKE_LAST_NAME': return fakeLastName();\n case 'FAKE_AGE': return fakeAge();\n case 'FAKE_EMAIL': return fakeEmail();\n case 'FAKE_PHONE': return fakePhone();\n case 'FAKE_PASSWORD': return fakePassword();\n default: {\n const m = tokenName.match(/^FAKE_NUMBER_(\\d+)$/);\n if (m && m[1]) return fakeNumber(parseInt(m[1], 10));\n return null;\n }\n }\n}\n","/**\r\n * Variable Interpolator — replaces {{VAR_NAME}} tokens in generated code\r\n * with their resolved values before execution.\r\n *\r\n * {{BASE_URL}} — always replaced with the configured base URL.\r\n * {{FAKE_FIRST_NAME}} — random first name (generated fresh each run)\r\n * {{FAKE_LAST_NAME}} — random last name\r\n * {{FAKE_AGE}} — random age 18–80\r\n * {{FAKE_EMAIL}} — random email address\r\n * {{FAKE_PHONE}} — random phone number\r\n * {{FAKE_NUMBER_<N>}} — random N-digit number (e.g. {{FAKE_NUMBER_6}})\r\n * {{FAKE_PASSWORD}} — random strong password\r\n * All other tokens are looked up in the variables map.\r\n * Unresolved tokens are left as-is so failures are obvious.\r\n */\r\n\r\nimport { resolveFakeToken } from '../utils/faker';\r\n\r\n// NOTE: Do NOT use a module-level regex with /g flag here — the shared\r\n// lastIndex state causes replace() to skip tokens on subsequent calls.\r\n// Always create a fresh regex per invocation.\r\nconst TOKEN_SOURCE = '\\\\{\\\\{([A-Z0-9_]+)\\\\}\\\\}';\r\n\r\n/**\r\n * Replaces all {{TOKEN}} placeholders in code with resolved values.\r\n *\r\n * @param code - Generated Playwright code containing tokens\r\n * @param variables - Resolved variable map (key → value, secrets already redacted)\r\n * @param baseUrl - The configured base URL (replaces {{BASE_URL}})\r\n * @returns - Code with all known tokens substituted\r\n */\r\nexport function interpolate(\r\n code: string,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n): string {\r\n // Fresh regex each call — avoids stale lastIndex with the /g flag\r\n return code.replace(new RegExp(TOKEN_SOURCE, 'g'), (_match, name: string) => {\r\n if (name === 'BASE_URL') return baseUrl;\r\n // Dynamic fake-data tokens — resolved fresh on every run\r\n const fakeValue = resolveFakeToken(name);\r\n if (fakeValue !== null) return fakeValue;\r\n return variables[name] ?? `{{${name}}}`; // keep unresolved tokens visible\r\n });\r\n}\r\n\r\n/**\r\n * Returns all token names found in a code string (for pre-flight validation).\r\n */\r\nexport function extractTokens(code: string): string[] {\r\n const tokens: string[] = [];\r\n let match: RegExpExecArray | null;\r\n const re = new RegExp(TOKEN_SOURCE, 'g');\r\n while ((match = re.exec(code)) !== null) {\r\n if (match[1]) tokens.push(match[1]);\r\n }\r\n return [...new Set(tokens)];\r\n}\r\n","/**\r\n * Code Runner — executes validated Playwright code strings in a live page context.\r\n *\r\n * Wait strategy applied on every step:\r\n * 1. page.setDefaultTimeout / setDefaultNavigationTimeout — ensures ALL\r\n * Playwright actions (click, fill, goto, waitFor…) respect the configured\r\n * step timeout, not Playwright's internal 30 s default.\r\n * 2. The generated async function runs (step code executes here).\r\n * 3. page.waitForLoadState(pageLoad) — post-action wait so the next step\r\n * doesn't start before the page settles after navigations or SPAs.\r\n * Uses half the step timeout capped at 10 s to avoid blocking on slow pages.\r\n */\r\nimport { expect } from '@playwright/test';\r\nimport type { Page } from 'playwright';\r\nimport type { PageLoadStrategy } from '../types/config.js';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\nconst AsyncFunction: new (...args: string[]) => (...args: unknown[]) => Promise<void> =\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n Object.getPrototypeOf(async function () {}).constructor;\r\n\r\n/**\r\n * Shared runtime context passed into generated test code.\r\n * Allows steps to store/retrieve values across cases in the same run.\r\n */\r\nexport interface RuntimeContext {\r\n setVariable: (key: string, value: string) => void;\r\n getVariable: (key: string) => string | undefined;\r\n}\r\n\r\n/**\r\n * Executes a Playwright code string inside an async function scope.\r\n *\r\n * @param timeout Per-step timeout in ms (configures page + expect timeouts).\r\n * @param pageLoad Load-state strategy to await after the step completes.\r\n * @param runtimeCtx Optional shared context for runtime variable sharing across steps/cases.\r\n */\r\nexport async function executeCode(\r\n code: string,\r\n page: Page,\r\n timeout?: number,\r\n pageLoad: PageLoadStrategy = 'domcontentloaded',\r\n runtimeCtx?: RuntimeContext,\r\n): Promise<void> {\r\n // ── 1. Set page-level timeouts so every Playwright action uses the same budget\r\n if (timeout) {\r\n page.setDefaultTimeout(timeout);\r\n page.setDefaultNavigationTimeout(timeout);\r\n }\r\n\r\n // ── 2. Configure expect assertion timeout to match step timeout\r\n const configuredExpect = timeout ? expect.configure({ timeout }) : expect;\r\n\r\n // ── 3. Build the context object available to generated code\r\n const context = runtimeCtx ?? { setVariable: () => {}, getVariable: () => undefined };\r\n\r\n // ── 4. Run the generated step code (context is available as 3rd arg)\r\n const fn = new AsyncFunction('page', 'expect', 'context', code);\r\n const runPromise = fn(page, configuredExpect, context) as Promise<void>;\r\n // Attach a no-op catch to the raw promise so that if Playwright fires a\r\n // secondary rejection (e.g. navigation timeout arriving after the first\r\n // error was already caught upstream) it never becomes an unhandled rejection\r\n // that would crash the server process.\r\n runPromise.catch(() => {});\r\n await runPromise;\r\n\r\n // ── 4. Post-step wait: let the page settle after navigations / async updates\r\n // Cap at half the step timeout or 10 s — whichever is smaller — so a\r\n // networkidle wait on a chatty page doesn't eat the whole timeout budget.\r\n const loadWaitMs = timeout ? Math.min(timeout / 2, 10_000) : 10_000;\r\n try {\r\n await page.waitForLoadState(pageLoad, { timeout: loadWaitMs });\r\n } catch {\r\n // Non-fatal: page may already be stable or navigated away; continue to next step\r\n }\r\n}\r\n","/**\r\n * Context Extractor — captures live page state for AI prompts.\r\n * Called before every AI code-generation or healing call.\r\n *\r\n * Enhanced extraction includes:\r\n * - data-testid / data-cy / data-qa / data-test (highest-priority selectors)\r\n * - aria-labelledby resolved to actual text\r\n * - Associated <label> text for inputs\r\n * - href for links\r\n * - Visibility check (hidden elements excluded)\r\n * - Element bounding position (top/left) for ordering\r\n */\r\nimport type { Page } from 'playwright';\r\nimport type { PageContext } from '../types/ai.js';\r\n\r\nconst MAX_ELEMENTS = 120;\r\nconst MAX_TEXT_LEN = 80;\r\nconst MAX_HTML_LEN = 8000;\r\n\r\n/**\r\n * Extracts a PageContext snapshot from the current Playwright page.\r\n * Runs entirely in the browser via page.evaluate — no AI cost.\r\n */\r\nexport async function extractPageContext(\r\n page: Page,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n variables: Record<string, string>,\r\n): Promise<PageContext> {\r\n const url = page.url();\r\n const title = await page.title().catch(() => '');\r\n\r\n const interactiveElements = await page\r\n .evaluate(\r\n ({ maxElements, maxTextLen }: { maxElements: number; maxTextLen: number }) => {\r\n const SELECTORS = [\r\n 'button',\r\n '[role=\"button\"]',\r\n 'a[href]',\r\n 'input:not([type=\"hidden\"])',\r\n 'textarea',\r\n 'select',\r\n '[role=\"link\"]',\r\n '[role=\"tab\"]',\r\n '[role=\"checkbox\"]',\r\n '[role=\"radio\"]',\r\n '[role=\"menuitem\"]',\r\n '[role=\"option\"]',\r\n '[role=\"combobox\"]',\r\n '[role=\"listbox\"]',\r\n '[role=\"switch\"]',\r\n ];\r\n\r\n /** Resolve aria-labelledby to actual text */\r\n function resolveAriaLabelledBy(el: Element): string {\r\n const ids = el.getAttribute('aria-labelledby');\r\n if (!ids) return '';\r\n return ids\r\n .split(/\\s+/)\r\n .map((id) => document.getElementById(id)?.textContent?.trim() ?? '')\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n /** Find associated <label> text for an input */\r\n function findLabelText(el: Element): string {\r\n const id = el.getAttribute('id');\r\n if (id) {\r\n const label = document.querySelector(`label[for=\"${id}\"]`);\r\n if (label) return (label.textContent ?? '').trim().slice(0, 60);\r\n }\r\n // Check if wrapped in a <label>\r\n const parentLabel = el.closest('label');\r\n if (parentLabel) {\r\n const clone = parentLabel.cloneNode(true) as Element;\r\n clone.querySelectorAll('input,textarea,select').forEach((n) => n.remove());\r\n return (clone.textContent ?? '').trim().slice(0, 60);\r\n }\r\n return '';\r\n }\r\n\r\n /** Check if element is visible (not hidden) */\r\n function isVisible(el: Element): boolean {\r\n const style = window.getComputedStyle(el);\r\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0')\r\n return false;\r\n const rect = (el as HTMLElement).getBoundingClientRect();\r\n return rect.width > 0 && rect.height > 0;\r\n }\r\n\r\n /** Get the best test-ID attribute */\r\n function getTestId(el: Element): string {\r\n return (\r\n el.getAttribute('data-testid') ??\r\n el.getAttribute('data-cy') ??\r\n el.getAttribute('data-qa') ??\r\n el.getAttribute('data-test') ??\r\n ''\r\n );\r\n }\r\n\r\n const seen = new Set<Element>();\r\n const lines: string[] = [];\r\n\r\n for (const sel of SELECTORS) {\r\n if (lines.length >= maxElements) break;\r\n for (const el of Array.from(document.querySelectorAll(sel))) {\r\n if (lines.length >= maxElements) break;\r\n if (seen.has(el)) continue;\r\n if (!isVisible(el)) continue;\r\n seen.add(el);\r\n\r\n const tag = el.tagName.toLowerCase();\r\n const role = el.getAttribute('role') ?? tag;\r\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ').slice(0, maxTextLen);\r\n const ariaLabel = el.getAttribute('aria-label') ?? '';\r\n const ariaLabelledBy = resolveAriaLabelledBy(el);\r\n const labelText = findLabelText(el);\r\n const testId = getTestId(el);\r\n const name = el.getAttribute('name') ?? '';\r\n const id = el.getAttribute('id') ?? '';\r\n const placeholder = el.getAttribute('placeholder') ?? '';\r\n const type = el.getAttribute('type') ?? '';\r\n const href =\r\n tag === 'a' ? (el.getAttribute('href') ?? '').slice(0, 60) : '';\r\n const value =\r\n tag === 'select' || tag === 'input'\r\n ? (el as HTMLInputElement).value?.slice(0, 40)\r\n : '';\r\n\r\n // Build a compact, informative line for the AI\r\n const parts: string[] = [`<${tag}>`];\r\n if (testId) parts.push(`data-testid=\"${testId}\"`);\r\n if (ariaLabel) parts.push(`aria-label=\"${ariaLabel}\"`);\r\n if (ariaLabelledBy) parts.push(`aria-labelledby=\"${ariaLabelledBy}\"`);\r\n if (labelText) parts.push(`label=\"${labelText}\"`);\r\n if (placeholder) parts.push(`placeholder=\"${placeholder}\"`);\r\n if (text) parts.push(`text=\"${text}\"`);\r\n if (type) parts.push(`type=\"${type}\"`);\r\n if (name) parts.push(`name=\"${name}\"`);\r\n if (id) parts.push(`id=\"${id}\"`);\r\n if (href) parts.push(`href=\"${href}\"`);\r\n if (value) parts.push(`value=\"${value}\"`);\r\n if (role !== tag) parts.push(`role=\"${role}\"`);\r\n\r\n lines.push(parts.join(' '));\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n },\r\n { maxElements: MAX_ELEMENTS, maxTextLen: MAX_TEXT_LEN },\r\n )\r\n .catch(() => '');\r\n\r\n const htmlSnapshot = await page\r\n .evaluate(\r\n ({ maxLen }: { maxLen: number }) => document.body?.innerHTML?.slice(0, maxLen) ?? '',\r\n { maxLen: MAX_HTML_LEN },\r\n )\r\n .catch(() => '');\r\n\r\n return {\r\n url,\r\n title,\r\n interactiveElements,\r\n htmlSnapshot,\r\n previousSteps,\r\n variables,\r\n };\r\n}\r\n","/**\r\n * Set-of-Marks (SoM) Annotator\r\n *\r\n * Implements the same visual element-detection technique as Browser-Use:\r\n * 1. Extract all visible interactive elements with bounding boxes\r\n * 2. Inject colored numbered SVG overlays directly on the page DOM\r\n * 3. Capture an annotated screenshot (overlays visible)\r\n * 4. Remove overlays cleanly\r\n * 5. Return screenshot + structured element list so vision AI can identify\r\n * the exact element and generate a precise Playwright selector\r\n *\r\n * Color coding (Browser-Use style):\r\n * buttons → #FF6B6B red\r\n * links → #96CEB4 green\r\n * inputs → #4ECDC4 teal\r\n * selects → #45B7D1 blue\r\n * menu items → #DDA0DD purple\r\n * other → #FFE66D yellow\r\n *\r\n * No external image libraries — SVG is injected via page.evaluate().\r\n */\r\nimport type { Page } from 'playwright';\r\n\r\nconst OVERLAY_ID = '__testassuremind_som__';\r\n\r\nexport interface SoMElement {\r\n /** 1-based index shown in the screenshot label */\r\n index: number;\r\n tag: string;\r\n role: string;\r\n /** Best Playwright selector for this element */\r\n selector: string;\r\n /** Human-readable description for the AI prompt */\r\n description: string;\r\n /** Bounding box in CSS pixels (viewport-relative) */\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface SoMResult {\r\n /** PNG screenshot with numbered colored boxes overlaid */\r\n screenshot: Buffer;\r\n /** Structured element list */\r\n elements: SoMElement[];\r\n /** Formatted text map — included in the AI vision prompt */\r\n elementMap: string;\r\n}\r\n\r\n// ─── Color map by element category ──────────────────────────────────────────\r\n\r\nfunction getColor(tag: string, role: string): string {\r\n const t = tag.toLowerCase();\r\n const r = role.toLowerCase();\r\n if (t === 'button' || r === 'button') return '#FF6B6B';\r\n if (t === 'a' || r === 'link') return '#96CEB4';\r\n if (t === 'input' || t === 'textarea') return '#4ECDC4';\r\n if (t === 'select' || r === 'combobox' || r === 'listbox') return '#45B7D1';\r\n if (r === 'menuitem' || r === 'tab' || r === 'option') return '#DDA0DD';\r\n return '#FFE66D';\r\n}\r\n\r\n// ─── Selector builder ────────────────────────────────────────────────────────\r\n\r\nfunction buildSelector(el: {\r\n tag: string;\r\n role: string;\r\n testId: string;\r\n ariaLabel: string;\r\n labelText: string;\r\n placeholder: string;\r\n text: string;\r\n href: string;\r\n id: string;\r\n name: string;\r\n inputType: string;\r\n}): string {\r\n // Priority 1: data-testid\r\n if (el.testId) return `page.getByTestId('${el.testId}')`;\r\n\r\n // Priority 2: aria-label → getByRole with name\r\n if (el.ariaLabel) {\r\n const role = el.role || el.tag;\r\n return `page.getByRole('${role}', { name: '${el.ariaLabel}' })`;\r\n }\r\n\r\n // Priority 3: label text (for inputs)\r\n if (el.labelText && (el.tag === 'input' || el.tag === 'textarea' || el.tag === 'select')) {\r\n return `page.getByLabel('${el.labelText}')`;\r\n }\r\n\r\n // Priority 4: placeholder (for inputs)\r\n if (el.placeholder) return `page.getByPlaceholder('${el.placeholder}')`;\r\n\r\n // Priority 5: text content for links → getByRole('link')\r\n if (el.tag === 'a' && el.text) {\r\n return `page.getByRole('link', { name: '${el.text}' })`;\r\n }\r\n\r\n // Priority 6: text content for buttons\r\n if ((el.tag === 'button' || el.role === 'button') && el.text) {\r\n return `page.getByRole('button', { name: '${el.text}' })`;\r\n }\r\n\r\n // Priority 7: role-based with text\r\n if (el.role && el.text) {\r\n return `page.getByRole('${el.role}', { name: '${el.text}' })`;\r\n }\r\n\r\n // Priority 8: getByText for any visible text\r\n if (el.text) return `page.getByText('${el.text}')`;\r\n\r\n // Priority 9: CSS fallback\r\n if (el.id) return `page.locator('#${el.id}')`;\r\n if (el.name) return `page.locator('[name=\"${el.name}\"]')`;\r\n if (el.inputType) return `page.locator('${el.tag}[type=\"${el.inputType}\"]')`;\r\n\r\n return `page.locator('${el.tag}')`;\r\n}\r\n\r\n// ─── Main annotation function ────────────────────────────────────────────────\r\n\r\n/**\r\n * Captures a Set-of-Marks annotated screenshot of the current page.\r\n * Elements are numbered with colored SVG overlays injected directly into the DOM.\r\n */\r\nexport async function captureSetOfMarks(page: Page): Promise<SoMResult> {\r\n // ── Step 1: Extract all visible interactive elements with bounding boxes ──\r\n type RawElement = {\r\n tag: string; role: string; text: string; ariaLabel: string;\r\n ariaLabelledBy: string; labelText: string; placeholder: string;\r\n testId: string; href: string; id: string; name: string; inputType: string;\r\n x: number; y: number; width: number; height: number;\r\n };\r\n\r\n const rawElements = await page.evaluate((): RawElement[] => {\r\n const SELECTORS = [\r\n 'button', '[role=\"button\"]', 'a[href]',\r\n 'input:not([type=\"hidden\"])', 'textarea', 'select',\r\n '[role=\"link\"]', '[role=\"tab\"]', '[role=\"checkbox\"]',\r\n '[role=\"radio\"]', '[role=\"menuitem\"]', '[role=\"option\"]',\r\n '[role=\"combobox\"]', '[role=\"switch\"]',\r\n ];\r\n\r\n function resolveAriaLabelledBy(el: Element): string {\r\n const ids = el.getAttribute('aria-labelledby');\r\n if (!ids) return '';\r\n return ids.split(/\\s+/)\r\n .map((id) => document.getElementById(id)?.textContent?.trim() ?? '')\r\n .filter(Boolean).join(' ');\r\n }\r\n\r\n function findLabelText(el: Element): string {\r\n const elId = el.getAttribute('id');\r\n if (elId) {\r\n const label = document.querySelector(`label[for=\"${elId}\"]`);\r\n if (label) return (label.textContent ?? '').trim().slice(0, 60);\r\n }\r\n const parentLabel = el.closest('label');\r\n if (parentLabel) {\r\n const clone = parentLabel.cloneNode(true) as Element;\r\n clone.querySelectorAll('input,textarea,select').forEach((n) => n.remove());\r\n return (clone.textContent ?? '').trim().slice(0, 60);\r\n }\r\n return '';\r\n }\r\n\r\n const seen = new Set<Element>();\r\n const results: RawElement[] = [];\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n\r\n for (const sel of SELECTORS) {\r\n for (const el of Array.from(document.querySelectorAll(sel))) {\r\n if (seen.has(el)) continue;\r\n const style = window.getComputedStyle(el);\r\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;\r\n const rect = (el as HTMLElement).getBoundingClientRect();\r\n if (rect.width <= 0 || rect.height <= 0) continue;\r\n // Must be within viewport\r\n if (rect.right < 0 || rect.bottom < 0 || rect.left > vw || rect.top > vh) continue;\r\n seen.add(el);\r\n\r\n const tag = el.tagName.toLowerCase();\r\n const role = el.getAttribute('role') ?? '';\r\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ').slice(0, 60);\r\n const ariaLabel = el.getAttribute('aria-label') ?? '';\r\n const ariaLabelledBy = resolveAriaLabelledBy(el);\r\n const labelText = findLabelText(el);\r\n const testId =\r\n el.getAttribute('data-testid') ??\r\n el.getAttribute('data-cy') ??\r\n el.getAttribute('data-qa') ??\r\n el.getAttribute('data-test') ?? '';\r\n const placeholder = el.getAttribute('placeholder') ?? '';\r\n const href = tag === 'a' ? (el.getAttribute('href') ?? '') : '';\r\n const id = el.getAttribute('id') ?? '';\r\n const name = el.getAttribute('name') ?? '';\r\n const inputType = el.getAttribute('type') ?? '';\r\n\r\n results.push({\r\n tag, role, text, ariaLabel, ariaLabelledBy, labelText,\r\n testId, placeholder, href, id, name, inputType,\r\n x: Math.round(rect.left), y: Math.round(rect.top),\r\n width: Math.round(rect.width), height: Math.round(rect.height),\r\n });\r\n\r\n if (results.length >= 80) break;\r\n }\r\n if (results.length >= 80) break;\r\n }\r\n\r\n return results;\r\n });\r\n\r\n // ── Step 2: Build SoMElement list with selectors ──────────────────────────\r\n const elements: SoMElement[] = rawElements.map((raw, i) => {\r\n const selector = buildSelector(raw);\r\n const display =\r\n raw.ariaLabel || raw.labelText || raw.text || raw.placeholder ||\r\n raw.testId || raw.href || `${raw.tag}[${i}]`;\r\n const description =\r\n `[${i + 1}] ${raw.tag}${raw.role ? `(${raw.role})` : ''} \"${display.slice(0, 50)}\" → ${selector}`;\r\n\r\n return {\r\n index: i + 1,\r\n tag: raw.tag,\r\n role: raw.role || raw.tag,\r\n selector,\r\n description,\r\n x: raw.x, y: raw.y, width: raw.width, height: raw.height,\r\n };\r\n });\r\n\r\n // ── Step 3: Inject SVG overlay onto the page ──────────────────────────────\r\n await page.evaluate(\r\n ({ els, overlayId }: { els: Array<{ index: number; x: number; y: number; width: number; height: number; tag: string; role: string }>; overlayId: string }) => {\r\n const existing = document.getElementById(overlayId);\r\n if (existing) existing.remove();\r\n\r\n const NS = 'http://www.w3.org/2000/svg';\r\n const svg = document.createElementNS(NS, 'svg');\r\n svg.id = overlayId;\r\n svg.setAttribute('xmlns', NS);\r\n svg.style.cssText = [\r\n 'position:fixed', 'top:0', 'left:0',\r\n 'width:100%', 'height:100%',\r\n 'pointer-events:none',\r\n 'z-index:2147483647',\r\n ].join(';');\r\n\r\n const getColor = (tag: string, role: string): string => {\r\n const t = tag.toLowerCase(); const r = role.toLowerCase();\r\n if (t === 'button' || r === 'button') return '#FF6B6B';\r\n if (t === 'a' || r === 'link') return '#96CEB4';\r\n if (t === 'input' || t === 'textarea') return '#4ECDC4';\r\n if (t === 'select' || r === 'combobox') return '#45B7D1';\r\n if (r === 'menuitem' || r === 'tab') return '#DDA0DD';\r\n return '#FFE66D';\r\n };\r\n\r\n for (const el of els) {\r\n const color = getColor(el.tag, el.role);\r\n\r\n // Dashed border box\r\n const rect = document.createElementNS(NS, 'rect');\r\n rect.setAttribute('x', String(el.x + 1));\r\n rect.setAttribute('y', String(el.y + 1));\r\n rect.setAttribute('width', String(Math.max(el.width - 2, 4)));\r\n rect.setAttribute('height', String(Math.max(el.height - 2, 4)));\r\n rect.setAttribute('fill', 'none');\r\n rect.setAttribute('stroke', color);\r\n rect.setAttribute('stroke-width', '2');\r\n rect.setAttribute('stroke-dasharray', '4,3');\r\n svg.appendChild(rect);\r\n\r\n // Label background\r\n const labelW = el.index >= 10 ? 22 : 16;\r\n const labelH = 16;\r\n const labelX = el.index < el.x - labelW ? el.x - labelW : el.x;\r\n const labelY = el.y < labelH ? el.y : el.y - labelH + 2;\r\n\r\n const bg = document.createElementNS(NS, 'rect');\r\n bg.setAttribute('x', String(labelX));\r\n bg.setAttribute('y', String(labelY));\r\n bg.setAttribute('width', String(labelW));\r\n bg.setAttribute('height', String(labelH));\r\n bg.setAttribute('fill', color);\r\n bg.setAttribute('rx', '3');\r\n svg.appendChild(bg);\r\n\r\n // Index number\r\n const txt = document.createElementNS(NS, 'text');\r\n txt.setAttribute('x', String(labelX + labelW / 2));\r\n txt.setAttribute('y', String(labelY + 12));\r\n txt.setAttribute('fill', '#000');\r\n txt.setAttribute('font-size', '11');\r\n txt.setAttribute('font-family', 'monospace');\r\n txt.setAttribute('font-weight', 'bold');\r\n txt.setAttribute('text-anchor', 'middle');\r\n txt.textContent = String(el.index);\r\n svg.appendChild(txt);\r\n }\r\n\r\n document.documentElement.appendChild(svg);\r\n },\r\n {\r\n els: elements.map((e) => ({\r\n index: e.index, x: e.x, y: e.y,\r\n width: e.width, height: e.height,\r\n tag: e.tag, role: e.role,\r\n })),\r\n overlayId: OVERLAY_ID,\r\n },\r\n );\r\n\r\n // ── Step 4: Screenshot with overlay visible ───────────────────────────────\r\n const screenshotBuffer = await page.screenshot({ type: 'png', fullPage: false });\r\n\r\n // ── Step 5: Remove overlay cleanly ───────────────────────────────────────\r\n await page.evaluate(\r\n (id: string) => document.getElementById(id)?.remove(),\r\n OVERLAY_ID,\r\n );\r\n\r\n // ── Step 6: Build formatted element map for AI prompt ────────────────────\r\n const elementMap = elements\r\n .map((e) => e.description)\r\n .join('\\n');\r\n\r\n return { screenshot: screenshotBuffer, elements, elementMap };\r\n}\r\n\r\n/**\r\n * Removes any leftover SoM overlay (safety cleanup).\r\n */\r\nexport async function cleanupSoMOverlay(page: Page): Promise<void> {\r\n await page\r\n .evaluate((id: string) => document.getElementById(id)?.remove(), OVERLAY_ID)\r\n .catch(() => undefined);\r\n}\r\n","/**\r\n * Self-Healing Engine — 6-level fallback system.\r\n *\r\n * Level 1 — Smart Retry ($0, no AI) — wait + retry same code\r\n * Level 2 — AI Re-generation (1 AI call) — fresh page context → new code\r\n * Level 3 — Multi-Selector (1 AI call) — 5 different selector strategies\r\n * Level 4 — Visual/Coordinate (1 AI call) — screenshot → pixel coordinates\r\n * Level 5 — Decompose (1 AI call) — break into micro-actions\r\n * Level 6 — Manual ($0, no AI) — log + skip (CI) or pause (Studio)\r\n *\r\n * Healing NEVER writes to disk — results are returned to the executor,\r\n * which reports them to the HealingReporter for human review.\r\n */\r\nimport type { Page } from 'playwright';\r\nimport type { TestStep } from '../types/suite.js';\r\nimport type { StepFailure, HealingStrategy } from '../types/healing.js';\r\nimport type { AIProvider } from '../types/ai.js';\r\nimport { extractPageContext } from './context-extractor.js';\r\nimport { captureSetOfMarks, cleanupSoMOverlay } from './som-annotator.js';\r\nimport { sanitizeGeneratedCode } from '../utils/sanitize.js';\r\nimport { interpolate } from './variable-interpolator.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport { executeCode } from './code-runner.js';\r\nimport { detectStepType } from './step-type-detector.js';\r\nimport { buildApiSelfHealPrompt } from '../ai/prompts/api-self-heal.js';\r\n\r\nconst logger = createChildLogger('self-healing');\r\n\r\nexport interface HealResult {\r\n code: string;\r\n level: number;\r\n strategy: HealingStrategy;\r\n}\r\n\r\nexport class SelfHealer {\r\n constructor(\r\n private readonly provider: AIProvider,\r\n private readonly maxLevel: number,\r\n ) {}\r\n\r\n /**\r\n * Attempts to heal a failed step by cycling through levels 1–maxLevel.\r\n * Returns the first successful HealResult, or null if all levels fail.\r\n *\r\n * For API steps: skips Level 3 (multi-selector) and Level 4 (visual/SoM)\r\n * since they are DOM-specific. Uses API-specific prompts for Level 2.\r\n */\r\n async heal(\r\n step: TestStep,\r\n failure: StepFailure,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n ): Promise<HealResult | null> {\r\n // Safety net: NEVER heal assertion failures — they indicate real application bugs\r\n if (failure.failureKind === 'assertion') {\r\n logger.info(\r\n { stepId: step.id },\r\n 'Assertion failure — skipping all healing levels (possible application bug)',\r\n );\r\n return null;\r\n }\r\n\r\n const isApi = (step.stepType === 'api') || detectStepType(step.instruction) === 'api';\r\n\r\n for (let level = 1; level <= this.maxLevel; level++) {\r\n // Skip DOM-specific levels for API steps\r\n if (isApi && (level === 3 || level === 4)) {\r\n logger.debug({ stepId: step.id, level }, `Skipping DOM-specific level ${level} for API step`);\r\n continue;\r\n }\r\n\r\n logger.debug({ stepId: step.id, level, isApi }, `Attempting heal level ${level}`);\r\n try {\r\n const result = await this.tryLevel(\r\n level,\r\n step,\r\n failure,\r\n previousSteps,\r\n page,\r\n variables,\r\n baseUrl,\r\n isApi,\r\n );\r\n if (result !== null) {\r\n logger.info({ stepId: step.id, level, strategy: result.strategy }, 'Healing succeeded');\r\n return result;\r\n }\r\n } catch (err) {\r\n logger.debug({ err, level, stepId: step.id }, `Level ${level} healing attempt threw`);\r\n }\r\n }\r\n\r\n logger.warn({ stepId: step.id, maxLevel: this.maxLevel }, 'All healing levels exhausted');\r\n return null;\r\n }\r\n\r\n // ─── Level dispatcher ─────────────────────────────────────────────────────\r\n\r\n private async tryLevel(\r\n level: number,\r\n step: TestStep,\r\n failure: StepFailure,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n isApi = false,\r\n ): Promise<HealResult | null> {\r\n switch (level) {\r\n case 1:\r\n return this.level1Retry(failure, page);\r\n case 2:\r\n return isApi\r\n ? this.level2ApiRegenerate(step, failure, page, variables, baseUrl)\r\n : this.level2Regenerate(step, failure, previousSteps, page, variables, baseUrl);\r\n case 3:\r\n return this.level3MultiSelector(step, failure, previousSteps, page, variables, baseUrl);\r\n case 4:\r\n return this.level4Visual(step, page, variables, baseUrl);\r\n case 5:\r\n return this.level5Decompose(step, failure, previousSteps, page, variables, baseUrl);\r\n case 6:\r\n return this.level6Manual(step, failure);\r\n default:\r\n return null;\r\n }\r\n }\r\n\r\n // ─── Level 1: Smart Retry ($0) ────────────────────────────────────────────\r\n\r\n private async level1Retry(failure: StepFailure, page: Page): Promise<HealResult | null> {\r\n // Wait for network to settle and animations to finish, then retry\r\n // Use failure.failedCode — already variable-interpolated by the executor\r\n await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {});\r\n await page.waitForTimeout(1000);\r\n\r\n await executeCode(failure.failedCode, page);\r\n return { code: failure.failedCode, level: 1, strategy: 'retry' };\r\n }\r\n\r\n // ─── Level 2: AI Re-generation — SoM vision if available, text if not ────\r\n\r\n private async level2Regenerate(\r\n step: TestStep,\r\n failure: StepFailure,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n ): Promise<HealResult | null> {\r\n // If the provider supports vision, use Set-of-Marks for far better accuracy\r\n if (this.provider.supportsVision) {\r\n try {\r\n const som = await captureSetOfMarks(page);\r\n logger.debug({ stepId: step.id }, 'Level 2: using SoM vision healing');\r\n const code = await (this.provider as any).analyzeWithSoM(\r\n som.screenshot,\r\n som.elementMap,\r\n step.instruction,\r\n ) as string;\r\n const sanitized = interpolate(sanitizeGeneratedCode(code), variables, baseUrl);\r\n await executeCode(sanitized, page);\r\n return { code: sanitized, level: 2, strategy: 'regenerate' };\r\n } catch (visionErr) {\r\n logger.debug({ stepId: step.id, err: visionErr }, 'SoM vision failed, falling back to text regeneration');\r\n await cleanupSoMOverlay(page);\r\n }\r\n }\r\n\r\n // Text-only fallback: full HTML context → AI regenerates selector\r\n const context = await extractPageContext(page, previousSteps, variables);\r\n const code = await this.provider.healSelector(\r\n step.instruction,\r\n failure.failedCode,\r\n failure.error,\r\n context,\r\n );\r\n const sanitized = interpolate(sanitizeGeneratedCode(code), variables, baseUrl);\r\n await executeCode(sanitized, page);\r\n return { code: sanitized, level: 2, strategy: 'regenerate' };\r\n }\r\n\r\n // ─── Level 2 (API): Re-generation with API-specific healing context ─────\r\n\r\n private async level2ApiRegenerate(\r\n step: TestStep,\r\n failure: StepFailure,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n ): Promise<HealResult | null> {\r\n // Build a minimal API-focused context (no DOM elements needed)\r\n const context = await extractPageContext(page, [], variables);\r\n // Use healSelector — the provider interprets instruction + error to fix API code\r\n // IMPORTANT: Only fix the REQUEST (URL, headers, body, method) — NEVER change assertions\r\n const apiInstruction =\r\n `[API STEP] Fix this failing API test step. Only fix the REQUEST — the URL, headers, body, ` +\r\n `or HTTP method. NEVER change expect() assertions or expected status codes. ` +\r\n `Common fixable issues: wrong endpoint URL, missing auth header, incorrect request body schema. ` +\r\n `Keep all assertions exactly as they are. Step: ${step.instruction}`;\r\n const code = await this.provider.healSelector(\r\n apiInstruction,\r\n failure.failedCode,\r\n failure.error,\r\n context,\r\n );\r\n const sanitized = interpolate(sanitizeGeneratedCode(code), variables, baseUrl);\r\n await executeCode(sanitized, page);\r\n return { code: sanitized, level: 2, strategy: 'regenerate' };\r\n }\r\n\r\n // ─── Level 3: Multi-Strategy Selector (1 call) ───────────────────────────\r\n\r\n private async level3MultiSelector(\r\n step: TestStep,\r\n failure: StepFailure,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n ): Promise<HealResult | null> {\r\n const context = await extractPageContext(page, previousSteps, variables);\r\n\r\n // Ask AI for 5 different strategies in one call\r\n const multiInstruction =\r\n `Generate 5 different Playwright selector strategies (one per line, separated by \"---\") ` +\r\n `for this step: ${step.instruction}`;\r\n\r\n const raw = await this.provider.healSelector(\r\n multiInstruction,\r\n failure.failedCode,\r\n failure.error,\r\n context,\r\n );\r\n\r\n const strategies = parseMultiStrategies(raw);\r\n for (const candidate of strategies) {\r\n try {\r\n const sanitized = interpolate(sanitizeGeneratedCode(candidate), variables, baseUrl);\r\n await executeCode(sanitized, page);\r\n return { code: sanitized, level: 3, strategy: 'multi-selector' };\r\n } catch {\r\n // Try next strategy\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n // ─── Level 4: Set-of-Marks visual healing ────────────────────────────────\r\n // Uses the Browser-Use technique: inject numbered colored boxes on the page,\r\n // take a screenshot, send to vision AI with element map → get a real selector.\r\n // Produces inspectable Playwright code (not pixel coordinates).\r\n\r\n private async level4Visual(step: TestStep, page: Page, variables: Record<string, string>, baseUrl: string): Promise<HealResult | null> {\r\n if (!this.provider.supportsVision) {\r\n logger.debug({ stepId: step.id }, 'Skipping SoM visual healing — provider lacks vision');\r\n return null;\r\n }\r\n\r\n try {\r\n const som = await captureSetOfMarks(page);\r\n logger.debug(\r\n { stepId: step.id, elementCount: som.elements.length },\r\n 'Level 4: SoM screenshot captured',\r\n );\r\n\r\n const code = await (this.provider as any).analyzeWithSoM(\r\n som.screenshot,\r\n som.elementMap,\r\n step.instruction,\r\n ) as string;\r\n\r\n const sanitized = interpolate(sanitizeGeneratedCode(code), variables, baseUrl);\r\n await executeCode(sanitized, page);\r\n return { code: sanitized, level: 4, strategy: 'visual' };\r\n } catch (err) {\r\n await cleanupSoMOverlay(page);\r\n logger.debug({ stepId: step.id, err }, 'Level 4 SoM failed');\r\n return null;\r\n }\r\n }\r\n\r\n // ─── Level 5: Decompose into micro-actions (1 call) ──────────────────────\r\n\r\n private async level5Decompose(\r\n step: TestStep,\r\n failure: StepFailure,\r\n previousSteps: Array<{ instruction: string; code: string }>,\r\n page: Page,\r\n variables: Record<string, string>,\r\n baseUrl: string,\r\n ): Promise<HealResult | null> {\r\n const context = await extractPageContext(page, previousSteps, variables);\r\n\r\n const decomposeInstruction =\r\n `Break this failing step into 3-5 sequential micro-actions (separate each with \"---\"): ` +\r\n step.instruction;\r\n\r\n const raw = await this.provider.healSelector(\r\n decomposeInstruction,\r\n failure.failedCode,\r\n failure.error,\r\n context,\r\n );\r\n\r\n const microSteps = parseMultiStrategies(raw);\r\n const executedCodes: string[] = [];\r\n\r\n for (const microCode of microSteps) {\r\n const sanitized = interpolate(sanitizeGeneratedCode(microCode), variables, baseUrl);\r\n await executeCode(sanitized, page); // throws on failure → propagates up\r\n executedCodes.push(sanitized);\r\n }\r\n\r\n return { code: executedCodes.join('\\n'), level: 5, strategy: 'decompose' };\r\n }\r\n\r\n // ─── Level 6: Manual (human in the loop) ─────────────────────────────────\r\n\r\n private level6Manual(step: TestStep, failure: StepFailure): HealResult | null {\r\n logger.warn(\r\n { stepId: step.id, instruction: step.instruction, error: failure.error },\r\n 'Level 6: manual intervention required — marking step for human review',\r\n );\r\n // Return null — the runner marks the step as failed and adds to healing report\r\n return null;\r\n }\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Parses an AI response that contains multiple code blocks separated by \"---\".\r\n * Falls back to splitting on blank lines if separator not found.\r\n */\r\nfunction parseMultiStrategies(raw: string): string[] {\r\n const stripped = raw\r\n .replace(/^```[\\w]*\\n?/gm, '')\r\n .replace(/^```\\s*$/gm, '')\r\n .trim();\r\n\r\n if (stripped.includes('---')) {\r\n return stripped\r\n .split('---')\r\n .map((s) => s.trim())\r\n .filter((s) => s.length > 0);\r\n }\r\n\r\n // Fallback: each non-empty line is a candidate\r\n return stripped\r\n .split('\\n')\r\n .map((s) => s.trim())\r\n .filter((s) => s.length > 0 && s.startsWith('await'));\r\n}\r\n","/**\r\n * Step Executor — runs a single TestStep against a live Playwright page.\r\n *\r\n * Responsibilities:\r\n * 1. Interpolate {{VAR}} tokens in generated code\r\n * 2. Execute the code (with per-step timeout)\r\n * 3. On failure: consult HealingBudget, invoke SelfHealer\r\n * 4. Capture screenshots / return StepResult\r\n */\r\nimport path from 'path';\r\nimport type { Page } from 'playwright';\r\nimport type { TestStep } from '../types/suite.js';\r\nimport type { StepResult } from '../types/run.js';\r\nimport type { AutotestConfig } from '../types/config.js';\r\nimport type { AIProvider } from '../types/ai.js';\r\nimport type { StepFailure, FailureKind } from '../types/healing.js';\r\nimport { interpolate } from './variable-interpolator.js';\r\nimport { executeCode, type RuntimeContext } from './code-runner.js';\r\nimport { SelfHealer } from './self-healing.js';\r\nimport { HealingBudget } from './healing-budget.js';\r\nimport { HealingReporter } from './healing-report.js';\r\nimport { detectStepType } from './step-type-detector.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('executor');\r\n\r\n// ─── Error Classification ─────────────────────────────────────────────────────\r\n// Determines whether a failure is an ASSERTION failure (potential bug — never heal)\r\n// or an INFRASTRUCTURE failure (broken selector, timeout — safe to heal).\r\n\r\n/**\r\n * Assertion errors = the test ran correctly but the result didn't match expectations.\r\n * These indicate real bugs in the application. NEVER heal them.\r\n *\r\n * Patterns matched:\r\n * - expect(...).toBe(...) — Playwright/Jest assertion\r\n * - expect(...).toEqual(...) — deep equality\r\n * - expect(...).toContain(...) — string/array inclusion\r\n * - expect(...).toHaveText() — Playwright DOM assertion\r\n * - expect(...).toBeVisible() — visibility assertion\r\n * - AssertionError — generic assertion\r\n * - Expected X, received Y — Jest-style mismatch\r\n * - Status code mismatch — API: expected 200 got 400\r\n */\r\nconst ASSERTION_PATTERNS = [\r\n /expect\\(.*\\)\\.(toBe|toEqual|toContain|toMatch|toHaveText|toHaveValue|toBeChecked|toBeVisible|toBeHidden|toBeEnabled|toBeDisabled|toHaveCount|toHaveAttribute|toHaveClass|toHaveCSS|toHaveURL|toHaveTitle)/i,\r\n /AssertionError/i,\r\n /AssertError/i,\r\n /Expected.*received/i,\r\n /Expected.*but got/i,\r\n /expect\\..*Error/i,\r\n /expected\\s+\\d{3}.*received\\s+\\d{3}/i, // expected 200 received 400\r\n /expected\\s+status\\s+.*\\d{3}/i, // expected status 200\r\n /toBe\\(\\d{3}\\).*Received:\\s*\\d{3}/i, // toBe(200)\\n Received: 400\r\n /Expected:.*\\d{3}.*Received:.*\\d{3}/i, // Expected: 200, Received: 400\r\n /Error:.*expect.*to(Be|Equal|Contain|Match|Have)/i,\r\n];\r\n\r\n/**\r\n * Infrastructure errors = the test couldn't execute properly.\r\n * Selectors broke, elements disappeared, timeouts, network issues.\r\n * These are safe to heal.\r\n */\r\nconst INFRA_PATTERNS = [\r\n /locator\\.(click|fill|type|check|selectOption|press).*timeout/i, // selector timeout\r\n /waiting for (locator|selector)/i, // waiting for element\r\n /element is not (visible|attached|enabled|stable)/i, // element state\r\n /page\\.(goto|waitForSelector|waitForURL|waitForNavigation).*timeout/i, // navigation timeout\r\n /net::ERR_/i, // network errors\r\n /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND/i, // connection errors\r\n /Target closed|Target page, context or browser has been closed/i, // browser/page closed\r\n /frame was detached/i, // frame issues\r\n /navigation interrupted/i, // navigation issues\r\n /Timeout \\d+ms exceeded/i, // generic timeout\r\n /Step timed out after \\d+ms/i, // assuremind step timeout\r\n /strict mode violation/i, // multiple elements matched\r\n /No element matches/i, // element not found\r\n /page\\.request\\.(get|post|put|delete|patch).*ECONNREFUSED/i, // API connection error\r\n /socket hang up/i, // server dropped connection\r\n /ERR_CONNECTION/i, // connection level failure\r\n];\r\n\r\nfunction classifyError(errorMsg: string): FailureKind {\r\n // Check assertion patterns first — these should NEVER be healed\r\n for (const pattern of ASSERTION_PATTERNS) {\r\n if (pattern.test(errorMsg)) return 'assertion';\r\n }\r\n\r\n // Check infra patterns — these are safe to heal\r\n for (const pattern of INFRA_PATTERNS) {\r\n if (pattern.test(errorMsg)) return 'infra';\r\n }\r\n\r\n // Default: treat unknown errors as assertion failures (safer — don't mask bugs)\r\n // It's better to miss a healing opportunity than to hide a real bug\r\n return 'assertion';\r\n}\r\n\r\nexport interface ExecutorContext {\r\n runId: string;\r\n suiteId: string;\r\n caseId: string;\r\n browser: string;\r\n rootDir: string;\r\n previousSteps: Array<{ instruction: string; code: string }>;\r\n variables: Record<string, string>;\r\n sharedVariables: Map<string, string>;\r\n config: AutotestConfig;\r\n provider: AIProvider;\r\n budget: HealingBudget;\r\n healingReporter: HealingReporter;\r\n}\r\n\r\n// Re-export so self-healing.ts and runner.ts can import from here\r\nexport { executeCode } from './code-runner.js';\r\n\r\nexport async function executeStep(\r\n step: TestStep,\r\n page: Page,\r\n ctx: ExecutorContext,\r\n): Promise<StepResult> {\r\n const start = Date.now();\r\n\r\n // Merge static variables with runtime shared variables (shared vars take precedence)\r\n const mergedVars = { ...ctx.variables, ...Object.fromEntries(ctx.sharedVariables) };\r\n\r\n // Resolve {{VAR}} tokens in the generated code\r\n const hasTokens = step.generatedCode.includes('{{');\r\n if (hasTokens) {\r\n logger.warn(\r\n { stepId: step.id, variableKeys: Object.keys(mergedVars), variableCount: Object.keys(mergedVars).length },\r\n 'Interpolating variables into step code',\r\n );\r\n }\r\n const code = interpolate(step.generatedCode, mergedVars, ctx.config.baseUrl);\r\n if (hasTokens) {\r\n logger.warn({ stepId: step.id, before: step.generatedCode, after: code }, 'Variable interpolation result');\r\n }\r\n\r\n if (!code.trim() && step.stepType !== 'mock') {\r\n logger.warn({ stepId: step.id }, 'Step has no generated code — skipping');\r\n return buildResult(step, 'skipped', code, Date.now() - start);\r\n }\r\n\r\n // ── Mock step handling ────────────────────────────────────────────────────\r\n if (step.stepType === 'mock' && step.mockUrl && step.mockResponse) {\r\n try {\r\n await page.route(step.mockUrl, (route) =>\r\n route.fulfill({\r\n status: step.mockStatus ?? 200,\r\n contentType: 'application/json',\r\n body: step.mockResponse ?? '',\r\n }),\r\n );\r\n const result = buildResult(step, 'passed', code, Date.now() - start);\r\n await page.unrouteAll().catch(() => {});\r\n return result;\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return buildResult(step, 'failed', code, Date.now() - start, msg);\r\n }\r\n }\r\n\r\n // ── Build runtime context for shared variable access ─────────────────────\r\n const runtimeCtx: RuntimeContext = {\r\n setVariable: (key: string, value: string) => {\r\n ctx.sharedVariables.set(key, value);\r\n logger.info({ stepId: step.id, key, value: value.slice(0, 50) }, 'Runtime variable set');\r\n },\r\n getVariable: (key: string) => ctx.sharedVariables.get(key),\r\n };\r\n\r\n // ── Per-step retry ────────────────────────────────────────────────────────\r\n const stepRetries = step.retries ?? ctx.config.retries ?? 0;\r\n\r\n // ── First attempt ─────────────────────────────────────────────────────────\r\n const stepTimeout = step.timeout ?? ctx.config.timeout;\r\n\r\n // Capture URL before execution to detect navigations\r\n const urlBefore = (step.stepType !== 'api') ? page.url() : '';\r\n\r\n let lastErr: unknown;\r\n for (let attempt = 0; attempt <= stepRetries; attempt++) {\r\n try {\r\n await withTimeout(\r\n executeCode(code, page, stepTimeout, ctx.config.pageLoad ?? 'domcontentloaded', runtimeCtx),\r\n stepTimeout,\r\n );\r\n\r\n // ── Navigation detection ─────────────────────────────────────────────\r\n let navigatedToUrl: string | undefined;\r\n if (step.stepType !== 'api') {\r\n try {\r\n const urlAfter = page.url();\r\n const navigationOccurred = urlBefore !== urlAfter || urlBefore === 'about:blank' || urlBefore === '';\r\n if (navigationOccurred && urlAfter && !urlAfter.startsWith('about:')) {\r\n navigatedToUrl = urlAfter;\r\n }\r\n } catch {\r\n // non-fatal\r\n }\r\n }\r\n\r\n // Capture audit URL when this step is marked as an audit checkpoint.\r\n // Use navigatedToUrl if available, otherwise capture current page URL.\r\n let auditUrl: string | undefined;\r\n if (step.runAudit && step.stepType !== 'api') {\r\n try { auditUrl = navigatedToUrl ?? (page.url() || undefined); } catch { /* non-fatal */ }\r\n }\r\n\r\n if (ctx.config.screenshot === 'on') {\r\n const screenshotPath = await captureScreenshot(page, ctx, step.id, 'pass');\r\n return { ...buildResult(step, 'passed', code, Date.now() - start, undefined, screenshotPath), navigatedToUrl, auditUrl };\r\n }\r\n\r\n return { ...buildResult(step, 'passed', code, Date.now() - start), navigatedToUrl, auditUrl };\r\n } catch (err) {\r\n lastErr = err;\r\n if (attempt < stepRetries) {\r\n logger.debug({ stepId: step.id, attempt, stepRetries }, 'Step failed — retrying');\r\n continue;\r\n }\r\n }\r\n }\r\n\r\n const firstErr = lastErr;\r\n {\r\n const errorMsg = firstErr instanceof Error ? firstErr.message : String(firstErr);\r\n logger.debug({ stepId: step.id, error: errorMsg }, 'Step failed on first attempt');\r\n\r\n // Capture audit URL even on failure — runAudit checkpoints should still record the page\r\n const failAuditUrl: string | undefined = (step.runAudit && step.stepType !== 'api')\r\n ? (() => { try { return page.url() || undefined; } catch { return undefined; } })()\r\n : undefined;\r\n\r\n // ── Screenshot on failure ───────────────────────────────────────────────\r\n let screenshotPath: string | undefined;\r\n if (ctx.config.screenshot !== 'off') {\r\n screenshotPath = await captureScreenshot(page, ctx, step.id, 'fail');\r\n }\r\n\r\n // ── Error classification ──────────────────────────────────────────────\r\n const failureKind = classifyError(errorMsg);\r\n\r\n if (failureKind === 'assertion') {\r\n // ASSERTION FAILURE = potential real bug — NEVER heal\r\n // This is a test doing its job: it found a mismatch between expected and actual\r\n logger.info(\r\n { stepId: step.id, error: errorMsg },\r\n 'Assertion failure detected — NOT healing (possible application bug)',\r\n );\r\n return { ...buildResult(step, 'failed', code, Date.now() - start, errorMsg, screenshotPath), ...(failAuditUrl ? { auditUrl: failAuditUrl } : {}) };\r\n }\r\n\r\n // ── Self-healing (infra failures only) ─────────────────────────────────\r\n if (!ctx.config.healing.enabled) {\r\n return { ...buildResult(step, 'failed', code, Date.now() - start, errorMsg, screenshotPath), ...(failAuditUrl ? { auditUrl: failAuditUrl } : {}) };\r\n }\r\n\r\n logger.debug({ stepId: step.id, failureKind }, 'Infrastructure failure — attempting to heal');\r\n\r\n const failure: StepFailure = {\r\n stepId: step.id,\r\n instruction: step.instruction,\r\n error: errorMsg,\r\n pageUrl: page.url(),\r\n failedCode: code,\r\n failureKind,\r\n };\r\n\r\n const decision = ctx.budget.shouldHeal(failure);\r\n\r\n if (!decision.heal) {\r\n logger.info({ stepId: step.id, reason: decision.reason }, 'Healing skipped');\r\n return { ...buildResult(step, 'failed', code, Date.now() - start, errorMsg, screenshotPath), ...(failAuditUrl ? { auditUrl: failAuditUrl } : {}) };\r\n }\r\n\r\n const healer = new SelfHealer(ctx.provider, ctx.config.healing.maxLevel);\r\n\r\n try {\r\n const healResult = await healer.heal(\r\n step,\r\n failure,\r\n ctx.previousSteps,\r\n page,\r\n ctx.variables,\r\n ctx.config.baseUrl,\r\n );\r\n\r\n if (healResult !== null) {\r\n // Level 1 (Smart Retry) uses the same code — no file change needed.\r\n // Only record healing events when the code actually changed (levels 2-5).\r\n const codeChanged = healResult.code.trim() !== code.trim();\r\n\r\n if (codeChanged) {\r\n // Estimate AI spend (~$0.005 per healing call)\r\n ctx.budget.recordSpend(0.005);\r\n\r\n // Record healing event for human review\r\n ctx.healingReporter.record({\r\n runId: ctx.runId,\r\n suiteId: ctx.suiteId,\r\n caseId: ctx.caseId,\r\n stepId: step.id,\r\n stepInstruction: step.instruction,\r\n failedCode: code,\r\n healedCode: healResult.code,\r\n error: errorMsg,\r\n strategy: healResult.strategy,\r\n level: healResult.level,\r\n pageUrl: page.url(),\r\n });\r\n }\r\n\r\n logger.info(\r\n { stepId: step.id, level: healResult.level, strategy: healResult.strategy, codeChanged },\r\n codeChanged\r\n ? 'Step passed after healing (code NOT saved — awaits human review)'\r\n : 'Step passed after smart retry (no code change)',\r\n );\r\n\r\n return buildResult(\r\n step,\r\n 'passed',\r\n code,\r\n Date.now() - start,\r\n undefined,\r\n screenshotPath,\r\n codeChanged ? healResult.code : undefined,\r\n );\r\n }\r\n } catch (healErr) {\r\n const healErrMsg = healErr instanceof Error ? healErr.message : String(healErr);\r\n logger.warn({ stepId: step.id, error: healErrMsg }, 'Healing threw an error');\r\n ctx.budget.recordHealFailure(step.id);\r\n }\r\n\r\n return { ...buildResult(step, 'failed', code, Date.now() - start, errorMsg, screenshotPath), ...(failAuditUrl ? { auditUrl: failAuditUrl } : {}) };\r\n }\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────────────\r\n\r\nfunction buildResult(\r\n step: TestStep,\r\n status: StepResult['status'],\r\n code: string,\r\n duration: number,\r\n error?: string,\r\n screenshotPath?: string,\r\n healedCode?: string,\r\n): StepResult {\r\n const stepType = step.stepType ?? detectStepType(step.instruction);\r\n return {\r\n stepId: step.id,\r\n instruction: step.instruction,\r\n status,\r\n code,\r\n duration,\r\n stepType,\r\n ...(error !== undefined && { error }),\r\n ...(screenshotPath !== undefined && { screenshotPath }),\r\n ...(healedCode !== undefined && { healed: true, healedCode }),\r\n };\r\n}\r\n\r\nasync function captureScreenshot(\r\n page: Page,\r\n ctx: ExecutorContext,\r\n stepId: string,\r\n suffix: string,\r\n): Promise<string | undefined> {\r\n try {\r\n // Wait for the page to fully paint before capturing so the screenshot\r\n // is never blank. Cap at 5 s — if the page is still loading after that\r\n // we still take the screenshot rather than skipping it entirely.\r\n await page.waitForLoadState('load', { timeout: 5000 }).catch(() => {});\r\n\r\n const screenshotsDir = path.join(ctx.rootDir, 'results', 'screenshots');\r\n const filename = `${ctx.runId}_${ctx.caseId}_${stepId}_${suffix}.png`;\r\n const screenshotPath = path.join(screenshotsDir, filename);\r\n await page.screenshot({ path: screenshotPath, fullPage: true });\r\n return screenshotPath;\r\n } catch (err) {\r\n logger.debug({ err }, 'Screenshot capture failed');\r\n return undefined;\r\n }\r\n}\r\n\r\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\r\n return Promise.race([\r\n promise,\r\n new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error(`Step timed out after ${ms}ms`)), ms),\r\n ),\r\n ]);\r\n}\r\n","/**\r\n * Element Highlighter\r\n *\r\n * Injects a lightweight DOM listener into every page load via addInitScript().\r\n * When Playwright interacts with an element (click, fill, focus, hover), the\r\n * target element gets a colored animated border + glow so it is clearly visible:\r\n *\r\n * • Headed mode — you can watch which element is being interacted with\r\n * • Screenshots — failed-step screenshot shows the last touched element\r\n * • Video — every interaction is visually annotated\r\n * • Trace Viewer — DOM snapshots show the highlight state\r\n *\r\n * Color coding:\r\n * click / submit → 🔴 #FF6B6B red\r\n * fill / type → 🩵 #4ECDC4 teal\r\n * select → 🔵 #45B7D1 blue\r\n * hover → 🟡 #FFE66D yellow\r\n * focus (generic) → 🟣 #C77DFF purple\r\n *\r\n * The highlight fades after 2 seconds, or is immediately replaced when the\r\n * next interaction fires — whichever comes first.\r\n */\r\nimport type { Page } from 'playwright';\r\n\r\nconst HIGHLIGHTER_SCRIPT = `(function () {\r\n if (window.__tm_highlighter_installed__) return;\r\n window.__tm_highlighter_installed__ = true;\r\n\r\n /* ── Inject pulse keyframe animation once ─────────────────────────── */\r\n const style = document.createElement('style');\r\n style.id = '__tm_styles__';\r\n style.textContent = \\`\r\n @keyframes __tm_pulse_red { 0%{box-shadow:0 0 0 0 rgba(255,107,107,.7)} 70%{box-shadow:0 0 0 10px transparent} 100%{box-shadow:0 0 0 0 transparent} }\r\n @keyframes __tm_pulse_teal { 0%{box-shadow:0 0 0 0 rgba(78,205,196,.7)} 70%{box-shadow:0 0 0 10px transparent} 100%{box-shadow:0 0 0 0 transparent} }\r\n @keyframes __tm_pulse_blue { 0%{box-shadow:0 0 0 0 rgba(69,183,209,.7)} 70%{box-shadow:0 0 0 10px transparent} 100%{box-shadow:0 0 0 0 transparent} }\r\n @keyframes __tm_pulse_yellow{ 0%{box-shadow:0 0 0 0 rgba(255,230,109,.7)} 70%{box-shadow:0 0 0 10px transparent} 100%{box-shadow:0 0 0 0 transparent} }\r\n @keyframes __tm_pulse_purple{ 0%{box-shadow:0 0 0 0 rgba(199,125,255,.7)} 70%{box-shadow:0 0 0 10px transparent} 100%{box-shadow:0 0 0 0 transparent} }\r\n .__tm_highlight__ {\r\n transition: outline 0.05s ease, box-shadow 0.05s ease !important;\r\n position: relative !important;\r\n z-index: 2147483640 !important;\r\n }\r\n \\`;\r\n var root = document.head || document.documentElement;\r\n if (root) { root.appendChild(style); }\r\n\r\n /* ── State ─────────────────────────────────────────────────────────── */\r\n var _prev = null;\r\n var _timer = null;\r\n\r\n /* ── Helpers ───────────────────────────────────────────────────────── */\r\n function save(el) {\r\n el.__tm_saved__ = {\r\n outline: el.style.outline,\r\n boxShadow: el.style.boxShadow,\r\n zIndex: el.style.zIndex,\r\n animation: el.style.animation,\r\n position: el.style.position,\r\n };\r\n }\r\n\r\n function restore(el) {\r\n if (!el || !el.__tm_saved__) return;\r\n var s = el.__tm_saved__;\r\n el.style.outline = s.outline;\r\n el.style.boxShadow = s.boxShadow;\r\n el.style.zIndex = s.zIndex;\r\n el.style.animation = s.animation;\r\n el.style.position = s.position;\r\n el.classList.remove('__tm_highlight__');\r\n delete el.__tm_saved__;\r\n }\r\n\r\n function highlight(el, color, animName, duration) {\r\n if (!el || !(el instanceof HTMLElement)) return;\r\n\r\n /* Clear previous */\r\n if (_prev && _prev !== el) restore(_prev);\r\n if (_timer) { clearTimeout(_timer); _timer = null; }\r\n\r\n save(el);\r\n el.classList.add('__tm_highlight__');\r\n el.style.outline = '3px solid ' + color;\r\n el.style.boxShadow = '0 0 0 5px ' + color + '55, 0 0 18px ' + color + '44';\r\n el.style.animation = animName + ' 0.6s ease-out';\r\n _prev = el;\r\n\r\n /* Auto-remove after duration */\r\n _timer = setTimeout(function () {\r\n restore(el);\r\n _prev = null;\r\n _timer = null;\r\n }, duration);\r\n }\r\n\r\n function getInteractiveTarget(el) {\r\n /* Walk up to find the most relevant interactive ancestor */\r\n var cur = el;\r\n while (cur && cur !== document.body) {\r\n var tag = (cur.tagName || '').toLowerCase();\r\n if (['button','a','input','textarea','select','label'].includes(tag)) return cur;\r\n var role = (cur.getAttribute && cur.getAttribute('role')) || '';\r\n if (['button','link','menuitem','tab','checkbox','radio','option','combobox','switch'].includes(role)) return cur;\r\n cur = cur.parentElement;\r\n }\r\n return el;\r\n }\r\n\r\n /* ── Event listeners ───────────────────────────────────────────────── */\r\n\r\n /* CLICK → red */\r\n document.addEventListener('mousedown', function (e) {\r\n var target = getInteractiveTarget(e.target);\r\n highlight(target, '#FF6B6B', '__tm_pulse_red', 2000);\r\n }, { capture: true, passive: true });\r\n\r\n /* FILL / FOCUS on inputs → teal */\r\n document.addEventListener('focusin', function (e) {\r\n var el = e.target;\r\n if (!(el instanceof HTMLElement)) return;\r\n var tag = el.tagName.toLowerCase();\r\n if (tag === 'input' || tag === 'textarea') {\r\n highlight(el, '#4ECDC4', '__tm_pulse_teal', 3000);\r\n } else if (tag === 'select') {\r\n highlight(el, '#45B7D1', '__tm_pulse_blue', 2000);\r\n }\r\n }, { capture: true, passive: true });\r\n\r\n /* HOVER → yellow (subtle, shorter) */\r\n document.addEventListener('mouseover', function (e) {\r\n var target = getInteractiveTarget(e.target);\r\n if (!target || target === document.body) return;\r\n var tag = (target.tagName || '').toLowerCase();\r\n var role = (target.getAttribute && target.getAttribute('role')) || '';\r\n var isInteractive =\r\n ['button','a','input','textarea','select'].includes(tag) ||\r\n ['button','link','menuitem','tab'].includes(role);\r\n if (isInteractive && target !== _prev) {\r\n /* Subtle hover — don't overwrite an active highlight */\r\n if (!_prev) {\r\n save(target);\r\n target.style.outline = '2px dashed #FFE66D';\r\n target.style.boxShadow = '0 0 0 3px #FFE66D33';\r\n target.classList.add('__tm_highlight__');\r\n var hoverTimer = setTimeout(function () {\r\n if (!target.__tm_saved__) return;\r\n restore(target);\r\n }, 800);\r\n target.__tm_hoverTimer__ = hoverTimer;\r\n }\r\n }\r\n }, { capture: true, passive: true });\r\n\r\n /* Cleanup hover on mouseout */\r\n document.addEventListener('mouseout', function (e) {\r\n var target = getInteractiveTarget(e.target);\r\n if (!target) return;\r\n if (target.__tm_hoverTimer__) {\r\n clearTimeout(target.__tm_hoverTimer__);\r\n delete target.__tm_hoverTimer__;\r\n }\r\n if (target !== _prev && target.__tm_saved__) {\r\n restore(target);\r\n }\r\n }, { capture: true, passive: true });\r\n\r\n})();`;\r\n\r\n/**\r\n * Installs the element highlighter on every page/frame load.\r\n * Call once right after the page is created, before any navigation.\r\n */\r\nexport async function installHighlighter(page: Page): Promise<void> {\r\n // addInitScript runs on EVERY navigation — perfect for multi-page tests\r\n await page.addInitScript(HIGHLIGHTER_SCRIPT);\r\n}\r\n\r\n/**\r\n * Also injects the highlighter on the currently loaded page\r\n * (for cases where the page is already open when called).\r\n */\r\nexport async function injectHighlighterNow(page: Page): Promise<void> {\r\n await page.evaluate(HIGHLIGHTER_SCRIPT).catch(() => undefined);\r\n}\r\n","/**\n * Data Loader — loads data rows for data-driven testing.\n * Supports inline JSON, JSON files, and CSV files.\n */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { createChildLogger } from '../utils/logger.js';\n\nconst logger = createChildLogger('data-loader');\n\ninterface DataSource {\n type: 'inline' | 'json-file' | 'csv-file';\n path?: string;\n data?: Record<string, string>[];\n}\n\nexport async function loadDataRows(\n rootDir: string,\n dataSource: DataSource,\n): Promise<Record<string, string>[]> {\n switch (dataSource.type) {\n case 'inline':\n return dataSource.data ?? [];\n\n case 'json-file': {\n if (!dataSource.path) throw new Error('JSON data source requires a path');\n const filePath = path.resolve(rootDir, dataSource.path);\n if (!(await fs.pathExists(filePath))) {\n throw new Error(`Data file not found: ${filePath}`);\n }\n const raw = await fs.readJson(filePath);\n if (!Array.isArray(raw)) throw new Error('JSON data file must contain an array of objects');\n logger.info({ path: filePath, rows: raw.length }, 'Loaded JSON data rows');\n return raw.map((row: Record<string, unknown>) =>\n Object.fromEntries(Object.entries(row).map(([k, v]) => [k, String(v)])),\n );\n }\n\n case 'csv-file': {\n if (!dataSource.path) throw new Error('CSV data source requires a path');\n const filePath = path.resolve(rootDir, dataSource.path);\n if (!(await fs.pathExists(filePath))) {\n throw new Error(`Data file not found: ${filePath}`);\n }\n const content = await fs.readFile(filePath, 'utf8');\n const lines = content.trim().split('\\n').map((l) => l.trim()).filter(Boolean);\n if (lines.length < 2) return [];\n const headers = lines[0].split(',').map((h) => h.trim());\n const rows = lines.slice(1).map((line) => {\n const values = line.split(',').map((v) => v.trim());\n const row: Record<string, string> = {};\n headers.forEach((h, i) => { row[h] = values[i] ?? ''; });\n return row;\n });\n logger.info({ path: filePath, rows: rows.length }, 'Loaded CSV data rows');\n return rows;\n }\n\n default:\n return [];\n }\n}\n","'use strict';\n\nmodule.exports = string => {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError('Expected a string');\n\t}\n\n\t// Escape characters with special meaning either inside or outside character sets.\n\t// Use a simple backslash escape when it’s always valid, and a \\unnnn escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.\n\treturn string\n\t\t.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&')\n\t\t.replace(/-/g, '\\\\x2d');\n};\n","/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function (val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n","\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = require('ms');\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '')\n\t\t\t.trim()\n\t\t\t.replace(/\\s+/g, ',')\n\t\t\t.split(',')\n\t\t\t.filter(Boolean);\n\n\t\tfor (const ns of split) {\n\t\t\tif (ns[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(ns.slice(1));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(ns);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the given string matches a namespace template, honoring\n\t * asterisks as wildcards.\n\t *\n\t * @param {String} search\n\t * @param {String} template\n\t * @return {Boolean}\n\t */\n\tfunction matchesTemplate(search, template) {\n\t\tlet searchIndex = 0;\n\t\tlet templateIndex = 0;\n\t\tlet starIndex = -1;\n\t\tlet matchIndex = 0;\n\n\t\twhile (searchIndex < search.length) {\n\t\t\tif (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {\n\t\t\t\t// Match character or proceed with wildcard\n\t\t\t\tif (template[templateIndex] === '*') {\n\t\t\t\t\tstarIndex = templateIndex;\n\t\t\t\t\tmatchIndex = searchIndex;\n\t\t\t\t\ttemplateIndex++; // Skip the '*'\n\t\t\t\t} else {\n\t\t\t\t\tsearchIndex++;\n\t\t\t\t\ttemplateIndex++;\n\t\t\t\t}\n\t\t\t} else if (starIndex !== -1) { // eslint-disable-line no-negated-condition\n\t\t\t\t// Backtrack to the last '*' and try to match more characters\n\t\t\t\ttemplateIndex = starIndex + 1;\n\t\t\t\tmatchIndex++;\n\t\t\t\tsearchIndex = matchIndex;\n\t\t\t} else {\n\t\t\t\treturn false; // No match\n\t\t\t}\n\t\t}\n\n\t\t// Handle trailing '*' in template\n\t\twhile (templateIndex < template.length && template[templateIndex] === '*') {\n\t\t\ttemplateIndex++;\n\t\t}\n\n\t\treturn templateIndex === template.length;\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names,\n\t\t\t...createDebug.skips.map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tfor (const skip of createDebug.skips) {\n\t\t\tif (matchesTemplate(name, skip)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const ns of createDebug.names) {\n\t\t\tif (matchesTemplate(name, ns)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n","/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\tlet m;\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\t// eslint-disable-next-line no-return-assign\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)) && parseInt(m[1], 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = process.env.DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = require('./common')(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n","'use strict';\n\nmodule.exports = (flag, argv = process.argv) => {\n\tconst prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');\n\tconst position = argv.indexOf(prefix + flag);\n\tconst terminatorPosition = argv.indexOf('--');\n\treturn position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);\n};\n","'use strict';\nconst os = require('os');\nconst tty = require('tty');\nconst hasFlag = require('has-flag');\n\nconst {env} = process;\n\nlet forceColor;\nif (hasFlag('no-color') ||\n\thasFlag('no-colors') ||\n\thasFlag('color=false') ||\n\thasFlag('color=never')) {\n\tforceColor = 0;\n} else if (hasFlag('color') ||\n\thasFlag('colors') ||\n\thasFlag('color=true') ||\n\thasFlag('color=always')) {\n\tforceColor = 1;\n}\n\nif ('FORCE_COLOR' in env) {\n\tif (env.FORCE_COLOR === 'true') {\n\t\tforceColor = 1;\n\t} else if (env.FORCE_COLOR === 'false') {\n\t\tforceColor = 0;\n\t} else {\n\t\tforceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);\n\t}\n}\n\nfunction translateLevel(level) {\n\tif (level === 0) {\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tlevel,\n\t\thasBasic: true,\n\t\thas256: level >= 2,\n\t\thas16m: level >= 3\n\t};\n}\n\nfunction supportsColor(haveStream, streamIsTTY) {\n\tif (forceColor === 0) {\n\t\treturn 0;\n\t}\n\n\tif (hasFlag('color=16m') ||\n\t\thasFlag('color=full') ||\n\t\thasFlag('color=truecolor')) {\n\t\treturn 3;\n\t}\n\n\tif (hasFlag('color=256')) {\n\t\treturn 2;\n\t}\n\n\tif (haveStream && !streamIsTTY && forceColor === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst min = forceColor || 0;\n\n\tif (env.TERM === 'dumb') {\n\t\treturn min;\n\t}\n\n\tif (process.platform === 'win32') {\n\t\t// Windows 10 build 10586 is the first Windows release that supports 256 colors.\n\t\t// Windows 10 build 14931 is the first release that supports 16m/TrueColor.\n\t\tconst osRelease = os.release().split('.');\n\t\tif (\n\t\t\tNumber(osRelease[0]) >= 10 &&\n\t\t\tNumber(osRelease[2]) >= 10586\n\t\t) {\n\t\t\treturn Number(osRelease[2]) >= 14931 ? 3 : 2;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tif ('CI' in env) {\n\t\tif (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'GITHUB_ACTIONS', 'BUILDKITE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn min;\n\t}\n\n\tif ('TEAMCITY_VERSION' in env) {\n\t\treturn /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;\n\t}\n\n\tif (env.COLORTERM === 'truecolor') {\n\t\treturn 3;\n\t}\n\n\tif ('TERM_PROGRAM' in env) {\n\t\tconst version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n\t\tswitch (env.TERM_PROGRAM) {\n\t\t\tcase 'iTerm.app':\n\t\t\t\treturn version >= 3 ? 3 : 2;\n\t\t\tcase 'Apple_Terminal':\n\t\t\t\treturn 2;\n\t\t\t// No default\n\t\t}\n\t}\n\n\tif (/-256(color)?$/i.test(env.TERM)) {\n\t\treturn 2;\n\t}\n\n\tif (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n\t\treturn 1;\n\t}\n\n\tif ('COLORTERM' in env) {\n\t\treturn 1;\n\t}\n\n\treturn min;\n}\n\nfunction getSupportLevel(stream) {\n\tconst level = supportsColor(stream, stream && stream.isTTY);\n\treturn translateLevel(level);\n}\n\nmodule.exports = {\n\tsupportsColor: getSupportLevel,\n\tstdout: translateLevel(supportsColor(true, tty.isatty(1))),\n\tstderr: translateLevel(supportsColor(true, tty.isatty(2)))\n};\n","/**\n * Module dependencies.\n */\n\nconst tty = require('tty');\nconst util = require('util');\n\n/**\n * This is the Node.js implementation of `debug()`.\n */\n\nexports.init = init;\nexports.log = log;\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.destroy = util.deprecate(\n\t() => {},\n\t'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'\n);\n\n/**\n * Colors.\n */\n\nexports.colors = [6, 2, 3, 4, 5, 1];\n\ntry {\n\t// Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)\n\t// eslint-disable-next-line import/no-extraneous-dependencies\n\tconst supportsColor = require('supports-color');\n\n\tif (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {\n\t\texports.colors = [\n\t\t\t20,\n\t\t\t21,\n\t\t\t26,\n\t\t\t27,\n\t\t\t32,\n\t\t\t33,\n\t\t\t38,\n\t\t\t39,\n\t\t\t40,\n\t\t\t41,\n\t\t\t42,\n\t\t\t43,\n\t\t\t44,\n\t\t\t45,\n\t\t\t56,\n\t\t\t57,\n\t\t\t62,\n\t\t\t63,\n\t\t\t68,\n\t\t\t69,\n\t\t\t74,\n\t\t\t75,\n\t\t\t76,\n\t\t\t77,\n\t\t\t78,\n\t\t\t79,\n\t\t\t80,\n\t\t\t81,\n\t\t\t92,\n\t\t\t93,\n\t\t\t98,\n\t\t\t99,\n\t\t\t112,\n\t\t\t113,\n\t\t\t128,\n\t\t\t129,\n\t\t\t134,\n\t\t\t135,\n\t\t\t148,\n\t\t\t149,\n\t\t\t160,\n\t\t\t161,\n\t\t\t162,\n\t\t\t163,\n\t\t\t164,\n\t\t\t165,\n\t\t\t166,\n\t\t\t167,\n\t\t\t168,\n\t\t\t169,\n\t\t\t170,\n\t\t\t171,\n\t\t\t172,\n\t\t\t173,\n\t\t\t178,\n\t\t\t179,\n\t\t\t184,\n\t\t\t185,\n\t\t\t196,\n\t\t\t197,\n\t\t\t198,\n\t\t\t199,\n\t\t\t200,\n\t\t\t201,\n\t\t\t202,\n\t\t\t203,\n\t\t\t204,\n\t\t\t205,\n\t\t\t206,\n\t\t\t207,\n\t\t\t208,\n\t\t\t209,\n\t\t\t214,\n\t\t\t215,\n\t\t\t220,\n\t\t\t221\n\t\t];\n\t}\n} catch (error) {\n\t// Swallow - we only care if `supports-color` is available; it doesn't have to be.\n}\n\n/**\n * Build up the default `inspectOpts` object from the environment variables.\n *\n * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js\n */\n\nexports.inspectOpts = Object.keys(process.env).filter(key => {\n\treturn /^debug_/i.test(key);\n}).reduce((obj, key) => {\n\t// Camel-case\n\tconst prop = key\n\t\t.substring(6)\n\t\t.toLowerCase()\n\t\t.replace(/_([a-z])/g, (_, k) => {\n\t\t\treturn k.toUpperCase();\n\t\t});\n\n\t// Coerce string value into JS value\n\tlet val = process.env[key];\n\tif (/^(yes|on|true|enabled)$/i.test(val)) {\n\t\tval = true;\n\t} else if (/^(no|off|false|disabled)$/i.test(val)) {\n\t\tval = false;\n\t} else if (val === 'null') {\n\t\tval = null;\n\t} else {\n\t\tval = Number(val);\n\t}\n\n\tobj[prop] = val;\n\treturn obj;\n}, {});\n\n/**\n * Is stdout a TTY? Colored output is enabled when `true`.\n */\n\nfunction useColors() {\n\treturn 'colors' in exports.inspectOpts ?\n\t\tBoolean(exports.inspectOpts.colors) :\n\t\ttty.isatty(process.stderr.fd);\n}\n\n/**\n * Adds ANSI color escape codes if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\tconst {namespace: name, useColors} = this;\n\n\tif (useColors) {\n\t\tconst c = this.color;\n\t\tconst colorCode = '\\u001B[3' + (c < 8 ? c : '8;5;' + c);\n\t\tconst prefix = ` ${colorCode};1m${name} \\u001B[0m`;\n\n\t\targs[0] = prefix + args[0].split('\\n').join('\\n' + prefix);\n\t\targs.push(colorCode + 'm+' + module.exports.humanize(this.diff) + '\\u001B[0m');\n\t} else {\n\t\targs[0] = getDate() + name + ' ' + args[0];\n\t}\n}\n\nfunction getDate() {\n\tif (exports.inspectOpts.hideDate) {\n\t\treturn '';\n\t}\n\treturn new Date().toISOString() + ' ';\n}\n\n/**\n * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr.\n */\n\nfunction log(...args) {\n\treturn process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\\n');\n}\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\tif (namespaces) {\n\t\tprocess.env.DEBUG = namespaces;\n\t} else {\n\t\t// If you set a process.env field to null or undefined, it gets cast to the\n\t\t// string 'null' or 'undefined'. Just delete instead.\n\t\tdelete process.env.DEBUG;\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\n\nfunction load() {\n\treturn process.env.DEBUG;\n}\n\n/**\n * Init logic for `debug` instances.\n *\n * Create a new `inspectOpts` object in case `useColors` is set\n * differently for a particular `debug` instance.\n */\n\nfunction init(debug) {\n\tdebug.inspectOpts = {};\n\n\tconst keys = Object.keys(exports.inspectOpts);\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tdebug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];\n\t}\n}\n\nmodule.exports = require('./common')(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %o to `util.inspect()`, all on a single line.\n */\n\nformatters.o = function (v) {\n\tthis.inspectOpts.colors = this.useColors;\n\treturn util.inspect(v, this.inspectOpts)\n\t\t.split('\\n')\n\t\t.map(str => str.trim())\n\t\t.join(' ');\n};\n\n/**\n * Map %O to `util.inspect()`, allowing multiple lines if needed.\n */\n\nformatters.O = function (v) {\n\tthis.inspectOpts.colors = this.useColors;\n\treturn util.inspect(v, this.inspectOpts);\n};\n","/**\n * Detect Electron renderer / nwjs process, which is node, but we should\n * treat as a browser.\n */\n\nif (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {\n\tmodule.exports = require('./browser.js');\n} else {\n\tmodule.exports = require('./node.js');\n}\n","/* global performance */\nvar perf = typeof performance !== 'undefined' && performance;\n\nvar nowPolyfillForNode;\n\n{\n // implementation borrowed from:\n // https://github.com/myrne/performance-now/blob/6223a0d544bae1d5578dd7431f78b4ec7d65b15c/src/performance-now.coffee\n var hrtime = process.hrtime;\n var getNanoSeconds = function () {\n var hr = hrtime();\n return hr[0] * 1e9 + hr[1]\n };\n var loadTime = getNanoSeconds();\n nowPolyfillForNode = function () { return ((getNanoSeconds() - loadTime) / 1e6); };\n}\n\nvar now = perf && perf.now\n ? function () { return perf.now(); }\n : nowPolyfillForNode;\n\nfunction throwIfEmpty (name) {\n if (!name) {\n throw new Error('name must be non-empty')\n }\n}\n\n// simple binary sort insertion\nfunction insertSorted (arr, item) {\n var low = 0;\n var high = arr.length;\n var mid;\n while (low < high) {\n mid = (low + high) >>> 1; // like (num / 2) but faster\n if (arr[mid].startTime < item.startTime) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n arr.splice(low, 0, item);\n}\n\nvar mark;\nvar stop;\nvar getEntries;\nvar clear;\n\nif (\n perf &&\n perf.mark &&\n perf.measure &&\n perf.getEntriesByName &&\n perf.getEntriesByType &&\n perf.clearMarks &&\n perf.clearMeasures &&\n // In Node, we want to detect that this perf/correctness fix [1] is available, which\n // landed in Node 16.15.0, 17.6.0, and 18.0.0. However, it's not observable, and\n // we don't want to rely on fragile version checks.\n // So we can rely on this observable change [2] to add clearResourceTimings, which\n // landed a bit later (18.2.0), but is close enough for our purposes.\n // [1]: https://github.com/nodejs/node/pull/42032\n // [2]: https://github.com/nodejs/node/pull/42725\n (perf.clearResourceTimings)\n) {\n mark = function (name) {\n throwIfEmpty(name);\n perf.mark((\"start \" + name));\n };\n stop = function (name) {\n throwIfEmpty(name);\n perf.mark((\"end \" + name));\n var measure = perf.measure(name, (\"start \" + name), (\"end \" + name));\n if (measure) {\n // return value from performance.measure not supported in all browsers\n // https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure#browser_compatibility\n return measure\n }\n var entries = perf.getEntriesByName(name);\n return entries[entries.length - 1]\n };\n getEntries = function () { return perf.getEntriesByType('measure'); };\n clear = function () {\n perf.clearMarks();\n perf.clearMeasures();\n };\n} else {\n var marks = {};\n var entries = [];\n mark = function (name) {\n throwIfEmpty(name);\n var startTime = now();\n marks['$' + name] = startTime;\n };\n stop = function (name) {\n throwIfEmpty(name);\n var endTime = now();\n var startTime = marks['$' + name];\n if (!startTime) {\n throw new Error((\"no known mark: \" + name))\n }\n var entry = {\n startTime: startTime,\n name: name,\n duration: endTime - startTime,\n entryType: 'measure'\n };\n // per the spec this should be at least 150:\n // https://www.w3.org/TR/resource-timing-1/#extensions-performance-interface\n // we just have no limit, per Chrome and Edge's de-facto behavior\n insertSorted(entries, entry);\n return entry\n };\n getEntries = function () { return entries; };\n clear = function () {\n marks = {};\n entries = [];\n };\n}\n\nexport { clear, getEntries, mark, stop };\n","/**\n * @license\n * Copyright 2016 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport process from 'process';\nimport {EventEmitter} from 'events';\n\nimport debug from 'debug';\nimport * as marky from 'marky';\n\nconst isWindows = process.platform === 'win32';\n\n// @ts-expect-error: process.browser is set via Rollup.\nconst isBrowser = process.browser;\n\nconst colors = {\n red: isBrowser ? 'crimson' : 1,\n yellow: isBrowser ? 'gold' : 3,\n cyan: isBrowser ? 'darkturquoise' : 6,\n green: isBrowser ? 'forestgreen' : 2,\n blue: isBrowser ? 'steelblue' : 4,\n magenta: isBrowser ? 'palevioletred' : 5,\n};\n\n// allow non-red/yellow colors for debug()\ndebug.colors = [colors.cyan, colors.green, colors.blue, colors.magenta];\n\nclass Emitter extends EventEmitter {\n // yarn build-types fails without this!\n // https://github.com/microsoft/TypeScript/issues/41672#issuecomment-2303803072\n constructor(options) {\n super(options);\n }\n\n /**\n * Fires off all status updates. Listen with\n * `require('lib/log').events.addListener('status', callback)`\n * @param {string} title\n * @param {!Array<*>} argsArray\n */\n issueStatus(title, argsArray) {\n if (title === 'status' || title === 'statusEnd') {\n this.emit(title, [title, ...argsArray]);\n }\n }\n\n /**\n * Fires off all warnings. Listen with\n * `require('lib/log').events.addListener('warning', callback)`\n * @param {string} title\n * @param {!Array<*>} argsArray\n */\n issueWarning(title, argsArray) {\n this.emit('warning', [title, ...argsArray]);\n }\n}\n\nconst loggersByTitle = {};\nconst loggingBufferColumns = 25;\nlet level_;\n\nclass Log {\n static _logToStdErr(title, argsArray) {\n const log = Log.loggerfn(title);\n log(...argsArray);\n }\n\n /**\n * @param {string} title\n */\n static loggerfn(title) {\n title = `LH:${title}`;\n let log = loggersByTitle[title];\n if (!log) {\n log = debug(title);\n loggersByTitle[title] = log;\n // errors with red, warnings with yellow.\n if (title.endsWith('error')) {\n log.color = colors.red;\n } else if (title.endsWith('warn')) {\n log.color = colors.yellow;\n }\n }\n return log;\n }\n\n /**\n * @param {string} level\n */\n static setLevel(level) {\n level_ = level;\n switch (level) {\n case 'silent':\n debug.enable('-LH:*');\n break;\n case 'verbose':\n debug.enable('LH:*');\n break;\n case 'warn':\n debug.enable('-LH:*, LH:*:warn, LH:*:error');\n break;\n case 'error':\n debug.enable('-LH:*, LH:*:error');\n break;\n default:\n debug.enable('LH:*, -LH:*:verbose');\n }\n }\n\n /**\n * A simple formatting utility for event logging.\n * @param {string} prefix\n * @param {!Object} data A JSON-serializable object of event data to log.\n * @param {string=} level Optional logging level. Defaults to 'log'.\n */\n static formatProtocol(prefix, data, level) {\n const columns = (!process || process.browser) ? Infinity : process.stdout.columns;\n const method = data.method || '?????';\n const maxLength = columns - method.length - prefix.length - loggingBufferColumns;\n // IO.read ignored here to avoid logging megabytes of trace data\n const snippet = (data.params && method !== 'IO.read') ?\n JSON.stringify(data.params).substr(0, maxLength) : '';\n Log._logToStdErr(`${prefix}:${level || ''}`, [method, snippet]);\n }\n\n /**\n * @return {boolean}\n */\n static isVerbose() {\n return level_ === 'verbose';\n }\n\n /**\n * @param {{msg: string, id: string, args?: any[]}} status\n * @param {string} level\n */\n static time({msg, id, args = []}, level = 'log') {\n marky.mark(id);\n Log[level]('status', msg, ...args);\n }\n\n /**\n * @param {{msg: string, id: string, args?: any[]}} status\n * @param {string} level\n */\n static timeEnd({msg, id, args = []}, level = 'verbose') {\n Log[level]('statusEnd', msg, ...args);\n marky.stop(id);\n }\n\n /**\n * @param {string} title\n * @param {...any} args\n */\n static log(title, ...args) {\n Log.events.issueStatus(title, args);\n return Log._logToStdErr(title, args);\n }\n\n /**\n * @param {string} title\n * @param {...any} args\n */\n static warn(title, ...args) {\n Log.events.issueWarning(title, args);\n return Log._logToStdErr(`${title}:warn`, args);\n }\n\n /**\n * @param {string} title\n * @param {...any} args\n */\n static error(title, ...args) {\n return Log._logToStdErr(`${title}:error`, args);\n }\n\n /**\n * @param {string} title\n * @param {...any} args\n */\n static verbose(title, ...args) {\n Log.events.issueStatus(title, args);\n return Log._logToStdErr(`${title}:verbose`, args);\n }\n\n /**\n * Add surrounding escape sequences to turn a string green when logged.\n * @param {string} str\n * @return {string}\n */\n static greenify(str) {\n return `${Log.green}${str}${Log.reset}`;\n }\n\n /**\n * Add surrounding escape sequences to turn a string red when logged.\n * @param {string} str\n * @return {string}\n */\n static redify(str) {\n return `${Log.red}${str}${Log.reset}`;\n }\n\n static get green() {\n return '\\x1B[32m';\n }\n\n static get red() {\n return '\\x1B[31m';\n }\n\n static get yellow() {\n return '\\x1b[33m';\n }\n\n static get purple() {\n return '\\x1b[95m';\n }\n\n static get reset() {\n return '\\x1B[0m';\n }\n\n static get bold() {\n return '\\x1b[1m';\n }\n\n static get dim() {\n return '\\x1b[2m';\n }\n\n static get tick() {\n return isWindows ? '\\u221A' : '✓';\n }\n\n static get cross() {\n return isWindows ? '\\u00D7' : '✘';\n }\n\n static get whiteSmallSquare() {\n return isWindows ? '\\u0387' : '▫';\n }\n\n static get heavyHorizontal() {\n return isWindows ? '\\u2500' : '━';\n }\n\n static get heavyVertical() {\n return isWindows ? '\\u2502 ' : '┃ ';\n }\n\n static get heavyUpAndRight() {\n return isWindows ? '\\u2514' : '┗';\n }\n\n static get heavyVerticalAndRight() {\n return isWindows ? '\\u251C' : '┣';\n }\n\n static get heavyDownAndHorizontal() {\n return isWindows ? '\\u252C' : '┳';\n }\n\n static get doubleLightHorizontal() {\n return '──';\n }\n}\n\nLog.events = new Emitter();\n\n/**\n * @return {PerformanceEntry[]}\n */\nLog.takeTimeEntries = () => {\n const entries = marky.getEntries();\n marky.clear();\n return entries;\n};\n\n/**\n * @return {PerformanceEntry[]}\n */\nLog.getTimeEntries = () => marky.getEntries();\n\nexport default Log;\n","'use strict';\nconst fs = require('fs');\n\nlet isDocker;\n\nfunction hasDockerEnv() {\n\ttry {\n\t\tfs.statSync('/.dockerenv');\n\t\treturn true;\n\t} catch (_) {\n\t\treturn false;\n\t}\n}\n\nfunction hasDockerCGroup() {\n\ttry {\n\t\treturn fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');\n\t} catch (_) {\n\t\treturn false;\n\t}\n}\n\nmodule.exports = () => {\n\tif (isDocker === undefined) {\n\t\tisDocker = hasDockerEnv() || hasDockerCGroup();\n\t}\n\n\treturn isDocker;\n};\n","'use strict';\nconst os = require('os');\nconst fs = require('fs');\nconst isDocker = require('is-docker');\n\nconst isWsl = () => {\n\tif (process.platform !== 'linux') {\n\t\treturn false;\n\t}\n\n\tif (os.release().toLowerCase().includes('microsoft')) {\n\t\tif (isDocker()) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\ttry {\n\t\treturn fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft') ?\n\t\t\t!isDocker() : false;\n\t} catch (_) {\n\t\treturn false;\n\t}\n};\n\nif (process.env.__IS_WSL_TEST__) {\n\tmodule.exports = isWsl;\n} else {\n\tmodule.exports = isWsl();\n}\n",null,null,null,null,null,null,"/**\r\n * Test Runner — main orchestrator for Phase 4.\r\n *\r\n * Flow:\r\n * 1. Resolve which suites/cases to run from RunConfig\r\n * 2. For each configured browser, run cases (up to config.parallel at once)\r\n * 3. Execute each step via StepExecutor (with self-healing)\r\n * 4. Collect results, generate Allure/HTML/JSON reports\r\n * 5. Flush healing events for human review\r\n * 6. Close all browsers\r\n */\r\nimport path from 'path';\r\nimport { randomUUID } from 'crypto';\r\nimport fs from 'fs-extra';\r\nimport type { RunConfig, RunResult, SuiteResult, TestCaseResult, StepResult, PageLoadMetric } from '../types/run.js';\r\nimport type { AutotestConfig } from '../types/config.js';\r\nimport type { TestCase, TestSuite } from '../types/suite.js';\r\nimport { listSuites, findSuiteDirById } from '../storage/suite-store.js';\r\nimport { listCases } from '../storage/case-store.js';\r\nimport { resolveVariables } from '../storage/variable-store.js';\r\nimport { writeResult } from '../storage/result-store.js';\r\nimport { createSmartRouter } from '../ai/router.js';\r\nimport { BrowserManager } from './browser-manager.js';\r\nimport { HealingBudget } from './healing-budget.js';\r\nimport { HealingReporter } from './healing-report.js';\r\nimport { AllureReporter } from './allure-reporter.js';\r\nimport { generateAllureReport } from './allure-generator.js';\r\nimport { executeStep } from './executor.js';\r\nimport { installHighlighter } from './highlighter.js';\r\nimport { loadDataRows } from './data-loader.js';\r\nimport { detectStepType } from './step-type-detector.js';\r\nimport { createChildLogger, createRunLogFile, type RunLogHandle } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('runner');\r\n\r\n/** Returns true if every step in the case is an API step (no UI). */\r\nfunction isCaseApiOnly(tc: TestCase): boolean {\r\n if (tc.steps.length === 0) return false;\r\n return tc.steps.every((s) => (s.stepType ?? detectStepType(s.instruction)) === 'api');\r\n}\r\n\r\n/** Returns true if the suite-level type is 'api'. */\r\nfunction isSuiteApiOnly(suite: TestSuite): boolean {\r\n return suite.type === 'api';\r\n}\r\n\r\n/** Returns true if the suite is an audit suite (audit or legacy performance). */\r\nfunction isSuiteAudit(suite: TestSuite): boolean {\r\n return suite.type === 'audit' || suite.type === 'performance';\r\n}\r\n\r\n// ─── Minimal broadcaster interface (duck-typed — no circular import) ──────────\r\n\r\ninterface WsBroadcaster {\r\n broadcast(event: string, data: unknown): void;\r\n}\r\n\r\n// ─── Public API ───────────────────────────────────────────────────────────────\r\n\r\nexport async function runTests(\r\n rootDir: string,\r\n runConfig: RunConfig,\r\n autotestConfig: AutotestConfig,\r\n ws?: WsBroadcaster,\r\n): Promise<RunResult> {\r\n const runId = randomUUID();\r\n const startedAt = new Date().toISOString();\r\n const testsDir = path.join(rootDir, 'tests');\r\n\r\n // ── Resolve environment-specific baseUrl ──────────────────────────────────\r\n const activeEnv = autotestConfig.environment ?? 'dev';\r\n const envUrl = autotestConfig.environmentUrls?.[activeEnv as keyof typeof autotestConfig.environmentUrls];\r\n if (envUrl) {\r\n autotestConfig = { ...autotestConfig, baseUrl: envUrl };\r\n }\r\n\r\n logger.info({ runId, runConfig, environment: activeEnv, baseUrl: autotestConfig.baseUrl }, 'Run started');\r\n\r\n // ── Create per-run log file ───────────────────────────────────────────────\r\n const runLog = await createRunLogFile(rootDir, runId);\r\n const logToFile = (level: string, msg: string, data?: Record<string, unknown>) => {\r\n const ts = new Date().toISOString();\r\n const extra = data ? ' ' + JSON.stringify(data) : '';\r\n runLog.write(`[${ts}] [${level.toUpperCase()}] ${msg}${extra}`);\r\n };\r\n logToFile('info', 'Run started', { runId, environment: activeEnv, baseUrl: autotestConfig.baseUrl });\r\n\r\n const browserManager = new BrowserManager();\r\n const healingReporter = new HealingReporter();\r\n const allureReporter = new AllureReporter(rootDir, runId, activeEnv);\r\n\r\n try {\r\n // ── 1. Collect suites + cases to run ────────────────────────────────────\r\n const pairs = await collectWork(testsDir, runConfig);\r\n\r\n if (pairs.length === 0) {\r\n logger.warn({ runConfig }, 'No tests matched the run config');\r\n }\r\n\r\n // ── 2. Variables ─────────────────────────────────────────────────────────\r\n const variables = await loadVariables(rootDir, runConfig.env);\r\n const sharedVariables = new Map<string, string>(); // Runtime shared context across cases\r\n\r\n // ── 2b. Expand data-driven cases ─────────────────────────────────────────\r\n // If a test case has a dataSource, load data rows and create one WorkPair per row.\r\n const expandedPairs: Array<WorkPair & { dataRow?: Record<string, string>; dataRowIndex?: number }> = [];\r\n for (const pair of pairs) {\r\n if (pair.testCase.dataSource) {\r\n try {\r\n const rows = await loadDataRows(rootDir, pair.testCase.dataSource);\r\n if (rows.length > 0) {\r\n rows.forEach((row, idx) => expandedPairs.push({ ...pair, dataRow: row, dataRowIndex: idx }));\r\n logger.info({ caseId: pair.testCase.id, rows: rows.length }, 'Expanded data-driven case');\r\n continue;\r\n }\r\n } catch (err) {\r\n logger.warn({ err, caseId: pair.testCase.id }, 'Failed to load data rows — running case once');\r\n }\r\n }\r\n expandedPairs.push(pair);\r\n }\r\n\r\n // Broadcast run:start so the UI spinner activates immediately\r\n ws?.broadcast('run:start', { runId, totalTests: expandedPairs.length });\r\n\r\n // ── 3. AI provider ────────────────────────────────────────────────────────\r\n const smartRouter = createSmartRouter(rootDir);\r\n const provider = smartRouter.getPrimaryProvider();\r\n\r\n // ── 4. Healing budget ────────────────────────────────────────────────────\r\n const budget = new HealingBudget(autotestConfig.healing.dailyBudget);\r\n\r\n // ── 5. Run across browsers ───────────────────────────────────────────────\r\n const browsers = autotestConfig.browsers;\r\n const allSuiteResults: SuiteResult[] = [];\r\n\r\n // Check if ALL cases in this run are API-only — if so, skip browser entirely.\r\n // Audit suites always need a browser (same as UI), so they prevent allApiOnly.\r\n const allApiOnly = expandedPairs.length > 0 &&\r\n expandedPairs.every(({ suite, testCase }) =>\r\n (isSuiteApiOnly(suite) || isCaseApiOnly(testCase)) &&\r\n !isSuiteAudit(suite),\r\n );\r\n\r\n if (allApiOnly) {\r\n logger.info('All test cases are API-only — no browser will be launched');\r\n logToFile('info', 'API-only run detected — skipping browser launch');\r\n }\r\n\r\n // Launch all browsers in parallel\r\n const browserInstances = new Map<string, import('playwright').Browser | null>();\r\n if (allApiOnly) {\r\n for (const b of browsers) browserInstances.set(b, null);\r\n } else {\r\n const launched = await Promise.all(\r\n browsers.map(async (b) => ({\r\n name: b,\r\n instance: await browserManager.launchBrowser(b, autotestConfig),\r\n })),\r\n );\r\n for (const { name, instance } of launched) browserInstances.set(name, instance);\r\n }\r\n\r\n // Flatten browser × case pairs so they can all run concurrently\r\n interface BrowserCasePair {\r\n browserName: string;\r\n browser: import('playwright').Browser | null;\r\n suite: typeof expandedPairs[0]['suite'];\r\n testCase: typeof expandedPairs[0]['testCase'];\r\n dataRow: typeof expandedPairs[0]['dataRow'];\r\n dataRowIndex: typeof expandedPairs[0]['dataRowIndex'];\r\n }\r\n const allPairs: BrowserCasePair[] = [];\r\n for (const browserName of browsers) {\r\n const browser = browserInstances.get(browserName) ?? null;\r\n for (const pair of expandedPairs) {\r\n allPairs.push({ browserName, browser, ...pair });\r\n }\r\n }\r\n\r\n // Run all browser+case combinations with the configured parallelism\r\n const allCaseResults = await runWithConcurrency(\r\n allPairs,\r\n autotestConfig.parallel,\r\n async ({ browserName, browser, suite, testCase, dataRow, dataRowIndex }) => {\r\n // Merge data row variables into the variable set for this case\r\n const caseVariables = dataRow ? { ...variables, ...dataRow } : variables;\r\n const caseName = dataRow\r\n ? `${testCase.name} [row ${(dataRowIndex ?? 0) + 1}]`\r\n : testCase.name;\r\n\r\n // Notify UI which case is starting\r\n ws?.broadcast('run:case', {\r\n runId,\r\n suiteId: suite.id,\r\n caseId: `${testCase.id}_${browserName}`,\r\n caseName: browsers.length > 1 ? `${caseName} [${browserName}]` : caseName,\r\n browser: browserName,\r\n status: 'running',\r\n });\r\n const compositeCaseId = `${testCase.id}_${browserName}`;\r\n logToFile('info', `Case started: ${suite.name} > ${caseName}`, { suiteId: suite.id, caseId: testCase.id, browser: browserName });\r\n const result = await runCase(\r\n rootDir,\r\n runId,\r\n suite,\r\n testCase,\r\n browserName,\r\n browser,\r\n autotestConfig,\r\n caseVariables,\r\n sharedVariables,\r\n provider,\r\n budget,\r\n healingReporter,\r\n browserManager,\r\n ws,\r\n logToFile,\r\n compositeCaseId,\r\n );\r\n\r\n // Attach suite type so Reports can render audit-specific view\r\n result.suiteType = suite.type;\r\n\r\n // Annotate result with data row info\r\n if (dataRow !== undefined) {\r\n result.caseResult.dataRowIndex = dataRowIndex;\r\n result.caseResult.dataRow = dataRow;\r\n result.caseResult.caseName = caseName;\r\n }\r\n\r\n // Notify UI of per-case result so Last Run status updates immediately\r\n ws?.broadcast('run:case:done', {\r\n runId,\r\n suiteId: suite.id,\r\n caseId: testCase.id,\r\n status: result.caseResult.status,\r\n });\r\n logToFile('info', `Case finished: ${caseName} [${browserName}] — ${result.caseResult.status.toUpperCase()}`, {\r\n duration: result.caseResult.duration,\r\n steps: result.caseResult.steps.length,\r\n passed: result.caseResult.steps.filter(s => s.status === 'passed').length,\r\n failed: result.caseResult.steps.filter(s => s.status === 'failed').length,\r\n });\r\n return { ...result, browserName };\r\n },\r\n );\r\n\r\n // Group into SuiteResults — partition by browser when multi-browser\r\n if (browsers.length > 1) {\r\n for (const browserName of browsers) {\r\n const browserResults = allCaseResults.filter((r) => r.browserName === browserName);\r\n const grouped = groupBySuite(browserResults, browserName);\r\n allSuiteResults.push(...grouped);\r\n }\r\n } else {\r\n const grouped = groupBySuite(allCaseResults);\r\n allSuiteResults.push(...grouped);\r\n }\r\n\r\n // ── 6. Build RunResult ───────────────────────────────────────────────────\r\n const finishedAt = new Date().toISOString();\r\n const runResult = buildRunResult(runId, startedAt, finishedAt, allSuiteResults, activeEnv);\r\n\r\n // Attach log file path to run result\r\n runResult.logFilePath = runLog.logFilePath;\r\n\r\n // Write run summary to log file\r\n logToFile('info', `Run finished: ${runResult.status.toUpperCase()}`, {\r\n totalTests: runResult.totalTests,\r\n passed: runResult.passed,\r\n failed: runResult.failed,\r\n skipped: runResult.skipped,\r\n duration: runResult.duration,\r\n });\r\n runLog.close();\r\n\r\n // ── 7. Persist results ───────────────────────────────────────────────────\r\n await writeResult(rootDir, runResult);\r\n\r\n if (autotestConfig.reporting.allure) {\r\n await allureReporter.writeResults(runResult);\r\n // Generate the HTML report in the background so it is ready before the\r\n // user opens the Reports page. Failure is non-fatal (e.g. no Java).\r\n generateAllureReport(rootDir, runId).catch(() => undefined);\r\n }\r\n\r\n if (autotestConfig.reporting.json) {\r\n const jsonPath = path.join(rootDir, 'results', `run-${runId}.json`);\r\n await fs.ensureDir(path.dirname(jsonPath));\r\n await fs.writeJson(jsonPath, runResult, { spaces: 2 });\r\n }\r\n\r\n // ── 8. Flush healing events ──────────────────────────────────────────────\r\n await healingReporter.flush(rootDir, runId);\r\n\r\n // ── 9. Persist AI code cache ──────────────────────────────────────────────\r\n await smartRouter.getCache().persist();\r\n\r\n logger.info(\r\n {\r\n runId,\r\n passed: runResult.passed,\r\n failed: runResult.failed,\r\n total: runResult.totalTests,\r\n healingSpend: budget.totalSpent,\r\n },\r\n 'Run finished',\r\n );\r\n\r\n return runResult;\r\n } finally {\r\n await browserManager.closeAll();\r\n }\r\n}\r\n\r\n// ─── Case runner ─────────────────────────────────────────────────────────────\r\n\r\ninterface CaseRunResult {\r\n suiteId: string;\r\n suiteName: string;\r\n suiteType?: string;\r\n caseResult: TestCaseResult;\r\n}\r\n\r\nasync function runCase(\r\n rootDir: string,\r\n runId: string,\r\n suite: TestSuite,\r\n testCase: TestCase,\r\n browserName: string,\r\n browser: import('playwright').Browser | null,\r\n config: AutotestConfig,\r\n variables: Record<string, string>,\r\n sharedVariables: Map<string, string>,\r\n provider: import('../types/ai.js').AIProvider,\r\n budget: HealingBudget,\r\n healingReporter: HealingReporter,\r\n browserManager: BrowserManager,\r\n ws?: WsBroadcaster,\r\n logToFile?: (level: string, msg: string, data?: Record<string, unknown>) => void,\r\n /** Override caseId used in WS broadcasts (e.g. composite id for multi-browser). */\r\n wsCaseId?: string,\r\n): Promise<CaseRunResult> {\r\n const broadcastCaseId = wsCaseId ?? testCase.id;\r\n const caseStart = new Date().toISOString();\r\n const stepResults: StepResult[] = [];\r\n const previousSteps: Array<{ instruction: string; code: string }> = [];\r\n\r\n const apiOnly = isSuiteApiOnly(suite) || isCaseApiOnly(testCase);\r\n\r\n // Audit suites focus on Lighthouse metrics — disable screenshot, video and trace\r\n // to avoid unnecessary overhead. UI/API suites keep their configured capture settings.\r\n const caseConfig = isSuiteAudit(suite)\r\n ? { ...config, screenshot: 'off' as const, video: 'off' as const, trace: 'off' as const }\r\n : config;\r\n\r\n const tracePath =\r\n !apiOnly && caseConfig.trace !== 'off'\r\n ? path.join(rootDir, 'results', 'traces', `${runId}_${testCase.id}_${browserName}.zip`)\r\n : undefined;\r\n\r\n // API-only cases: zero browser — use standalone Playwright APIRequestContext\r\n // UI cases: full browser context with video recording, tracing, element highlighting\r\n let context: import('playwright').BrowserContext | null = null;\r\n let page: import('playwright').Page;\r\n\r\n if (apiOnly) {\r\n // No browser needed — create a lightweight fake page with only page.request\r\n page = await browserManager.createApiOnlyPage(config.baseUrl);\r\n logger.debug({ caseName: testCase.name }, 'API-only case — zero browser, using standalone HTTP client');\r\n } else {\r\n if (!browser) throw new Error('Browser required for UI test cases');\r\n context = await browserManager.newContext(browser, caseConfig, path.join(rootDir, 'results', 'videos'));\r\n page = await browserManager.newPage(context);\r\n // Install element highlighter — colors each interacted element during execution.\r\n await installHighlighter(page);\r\n }\r\n\r\n let caseStatus: TestCaseResult['status'] = 'passed';\r\n let aborted = false;\r\n let pageLoads: PageLoadMetric[] = [];\r\n\r\n let pendingVideoPath: string | undefined;\r\n\r\n // Helper to execute a hook step (before/after)\r\n const execHookStep = async (hookStep: { id: string; instruction: string; generatedCode: string; order: number }) => {\r\n const effectiveTimeout = testCase.timeout ?? suite.timeout ?? caseConfig.timeout;\r\n const effectiveConfig = effectiveTimeout !== caseConfig.timeout ? { ...caseConfig, timeout: effectiveTimeout } : caseConfig;\r\n try {\r\n await executeStep(\r\n { ...hookStep, strategy: 'primary', stepType: 'ui', lastHealed: null } as import('../types/suite.js').TestStep,\r\n page,\r\n {\r\n runId, suiteId: suite.id, caseId: testCase.id, browser: browserName,\r\n rootDir, previousSteps, variables, sharedVariables, config: effectiveConfig,\r\n provider, budget, healingReporter,\r\n },\r\n );\r\n } catch {\r\n // Hook errors are non-fatal in isolation but logged\r\n }\r\n };\r\n\r\n try {\r\n // ── Before hooks ────────────────────────────────────────────────────────\r\n for (const hookStep of testCase.caseHooks?.before ?? []) {\r\n await execHookStep(hookStep);\r\n }\r\n\r\n for (const step of testCase.steps) {\r\n if (aborted) {\r\n stepResults.push({\r\n stepId: step.id,\r\n instruction: step.instruction,\r\n status: 'skipped',\r\n code: step.generatedCode,\r\n duration: 0,\r\n });\r\n continue;\r\n }\r\n\r\n // Broadcast the step as it starts so the UI shows it immediately\r\n ws?.broadcast('run:step', {\r\n runId,\r\n caseId: broadcastCaseId,\r\n stepId: step.id,\r\n instruction: step.instruction,\r\n status: 'running',\r\n duration: 0,\r\n });\r\n\r\n // Resolve effective timeout: case-level > suite-level > global\r\n const effectiveTimeout = testCase.timeout ?? suite.timeout ?? caseConfig.timeout;\r\n const effectiveConfig = effectiveTimeout !== caseConfig.timeout\r\n ? { ...caseConfig, timeout: effectiveTimeout }\r\n : caseConfig;\r\n\r\n const result = await executeStep(step, page, {\r\n runId,\r\n suiteId: suite.id,\r\n caseId: testCase.id,\r\n browser: browserName,\r\n rootDir,\r\n previousSteps,\r\n variables,\r\n sharedVariables,\r\n config: effectiveConfig,\r\n provider,\r\n budget,\r\n healingReporter,\r\n });\r\n\r\n // Broadcast the completed step result\r\n ws?.broadcast('run:step', {\r\n runId,\r\n caseId: broadcastCaseId,\r\n stepId: result.stepId,\r\n instruction: result.instruction,\r\n status: result.status,\r\n duration: result.duration,\r\n });\r\n\r\n // ── Live browser preview: capture screenshot + console logs ──\r\n if (!apiOnly && ws) {\r\n try {\r\n const screenshotBuf = await page.screenshot({ type: 'jpeg', quality: 60 });\r\n ws.broadcast('run:screenshot', {\r\n runId,\r\n caseId: broadcastCaseId,\r\n stepId: result.stepId,\r\n image: screenshotBuf.toString('base64'),\r\n timestamp: Date.now(),\r\n });\r\n } catch { /* page may have closed */ }\r\n\r\n const consoleLogs = browserManager.drainConsoleLogs(page);\r\n if (consoleLogs.length > 0) {\r\n ws.broadcast('run:console', {\r\n runId,\r\n caseId: broadcastCaseId,\r\n stepId: result.stepId,\r\n logs: consoleLogs,\r\n });\r\n }\r\n }\r\n\r\n // Log step result to run log file\r\n const stepLogLevel = result.status === 'failed' ? 'error' : 'info';\r\n logToFile?.(stepLogLevel, ` Step ${step.order}: ${result.instruction} — ${result.status.toUpperCase()} (${result.duration}ms)`, {\r\n ...(result.error ? { error: result.error } : {}),\r\n ...(result.healed ? { healed: true } : {}),\r\n });\r\n\r\n stepResults.push(result);\r\n\r\n if (result.status === 'passed') {\r\n previousSteps.push({ instruction: step.instruction, code: result.code });\r\n } else if (result.status === 'failed') {\r\n caseStatus = 'failed';\r\n aborted = true; // stop executing further steps on failure\r\n }\r\n }\r\n\r\n // ── Lighthouse performance audit (Chromium only) ─────────────────────────\r\n // For audit suites: default to all 3 categories when none are explicitly selected.\r\n // For non-audit suites: skip Lighthouse when lighthouseCategories is empty.\r\n const lhCategoriesForCase: ('performance' | 'accessibility' | 'seo')[] | null = (() => {\r\n const cats = testCase.lighthouseCategories;\r\n if (cats && cats.length > 0) return cats;\r\n if (isSuiteAudit(suite)) return ['performance', 'accessibility', 'seo']; // audit default: all\r\n return null; // non-audit: skip Lighthouse when no categories selected\r\n })();\r\n\r\n if (!apiOnly && browserName === 'chromium' && browser && lhCategoriesForCase !== null) {\r\n // Build a map from stepId → original TestStep so we can check runAudit flag\r\n const stepDefMap = new Map(testCase.steps.map((s) => [s.id, s]));\r\n\r\n // Lighthouse only runs on steps explicitly flagged with runAudit=true.\r\n // If no steps are flagged, skip Lighthouse entirely — the user must opt in per step.\r\n const hasAuditCheckpoints = testCase.steps.some((s) => s.runAudit === true);\r\n\r\n const navigatedSteps = hasAuditCheckpoints\r\n ? stepResults\r\n .map((s, idx) => ({ s, idx }))\r\n .filter(({ s }) => stepDefMap.get(s.stepId)?.runAudit === true && !!(s.auditUrl ?? s.navigatedToUrl))\r\n : []; // no ⚡ Audit flags set → skip Lighthouse\r\n\r\n const lhCategories = lhCategoriesForCase;\r\n\r\n if (navigatedSteps.length > 0) {\r\n logToFile?.('info', `--- LIGHTHOUSE AUDIT [${lhCategories.join(', ')}] ---`);\r\n try {\r\n const { default: lighthouse } = await import('lighthouse') as { default: typeof import('lighthouse').default };\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const chromeLauncher = await import('chrome-launcher') as any;\r\n const launch: (opts: Record<string, unknown>) => Promise<{ port: number; kill: () => Promise<void> }> =\r\n chromeLauncher.launch ?? chromeLauncher.default?.launch;\r\n\r\n // Use Playwright's own Chromium binary so no separate Chrome install is needed\r\n const { chromium: pwChromium } = await import('playwright') as { chromium: typeof import('playwright').chromium };\r\n const chromePath = pwChromium.executablePath();\r\n\r\n // Base dir for per-audit Chrome user-data dirs (avoids Windows %TEMP% permission issues)\r\n const lhBaseDir = path.join(rootDir, 'results', '.lh-profiles');\r\n await fs.ensureDir(lhBaseDir);\r\n\r\n for (let auditIdx = 0; auditIdx < navigatedSteps.length; auditIdx++) {\r\n const { s, idx } = navigatedSteps[auditIdx];\r\n // auditUrl is set when runAudit=true on a non-navigating step; fall back to navigatedToUrl\r\n const url = (s.auditUrl ?? s.navigatedToUrl) as string;\r\n logToFile?.('info', ` Auditing: ${url}`);\r\n let chromeInstance: { port: number; kill: () => Promise<void> } | null = null;\r\n // Use index in dir name to avoid collisions when two steps complete <1ms apart\r\n const userDataDir = path.join(lhBaseDir, `audit-${Date.now()}-${auditIdx}`);\r\n try {\r\n await fs.ensureDir(userDataDir);\r\n // Launch a dedicated headless Chrome for this Lighthouse audit.\r\n // Explicit userDataDir avoids Windows EPERM errors on %TEMP%\\lighthouse.*\r\n chromeInstance = await launch({\r\n chromePath,\r\n chromeFlags: ['--headless', '--no-sandbox', '--disable-gpu'],\r\n userDataDir,\r\n logLevel: 'silent',\r\n });\r\n\r\n const runnerResult = await Promise.race([\r\n lighthouse(url, {\r\n port: chromeInstance.port,\r\n output: 'json',\r\n logLevel: 'silent',\r\n onlyCategories: lhCategories,\r\n disableStorageReset: true,\r\n screenEmulation: { disabled: true },\r\n throttlingMethod: 'simulate',\r\n formFactor: 'desktop',\r\n } as Parameters<typeof lighthouse>[1]),\r\n new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error('Lighthouse audit timed out after 60s')), 60000),\r\n ),\r\n ]);\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const lhr = (runnerResult as any)?.lhr;\r\n const audits = lhr?.audits ?? {};\r\n const cats = lhr?.categories ?? {};\r\n\r\n // Coerce null → undefined for all numeric fields so Zod validation passes\r\n const nv = (id: string): number | undefined => {\r\n const v = audits[id]?.numericValue;\r\n return (v != null && isFinite(v)) ? v : undefined;\r\n };\r\n // Convert raw 0-1 Lighthouse category score → 0-100 integer.\r\n const catScore = (key: string): number | undefined => {\r\n const v = cats[key]?.score;\r\n return v != null ? Math.round(v * 100) : undefined;\r\n };\r\n\r\n // Extract individual audit pass/fail items for a category.\r\n // Only includes audits that have a weight (meaningful to the score).\r\n const getCategoryAudits = (categoryId: string) => {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const refs: any[] = cats[categoryId]?.auditRefs ?? [];\r\n return refs\r\n .filter((ref: any) => (ref.weight ?? 0) > 0)\r\n .map((ref: any) => {\r\n const audit = audits[ref.id];\r\n const sc = audit?.score ?? null;\r\n const partial = sc !== null && sc > 0 && sc < 1;\r\n return {\r\n id: ref.id as string,\r\n title: (audit?.title ?? ref.id) as string,\r\n passed: sc === 1,\r\n partial: partial || undefined,\r\n na: sc === null || undefined,\r\n };\r\n })\r\n // sort: failures first, partial (needs work), then N/A, then passes\r\n .sort((a: any, b: any) => {\r\n const rank = (x: any) => x.na ? 3 : x.passed ? 4 : x.partial ? 1 : 0;\r\n return rank(a) - rank(b);\r\n });\r\n };\r\n\r\n const hasPerf = lhCategories.includes('performance');\r\n const hasA11y = lhCategories.includes('accessibility');\r\n const hasSeo = lhCategories.includes('seo');\r\n const entry: PageLoadMetric = {\r\n url,\r\n stepIndex: idx,\r\n stepInstruction: s.instruction,\r\n score: hasPerf ? catScore('performance') : undefined,\r\n a11yScore: hasA11y ? catScore('accessibility') : undefined,\r\n seoScore: hasSeo ? catScore('seo') : undefined,\r\n fcp: hasPerf ? nv('first-contentful-paint') : undefined,\r\n lcp: hasPerf ? nv('largest-contentful-paint'): undefined,\r\n cls: hasPerf ? nv('cumulative-layout-shift') : undefined,\r\n ttfb: hasPerf ? nv('server-response-time') : undefined,\r\n tbt: hasPerf ? nv('total-blocking-time') : undefined,\r\n si: hasPerf ? nv('speed-index') : undefined,\r\n tti: hasPerf ? nv('interactive') : undefined,\r\n inp: hasPerf ? nv('interaction-to-next-paint'): undefined,\r\n a11yAudits: hasA11y ? getCategoryAudits('accessibility') : undefined,\r\n seoAudits: hasSeo ? getCategoryAudits('seo') : undefined,\r\n };\r\n pageLoads.push(entry);\r\n\r\n logToFile?.('info', ` Perf: ${entry.score ?? '--'} | A11y: ${entry.a11yScore ?? '--'} | SEO: ${entry.seoScore ?? '--'} | FCP: ${entry.fcp != null ? (entry.fcp / 1000).toFixed(2) + 's' : '--'} | LCP: ${entry.lcp != null ? (entry.lcp / 1000).toFixed(2) + 's' : '--'} | CLS: ${entry.cls?.toFixed(3) ?? '--'} | TTFB: ${entry.ttfb != null ? (entry.ttfb / 1000).toFixed(2) + 's' : '--'}`);\r\n } catch (auditErr) {\r\n const errMsg = auditErr instanceof Error ? auditErr.message : String(auditErr);\r\n logger.warn({ url, err: errMsg }, 'Lighthouse audit failed for URL');\r\n logToFile?.('warn', ` Lighthouse failed for ${url}: ${errMsg}`);\r\n pageLoads.push({\r\n url,\r\n stepIndex: idx,\r\n stepInstruction: s.instruction,\r\n lighthouseError: errMsg,\r\n });\r\n } finally {\r\n // Always kill the dedicated Chrome instance and clean up its profile dir.\r\n // Wrap in try/catch so a cleanup failure never overwrites the audit result.\r\n try { await chromeInstance?.kill(); } catch { /* ignore */ }\r\n try { await fs.remove(userDataDir); } catch { /* ignore */ }\r\n }\r\n }\r\n } catch (lhErr) {\r\n const errMsg = lhErr instanceof Error ? lhErr.message : String(lhErr);\r\n logger.warn({ err: errMsg }, 'Lighthouse import/init failed');\r\n logToFile?.('warn', ` Lighthouse init failed: ${errMsg}`);\r\n // Only add fallback entries for steps NOT already recorded (avoids duplicates\r\n // when some URLs succeeded before an outer-level error occurred).\r\n const recordedIndices = new Set(pageLoads.map((p) => p.stepIndex));\r\n for (const { s, idx } of navigatedSteps) {\r\n if (!recordedIndices.has(idx)) {\r\n pageLoads.push({\r\n url: (s.auditUrl ?? s.navigatedToUrl) as string,\r\n stepIndex: idx,\r\n stepInstruction: s.instruction,\r\n lighthouseError: `Lighthouse unavailable: ${errMsg}`,\r\n });\r\n }\r\n }\r\n }\r\n logToFile?.('info', '------------------------------------');\r\n }\r\n // Fail the case if any Lighthouse score is in the \"Poor\" zone (< 50)\r\n // Only applies to audit/performance suites, not standard UI suites\r\n if (isSuiteAudit(suite) && pageLoads.length > 0 && caseStatus === 'passed') {\r\n const SCORE_FAIL = 50;\r\n const hasPoorScore = pageLoads.some((p) =>\r\n !p.lighthouseError && (\r\n (p.score != null && p.score < SCORE_FAIL) ||\r\n (p.a11yScore != null && p.a11yScore < SCORE_FAIL) ||\r\n (p.seoScore != null && p.seoScore < SCORE_FAIL)\r\n ),\r\n );\r\n if (hasPoorScore) {\r\n caseStatus = 'failed';\r\n logToFile?.('warn', ' Case FAILED: one or more Lighthouse scores below 50 (Poor threshold)');\r\n }\r\n }\r\n\r\n } else if (!apiOnly && browserName !== 'chromium') {\r\n // Non-chromium: basic navigation tracking without Lighthouse\r\n pageLoads = stepResults\r\n .map((s, idx) => ({ s, idx }))\r\n .filter(({ s }) => !!s.navigatedToUrl)\r\n .map(({ s, idx }) => ({\r\n url: s.navigatedToUrl as string,\r\n stepIndex: idx,\r\n stepInstruction: s.instruction,\r\n lighthouseError: 'Lighthouse only available for Chromium',\r\n }));\r\n }\r\n\r\n // ── After hooks ─────────────────────────────────────────────────────────\r\n for (const hookStep of testCase.caseHooks?.after ?? []) {\r\n await execHookStep(hookStep);\r\n }\r\n\r\n // Capture video path before closing the context\r\n if (!apiOnly) {\r\n pendingVideoPath = await page.video()?.path().catch(() => undefined);\r\n }\r\n } finally {\r\n if (apiOnly) {\r\n // API-only: no browser context to close — API contexts cleaned up in closeAll()\r\n } else if (context) {\r\n await browserManager.closeContext(context, caseConfig, tracePath);\r\n\r\n // Video retain-on-failure: record always, delete if test passed\r\n const videoDeleteOnPass =\r\n caseConfig.video === 'retain-on-failure' || caseConfig.video === 'on-first-retry';\r\n if (videoDeleteOnPass && caseStatus === 'passed' && pendingVideoPath) {\r\n await fs.remove(pendingVideoPath).catch(() => undefined);\r\n }\r\n\r\n // Trace retain-on-failure: record always, delete if test passed\r\n const traceDeleteOnPass =\r\n caseConfig.trace === 'retain-on-failure' || caseConfig.trace === 'on-first-retry';\r\n if (traceDeleteOnPass && caseStatus === 'passed' && tracePath) {\r\n await fs.remove(tracePath).catch(() => undefined);\r\n }\r\n }\r\n }\r\n\r\n // Resolve final paths (API-only cases never have video/trace)\r\n let finalVideoPath: string | undefined;\r\n let finalTracePath: string | undefined;\r\n\r\n if (!apiOnly) {\r\n const videoDeleteOnPass =\r\n caseConfig.video === 'retain-on-failure' || caseConfig.video === 'on-first-retry';\r\n finalVideoPath =\r\n caseConfig.video !== 'off' && pendingVideoPath\r\n ? videoDeleteOnPass && caseStatus === 'passed'\r\n ? undefined\r\n : pendingVideoPath\r\n : undefined;\r\n\r\n const traceDeleteOnPass =\r\n caseConfig.trace === 'retain-on-failure' || caseConfig.trace === 'on-first-retry';\r\n finalTracePath =\r\n caseConfig.trace === 'off'\r\n ? undefined\r\n : traceDeleteOnPass && caseStatus === 'passed'\r\n ? undefined\r\n : tracePath;\r\n }\r\n\r\n const caseFinished = new Date().toISOString();\r\n const caseDuration =\r\n new Date(caseFinished).getTime() - new Date(caseStart).getTime();\r\n\r\n return {\r\n suiteId: suite.id,\r\n suiteName: suite.name,\r\n caseResult: {\r\n caseId: testCase.id,\r\n caseName: testCase.name,\r\n status: caseStatus,\r\n steps: stepResults,\r\n duration: caseDuration,\r\n browser: browserName,\r\n device: config.device || undefined,\r\n startedAt: caseStart,\r\n finishedAt: caseFinished,\r\n videoPath: finalVideoPath,\r\n tracePath: finalTracePath,\r\n pageLoads,\r\n },\r\n };\r\n}\r\n\r\n// ─── Work collection ─────────────────────────────────────────────────────────\r\n\r\ninterface WorkPair {\r\n suite: TestSuite;\r\n testCase: TestCase;\r\n}\r\n\r\nasync function collectWork(testsDir: string, runConfig: RunConfig): Promise<WorkPair[]> {\r\n const suites = await listSuites(testsDir);\r\n const pairs: WorkPair[] = [];\r\n\r\n for (const suite of suites) {\r\n // Filter by suite type (--type flag)\r\n if (runConfig.type && suite.type !== runConfig.type) continue;\r\n\r\n // Filter suites — accept either name or id so UI can pass either\r\n // Case-insensitive partial match for name\r\n if (runConfig.suite) {\r\n const q = runConfig.suite.toLowerCase();\r\n const nameMatch = suite.name.toLowerCase().includes(q);\r\n const idMatch = suite.id === runConfig.suite;\r\n if (!nameMatch && !idMatch) continue;\r\n }\r\n\r\n // Resolve the actual suite directory (slug-based, not UUID-based)\r\n const suiteDir = await findSuiteDirById(testsDir, suite.id);\r\n if (!suiteDir) {\r\n logger.warn({ suiteId: suite.id }, 'Suite directory not found — skipping');\r\n continue;\r\n }\r\n\r\n const cases = await listCases(suiteDir);\r\n\r\n for (const tc of cases) {\r\n // Filter by test name — case-insensitive partial match, or exact id match\r\n if (runConfig.test) {\r\n const q = runConfig.test.toLowerCase();\r\n const nameMatch = tc.name.toLowerCase().includes(q);\r\n const idMatch = tc.id === runConfig.test;\r\n if (!nameMatch && !idMatch) continue;\r\n }\r\n // Filter by tag\r\n if (runConfig.tag && !tc.tags.includes(runConfig.tag)) continue;\r\n // If no specific filter matches, skip (require at least one selector)\r\n if (!runConfig.all && !runConfig.type && !runConfig.suite && !runConfig.test && !runConfig.tag) continue;\r\n\r\n pairs.push({ suite, testCase: tc });\r\n }\r\n }\r\n\r\n return pairs;\r\n}\r\n\r\n// ─── Variable loading ─────────────────────────────────────────────────────────\r\n\r\nasync function loadVariables(rootDir: string, env?: string): Promise<Record<string, string>> {\r\n try {\r\n const resolved = await resolveVariables(rootDir, env ?? 'dev');\r\n const count = Object.keys(resolved).length;\r\n logger.info({ count, env: env ?? 'dev', rootDir }, 'Variables loaded');\r\n return resolved;\r\n } catch (err) {\r\n logger.warn({ err: err instanceof Error ? err.message : String(err) }, 'Failed to load variables — running without variable substitution');\r\n return {};\r\n }\r\n}\r\n\r\n// ─── Concurrency ─────────────────────────────────────────────────────────────\r\n\r\nasync function runWithConcurrency<T, R>(\r\n items: T[],\r\n limit: number,\r\n fn: (item: T) => Promise<R>,\r\n): Promise<R[]> {\r\n const results: R[] = [];\r\n const queue = [...items];\r\n\r\n async function worker(): Promise<void> {\r\n while (queue.length > 0) {\r\n const item = queue.shift();\r\n if (item !== undefined) {\r\n results.push(await fn(item));\r\n }\r\n }\r\n }\r\n\r\n const workers = Array.from({ length: Math.min(limit, items.length || 1) }, () => worker());\r\n await Promise.all(workers);\r\n return results;\r\n}\r\n\r\n// ─── Result builders ──────────────────────────────────────────────────────────\r\n\r\nfunction groupBySuite(\r\n caseRuns: CaseRunResult[],\r\n browserSuffix?: string,\r\n): SuiteResult[] {\r\n const suiteMap = new Map<string, CaseRunResult[]>();\r\n\r\n for (const run of caseRuns) {\r\n const key = run.suiteId;\r\n const list = suiteMap.get(key) ?? [];\r\n list.push(run);\r\n suiteMap.set(key, list);\r\n }\r\n\r\n const results: SuiteResult[] = [];\r\n\r\n for (const [suiteId, runs] of suiteMap) {\r\n const first = runs[0];\r\n if (!first) continue;\r\n\r\n const allCases = runs.map((r) => r.caseResult);\r\n const suiteStatus = allCases.some((c) => c.status === 'failed') ? 'failed' : 'passed';\r\n const startedAt = allCases[0]?.startedAt ?? new Date().toISOString();\r\n const finishedAt = allCases[allCases.length - 1]?.finishedAt ?? new Date().toISOString();\r\n const duration = new Date(finishedAt).getTime() - new Date(startedAt).getTime();\r\n\r\n results.push({\r\n suiteId,\r\n suiteName: browserSuffix\r\n ? `${first.suiteName} [${browserSuffix}]`\r\n : first.suiteName,\r\n suiteType: first.suiteType as SuiteResult['suiteType'],\r\n status: suiteStatus,\r\n cases: allCases,\r\n duration,\r\n browser: allCases[0]?.browser ?? 'chromium',\r\n startedAt,\r\n finishedAt,\r\n });\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction buildRunResult(\r\n runId: string,\r\n startedAt: string,\r\n finishedAt: string,\r\n suites: SuiteResult[],\r\n environment?: string,\r\n): RunResult {\r\n const allCases = suites.flatMap((s) => s.cases);\r\n const passed = allCases.filter((c) => c.status === 'passed').length;\r\n const failed = allCases.filter((c) => c.status === 'failed').length;\r\n const skipped = allCases.filter((c) => c.status === 'skipped').length;\r\n const total = allCases.length;\r\n const duration = new Date(finishedAt).getTime() - new Date(startedAt).getTime();\r\n\r\n return {\r\n runId,\r\n status: failed > 0 ? 'failed' : 'passed',\r\n environment,\r\n suites,\r\n duration,\r\n startedAt,\r\n finishedAt,\r\n totalTests: total,\r\n passed,\r\n failed,\r\n skipped,\r\n };\r\n}\r\n","/**\r\n * Run routes — start test runs and retrieve results.\r\n *\r\n * POST /api/run — start a new test run\r\n * GET /api/run — list recent run results (metadata)\r\n * GET /api/run/:runId — get full run result by id\r\n */\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { runTests } from '../../engine/runner.js';\r\nimport { readConfig } from '../../storage/config-store.js';\r\nimport { listResults, readResult } from '../../storage/result-store.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('routes/run');\r\n\r\nconst ScreenshotMode = z.enum(['off', 'on', 'only-on-failure']);\r\nconst VideoMode = z.enum(['off', 'on', 'on-first-retry', 'retain-on-failure']);\r\nconst TraceMode = z.enum(['off', 'on', 'on-first-retry', 'retain-on-failure']);\r\n\r\nconst StartRunBody = z.object({\r\n all: z.boolean().optional(),\r\n suite: z.string().optional(),\r\n tag: z.string().optional(),\r\n test: z.string().optional(),\r\n browsers: z.array(z.string()).optional(),\r\n env: z.string().optional(),\r\n parallel: z.number().int().positive().optional(),\r\n headed: z.boolean().optional(),\r\n ci: z.boolean().optional(),\r\n reporter: z.array(z.string()).optional(),\r\n noHealing: z.boolean().optional(),\r\n screenshot: ScreenshotMode.optional(),\r\n video: VideoMode.optional(),\r\n trace: TraceMode.optional(),\r\n device: z.string().optional(),\r\n});\r\n\r\nconst ListRunsQuery = z.object({\r\n limit: z.coerce.number().int().positive().max(100).default(20),\r\n});\r\n\r\nexport async function runRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n\r\n // POST /api/run\r\n fastify.post('/run', async (req, reply) => {\r\n const parsed = StartRunBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid run config', details: parsed.error.issues });\r\n }\r\n\r\n try {\r\n const baseConfig = await readConfig(rootDir);\r\n const runConfig = parsed.data;\r\n\r\n // Apply per-run overrides from the UI onto the base autotest config\r\n const autotestConfig = {\r\n ...baseConfig,\r\n // Studio (local server) defaults to headed (shows browser).\r\n // User can override via the headed toggle. CI mode overrides below.\r\n headless: runConfig.headed !== undefined ? !runConfig.headed : false,\r\n // browsers/parallel from run config take precedence when provided\r\n browsers: runConfig.browsers?.length ? runConfig.browsers : baseConfig.browsers,\r\n parallel: runConfig.parallel ?? baseConfig.parallel,\r\n // per-run capture overrides\r\n screenshot: runConfig.screenshot ?? baseConfig.screenshot,\r\n video: runConfig.video ?? baseConfig.video,\r\n trace: runConfig.trace ?? baseConfig.trace,\r\n // Device emulation (undefined = no emulation / use configured viewport)\r\n device: runConfig.device ?? baseConfig.device,\r\n // CI mode forces headless regardless of headed toggle\r\n ...(runConfig.ci ? { headless: true } : {}),\r\n };\r\n\r\n // Start the run asynchronously and broadcast progress via WebSocket\r\n const wsManager = fastify.wsManager;\r\n\r\n // Run is async — kick it off and return the runId immediately\r\n const startedAt = new Date().toISOString();\r\n logger.info({ runConfig }, 'Run requested via API');\r\n\r\n // Fire-and-forget with progress broadcasting\r\n runTests(rootDir, runConfig, autotestConfig, wsManager)\r\n .then((result) => {\r\n wsManager.broadcast('run:complete', {\r\n runId: result.runId,\r\n passed: result.passed,\r\n failed: result.failed,\r\n skipped: result.skipped,\r\n duration: result.duration,\r\n });\r\n logger.info({ runId: result.runId, status: result.status }, 'API-triggered run complete');\r\n })\r\n .catch((err) => {\r\n logger.error({ err }, 'API-triggered run failed');\r\n wsManager.broadcast('run:error', {\r\n error: err instanceof Error ? err.message : String(err),\r\n });\r\n });\r\n\r\n return reply.status(202).send({ status: 'accepted', startedAt, message: 'Run started — subscribe to WebSocket for progress' });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to start run', err);\r\n }\r\n });\r\n\r\n // GET /api/run\r\n fastify.get('/run', async (req, reply) => {\r\n const parsed = ListRunsQuery.safeParse(req.query);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid query', details: parsed.error.issues });\r\n }\r\n try {\r\n const results = await listResults(rootDir, parsed.data.limit);\r\n return reply.send(results);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to list run results', err);\r\n }\r\n });\r\n\r\n // GET /api/run/:runId\r\n fastify.get<{ Params: { runId: string } }>('/run/:runId', async (req, reply) => {\r\n try {\r\n const result = await readResult(rootDir, req.params.runId);\r\n return reply.send(result);\r\n } catch {\r\n return reply.status(404).send({ error: `Run \"${req.params.runId}\" not found` });\r\n }\r\n });\r\n}\r\n","/**\n * Swagger/OpenAPI Parser — fetches and parses an OpenAPI spec to extract endpoints.\n * Supports both JSON and YAML specs.\n */\nimport yaml from 'js-yaml';\nimport { createChildLogger } from '../utils/logger.js';\n\nconst logger = createChildLogger('swagger-parser');\n\nexport interface ParsedEndpoint {\n method: string;\n path: string;\n summary: string;\n tag: string;\n parameters: Array<{ name: string; in: string; required: boolean; type: string }>;\n requestBody?: { contentType: string; schema: Record<string, unknown>; example?: Record<string, unknown> };\n responses: Array<{ status: number; description: string }>;\n}\n\nexport interface ParsedApiSpec {\n title: string;\n baseUrl: string;\n endpoints: ParsedEndpoint[];\n}\n\nexport async function parseSwaggerSpec(urlOrJson: string): Promise<ParsedApiSpec> {\n let spec: Record<string, unknown>;\n\n // Determine if input is a URL or raw JSON\n if (urlOrJson.startsWith('http://') || urlOrJson.startsWith('https://')) {\n // Try fetching the spec as JSON\n let url = urlOrJson;\n // Strip Swagger UI fragment (e.g., #tag/...)\n if (url.includes('#')) url = url.split('#')[0];\n // Strip trailing slash\n const base = url.replace(/\\/$/, '');\n\n // Try many common spec paths — OpenAPI specs live at various locations\n const urls = [\n url,\n `${url}.json`,\n `${base}/swagger.json`,\n `${base}/openapi.json`,\n `${base}/openapi.yaml`,\n `${base}/openapi.yml`,\n `${base}/swagger.yaml`,\n `${base}/api-docs`,\n `${base}/api-docs.json`,\n `${base}/v2/swagger.json`,\n `${base}/v2/openapi.yaml`,\n `${base}/v2/openapi.json`,\n `${base}/v3/api-docs`,\n `${base}/v3/openapi.yaml`,\n // If URL ends with a path segment, try going up one level\n base.replace(/\\/[^/]+$/, '') + '/swagger.json',\n base.replace(/\\/[^/]+$/, '') + '/openapi.json',\n base.replace(/\\/[^/]+$/, '') + '/openapi.yaml',\n base.replace(/\\/[^/]+$/, '') + '/openapi.yml',\n // Go up two levels (e.g. /v2/api-docs → /v2/openapi.yaml)\n base.replace(/\\/[^/]+\\/[^/]+$/, '') + '/openapi.yaml',\n base.replace(/\\/[^/]+\\/[^/]+$/, '') + '/swagger.json',\n ];\n // Try to extract spec URL from HTML page first (Redoc, SwaggerUI, Redocly, etc.)\n try {\n const pageRes = await fetch(url, {\n headers: { Accept: 'text/html, */*' },\n signal: AbortSignal.timeout(10000),\n });\n if (pageRes.ok) {\n const html = await pageRes.text();\n if (html.includes('<!') || html.includes('<html')) {\n // Extract spec URLs from common patterns\n const specPatterns = [\n /Redoc\\.init\\(\\s*['\"]([^'\"]+)['\"]/, // Redoc.init('/path/to/spec')\n /spec-url=['\"]([^'\"]+)['\"]/i, // spec-url=\"/path\"\n /url:\\s*['\"]([^'\"]+\\.(?:json|yaml|yml))['\"]/, // url: '/spec.json'\n /specUrl:\\s*['\"]([^'\"]+)['\"]/, // specUrl: '...'\n /[\"']([^\"']*(?:openapi|swagger)[^\"']*\\.(?:json|yaml|yml))[\"']/i, // any openapi/swagger file ref\n /href=['\"]([^'\"]*\\.(?:json|yaml|yml))['\"][^>]*>.*?(?:openapi|swagger|spec|api-doc)/i,\n ];\n for (const pattern of specPatterns) {\n const match = html.match(pattern);\n if (match?.[1]) {\n let specUrl = match[1];\n // Resolve relative URLs\n if (specUrl.startsWith('/')) {\n const origin = new URL(url).origin;\n specUrl = `${origin}${specUrl}`;\n } else if (!specUrl.startsWith('http')) {\n specUrl = new URL(specUrl, url).href;\n }\n // Add to front of URL list (highest priority)\n urls.unshift(specUrl);\n logger.info({ specUrl, pattern: pattern.source }, 'Extracted spec URL from HTML page');\n }\n }\n }\n }\n } catch { /* ignore HTML fetch errors */ }\n\n // Deduplicate\n const uniqueUrls = [...new Set(urls)];\n\n let fetched = false;\n const errors: string[] = [];\n for (const tryUrl of uniqueUrls) {\n try {\n logger.debug({ tryUrl }, 'Trying to fetch OpenAPI spec');\n const res = await fetch(tryUrl, {\n headers: { Accept: 'application/json, application/yaml, */*' },\n signal: AbortSignal.timeout(15000),\n });\n if (res.ok) {\n const contentType = res.headers.get('content-type') ?? '';\n const text = await res.text();\n const isJson = contentType.includes('json') || text.trimStart().startsWith('{') || text.trimStart().startsWith('[');\n const isYaml = contentType.includes('yaml') || contentType.includes('yml') || tryUrl.endsWith('.yaml') || tryUrl.endsWith('.yml');\n\n if (isJson || isYaml) {\n try {\n spec = isJson\n ? JSON.parse(text) as Record<string, unknown>\n : yaml.load(text) as Record<string, unknown>;\n // Verify it looks like an OpenAPI/Swagger spec\n if (spec && (spec.openapi || spec.swagger || spec.paths)) {\n fetched = true;\n logger.info({ tryUrl, format: isYaml ? 'YAML' : 'JSON' }, 'Successfully fetched OpenAPI spec');\n break;\n }\n errors.push(`${tryUrl}: Parsed but not a valid OpenAPI spec`);\n } catch {\n errors.push(`${tryUrl}: Response is not valid ${isYaml ? 'YAML' : 'JSON'}`);\n }\n } else {\n // Last attempt — try YAML parse on any non-HTML text (some servers serve YAML as text/plain)\n if (!contentType.includes('html') && !text.trimStart().startsWith('<!')) {\n try {\n const parsed = yaml.load(text) as Record<string, unknown>;\n if (parsed && typeof parsed === 'object' && (parsed.openapi || parsed.swagger || parsed.paths)) {\n spec = parsed;\n fetched = true;\n logger.info({ tryUrl, format: 'YAML (text/plain)' }, 'Successfully fetched OpenAPI spec');\n break;\n }\n } catch { /* not YAML either */ }\n }\n errors.push(`${tryUrl}: Response is HTML/text, not JSON or YAML (content-type: ${contentType})`);\n }\n } else {\n errors.push(`${tryUrl}: HTTP ${res.status}`);\n }\n } catch (err) {\n errors.push(`${tryUrl}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n if (!fetched) {\n throw new Error(\n `Could not auto-discover the OpenAPI spec from this URL.\\n` +\n `This may be a developer portal that loads the spec dynamically.\\n\\n` +\n `Try one of these instead:\\n` +\n ` 1. Open the page in browser → DevTools → Network → filter \"json\" or \"yaml\" → find the spec request → copy that URL\\n` +\n ` 2. Use the direct API server URL (e.g. https://api.example.com/v2/api-docs)\\n` +\n ` 3. Ask your API team for the raw spec file URL\\n\\n` +\n `Details:\\n${errors.map((e) => ` • ${e}`).join('\\n')}`,\n );\n }\n } else {\n // Try JSON first, then YAML\n try {\n spec = JSON.parse(urlOrJson) as Record<string, unknown>;\n } catch {\n spec = yaml.load(urlOrJson) as Record<string, unknown>;\n }\n }\n\n return parseSpec(spec!);\n}\n\nfunction parseSpec(spec: Record<string, unknown>): ParsedApiSpec {\n const info = (spec.info as Record<string, string>) ?? {};\n const title = info.title ?? 'API';\n\n // Extract base URL\n let baseUrl = '';\n if (spec.servers && Array.isArray(spec.servers) && spec.servers.length > 0) {\n baseUrl = (spec.servers[0] as Record<string, string>).url ?? '';\n } else if (spec.host) {\n const scheme = (spec.schemes as string[])?.[0] ?? 'https';\n baseUrl = `${scheme}://${spec.host}${spec.basePath ?? ''}`;\n }\n\n const paths = (spec.paths as Record<string, Record<string, unknown>>) ?? {};\n const endpoints: ParsedEndpoint[] = [];\n\n for (const [pathStr, methods] of Object.entries(paths)) {\n for (const [method, details] of Object.entries(methods)) {\n if (['get', 'post', 'put', 'delete', 'patch'].indexOf(method) === -1) continue;\n const op = details as Record<string, unknown>;\n\n const tags = (op.tags as string[]) ?? ['Default'];\n const summary = (op.summary as string) ?? (op.operationId as string) ?? `${method.toUpperCase()} ${pathStr}`;\n\n // Parameters\n const params = ((op.parameters as Array<Record<string, unknown>>) ?? []).map((p) => ({\n name: p.name as string,\n in: p.in as string,\n required: (p.required as boolean) ?? false,\n type: ((p.schema as Record<string, string>)?.type ?? p.type ?? 'string') as string,\n }));\n\n // Request body\n let requestBody: ParsedEndpoint['requestBody'];\n if (op.requestBody) {\n const rb = op.requestBody as Record<string, unknown>;\n const content = rb.content as Record<string, Record<string, unknown>>;\n if (content) {\n const firstType = Object.keys(content)[0];\n const schema = (content[firstType]?.schema as Record<string, unknown>) ?? {};\n const example = (content[firstType]?.example ?? schema.example) as Record<string, unknown> | undefined;\n requestBody = { contentType: firstType, schema, example };\n }\n }\n\n // Responses\n const respObj = (op.responses as Record<string, Record<string, unknown>>) ?? {};\n const responses = Object.entries(respObj).map(([status, resp]) => ({\n status: parseInt(status, 10) || 0,\n description: (resp.description as string) ?? '',\n }));\n\n endpoints.push({\n method: method.toUpperCase(),\n path: pathStr,\n summary,\n tag: tags[0],\n parameters: params,\n requestBody,\n responses,\n });\n }\n }\n\n logger.info({ title, endpointCount: endpoints.length }, 'Parsed OpenAPI spec');\n return { title, baseUrl, endpoints };\n}\n","/**\r\n * Story routes — generate a test suite from a plain-English user story.\r\n *\r\n * POST /api/story/generate — generate suite + cases from story text\r\n * POST /api/story/generate-bulk — bulk generation with WebSocket progress\r\n * POST /api/story/fetch-jira — fetch a Jira issue and return structured content\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { generateSuiteFromStory, generateSuitesFromStories } from '../../ai/router.js';\r\nimport { parseSwaggerSpec } from '../../ai/swagger-parser.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('routes/story');\r\n\r\n// ─── Jira URL parsing ──────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Extract a Jira issue key from various URL formats:\r\n * https://domain.atlassian.net/browse/PROJ-123\r\n * https://domain.atlassian.net/jira/software/projects/PROJ/boards/1?selectedIssue=PROJ-123\r\n * PROJ-123 (bare key)\r\n */\r\nfunction extractIssueKey(input: string): string | null {\r\n const trimmed = input.trim();\r\n\r\n // Bare key: PROJ-123\r\n if (/^[A-Z][A-Z0-9_]+-\\d+$/i.test(trimmed)) {\r\n return trimmed.toUpperCase();\r\n }\r\n\r\n try {\r\n const url = new URL(trimmed);\r\n\r\n // /browse/PROJ-123\r\n const browseMatch = url.pathname.match(/\\/browse\\/([A-Z][A-Z0-9_]+-\\d+)/i);\r\n if (browseMatch) return browseMatch[1].toUpperCase();\r\n\r\n // selectedIssue=PROJ-123 (board views)\r\n const selectedIssue = url.searchParams.get('selectedIssue');\r\n if (selectedIssue && /^[A-Z][A-Z0-9_]+-\\d+$/i.test(selectedIssue)) {\r\n return selectedIssue.toUpperCase();\r\n }\r\n\r\n // /issue/PROJ-123\r\n const issueMatch = url.pathname.match(/\\/issue\\/([A-Z][A-Z0-9_]+-\\d+)/i);\r\n if (issueMatch) return issueMatch[1].toUpperCase();\r\n } catch {\r\n // Not a valid URL — try regex on the raw string\r\n const match = trimmed.match(/([A-Z][A-Z0-9_]+-\\d+)/i);\r\n if (match) return match[1].toUpperCase();\r\n }\r\n\r\n return null;\r\n}\r\n\r\n// ─── Jira issue fetcher ─────────────────────────────────────────────────────────\r\n\r\ninterface JiraStoryContent {\r\n issueKey: string;\r\n summary: string;\r\n description: string;\r\n acceptanceCriteria: string;\r\n comments: string[];\r\n issueType: string;\r\n status: string;\r\n priority: string;\r\n labels: string[];\r\n}\r\n\r\n/** Read Jira credentials from env. Returns null when not configured. */\r\nfunction getJiraConfig() {\r\n const baseUrl = process.env['JIRA_BASE_URL'];\r\n const email = process.env['JIRA_EMAIL'];\r\n const apiToken = process.env['JIRA_API_TOKEN'];\r\n if (!baseUrl || !email || !apiToken) return null;\r\n return { baseUrl: baseUrl.replace(/\\/+$/, ''), email, apiToken };\r\n}\r\n\r\n/**\r\n * Convert Atlassian Document Format (ADF) node tree to plain text.\r\n * ADF is what Jira Cloud uses for rich text fields.\r\n */\r\nfunction adfToText(node: unknown): string {\r\n if (!node || typeof node !== 'object') return '';\r\n const n = node as Record<string, unknown>;\r\n\r\n // Leaf text node\r\n if (n['type'] === 'text' && typeof n['text'] === 'string') {\r\n return n['text'] as string;\r\n }\r\n\r\n // Recursively process children\r\n if (Array.isArray(n['content'])) {\r\n const parts: string[] = (n['content'] as unknown[]).map((child) => adfToText(child));\r\n const blockTypes = new Set(['paragraph', 'heading', 'bulletList', 'orderedList', 'listItem', 'blockquote', 'codeBlock', 'rule']);\r\n if (typeof n['type'] === 'string' && blockTypes.has(n['type'])) {\r\n return parts.join('') + '\\n';\r\n }\r\n return parts.join('');\r\n }\r\n\r\n return '';\r\n}\r\n\r\n/** Fetch a Jira issue by key and extract structured content. */\r\nasync function fetchJiraIssue(issueKey: string): Promise<JiraStoryContent> {\r\n const config = getJiraConfig();\r\n if (!config) {\r\n throw new Error('Jira not configured — set JIRA_BASE_URL, JIRA_EMAIL, and JIRA_API_TOKEN in your .env file.');\r\n }\r\n\r\n const authHeader = 'Basic ' + Buffer.from(`${config.email}:${config.apiToken}`).toString('base64');\r\n const url = `${config.baseUrl}/rest/api/3/issue/${encodeURIComponent(issueKey)}?fields=summary,description,comment,issuetype,status,priority,labels,customfield_10020`;\r\n\r\n logger.info({ issueKey, url: url.replace(/\\/rest.*/, '/...') }, 'Fetching Jira issue');\r\n\r\n const res = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'Authorization': authHeader,\r\n 'Accept': 'application/json',\r\n },\r\n });\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n throw new Error(`Jira authentication failed (${res.status}). Check JIRA_EMAIL and JIRA_API_TOKEN in your .env file.`);\r\n }\r\n if (res.status === 404) {\r\n throw new Error(`Jira issue \"${issueKey}\" not found. Verify the issue key and that your account has access.`);\r\n }\r\n if (res.status === 429) {\r\n throw new Error('Jira API rate limit exceeded. Please try again in a few seconds.');\r\n }\r\n if (!res.ok) {\r\n const text = await res.text().catch(() => 'Unknown error');\r\n throw new Error(`Jira API returned ${res.status}: ${text}`);\r\n }\r\n\r\n const data = await res.json() as Record<string, unknown>;\r\n const fields = (data['fields'] ?? {}) as Record<string, unknown>;\r\n\r\n // Parse description (ADF or plain string)\r\n let description = '';\r\n if (typeof fields['description'] === 'string') {\r\n description = fields['description'];\r\n } else if (fields['description'] && typeof fields['description'] === 'object') {\r\n description = adfToText(fields['description']).trim();\r\n }\r\n\r\n // Extract acceptance criteria — commonly in description section or a custom field\r\n let acceptanceCriteria = '';\r\n // Check common custom field names for AC\r\n const acField = fields['customfield_10020'];\r\n if (typeof acField === 'string') {\r\n acceptanceCriteria = acField;\r\n } else if (acField && typeof acField === 'object') {\r\n acceptanceCriteria = adfToText(acField).trim();\r\n }\r\n // Also try to extract AC section from description\r\n if (!acceptanceCriteria && description) {\r\n const acMatch = description.match(/(?:acceptance\\s+criteria|AC|given\\s*\\/?\\s*when\\s*\\/?\\s*then)[:\\s]*\\n?([\\s\\S]*?)(?:\\n\\n|\\n(?=[A-Z])|\\n(?=#{1,3}\\s)|$)/i);\r\n if (acMatch) {\r\n acceptanceCriteria = acMatch[1].trim();\r\n }\r\n }\r\n\r\n // Parse comments\r\n const comments: string[] = [];\r\n const commentBlock = fields['comment'] as Record<string, unknown> | undefined;\r\n if (commentBlock && Array.isArray(commentBlock['comments'])) {\r\n for (const c of (commentBlock['comments'] as Array<Record<string, unknown>>).slice(-5)) {\r\n const body = c['body'];\r\n const text = typeof body === 'string' ? body : (body ? adfToText(body).trim() : '');\r\n if (text) comments.push(text);\r\n }\r\n }\r\n\r\n return {\r\n issueKey: String(data['key'] ?? issueKey),\r\n summary: String(fields['summary'] ?? ''),\r\n description,\r\n acceptanceCriteria,\r\n comments,\r\n issueType: (fields['issuetype'] as Record<string, unknown>)?.['name'] as string ?? 'Unknown',\r\n status: (fields['status'] as Record<string, unknown>)?.['name'] as string ?? 'Unknown',\r\n priority: (fields['priority'] as Record<string, unknown>)?.['name'] as string ?? 'Medium',\r\n labels: Array.isArray(fields['labels']) ? (fields['labels'] as string[]) : [],\r\n };\r\n}\r\n\r\n/** Merge Jira content with optional user story text into a rich prompt. */\r\nfunction buildEnrichedStory(jira: JiraStoryContent, userStory?: string): string {\r\n const parts: string[] = [];\r\n\r\n parts.push(`## Jira Issue: ${jira.issueKey}`);\r\n parts.push(`**Summary:** ${jira.summary}`);\r\n parts.push(`**Type:** ${jira.issueType} | **Status:** ${jira.status} | **Priority:** ${jira.priority}`);\r\n\r\n if (jira.labels.length > 0) {\r\n parts.push(`**Labels:** ${jira.labels.join(', ')}`);\r\n }\r\n\r\n if (jira.description) {\r\n parts.push(`\\n### Description\\n${jira.description}`);\r\n }\r\n\r\n if (jira.acceptanceCriteria) {\r\n parts.push(`\\n### Acceptance Criteria\\n${jira.acceptanceCriteria}`);\r\n }\r\n\r\n if (jira.comments.length > 0) {\r\n parts.push(`\\n### Relevant Comments`);\r\n jira.comments.forEach((c, i) => parts.push(`${i + 1}. ${c}`));\r\n }\r\n\r\n if (userStory && userStory.trim()) {\r\n parts.push(`\\n### Additional Context (User Input)\\n${userStory.trim()}`);\r\n }\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\n// ─── Route schemas ──────────────────────────────────────────────────────────────\r\n\r\nconst GenerateStoryBody = z.object({\r\n story: z.string().default(''),\r\n suiteName: z.string().min(1).optional(),\r\n jiraUrl: z.string().optional(),\r\n}).refine(\r\n (data) => data.story.length >= 10 || (!!data.jiraUrl && data.jiraUrl.trim().length > 0),\r\n { message: 'Provide a user story (≥ 10 chars) or a Jira link', path: ['story'] },\r\n);\r\n\r\nconst FetchJiraBody = z.object({\r\n jiraUrl: z.string().min(1, 'Jira URL is required'),\r\n});\r\n\r\n// ─── Routes ─────────────────────────────────────────────────────────────────────\r\n\r\nexport async function storyRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n\r\n // POST /api/story/fetch-jira — fetch Jira issue and return structured content\r\n fastify.post('/story/fetch-jira', async (req, reply) => {\r\n const parsed = FetchJiraBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n\r\n const issueKey = extractIssueKey(parsed.data.jiraUrl);\r\n if (!issueKey) {\r\n return reply.status(400).send({\r\n error: 'Invalid Jira URL',\r\n details: 'Could not extract an issue key. Expected format: https://domain.atlassian.net/browse/PROJ-123 or PROJ-123',\r\n });\r\n }\r\n\r\n try {\r\n const content = await fetchJiraIssue(issueKey);\r\n return reply.status(200).send(content);\r\n } catch (err) {\r\n const status = (err instanceof Error && err.message.includes('not configured')) ? 400\r\n : (err instanceof Error && (err.message.includes('401') || err.message.includes('403'))) ? 401\r\n : (err instanceof Error && err.message.includes('not found')) ? 404\r\n : (err instanceof Error && err.message.includes('rate limit')) ? 429\r\n : 500;\r\n return sendError(reply, status, 'Failed to fetch Jira issue', err);\r\n }\r\n });\r\n\r\n // POST /api/story/generate — generate suite + cases from story text (optionally enriched with Jira)\r\n fastify.post('/story/generate', async (req, reply) => {\r\n const parsed = GenerateStoryBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n\r\n try {\r\n const testsDir = path.join(rootDir, 'tests');\r\n let storyText = parsed.data.story;\r\n\r\n // If a Jira URL was provided, fetch and enrich the story\r\n if (parsed.data.jiraUrl) {\r\n const issueKey = extractIssueKey(parsed.data.jiraUrl);\r\n if (issueKey) {\r\n try {\r\n const jiraContent = await fetchJiraIssue(issueKey);\r\n storyText = buildEnrichedStory(jiraContent, parsed.data.story || undefined);\r\n logger.info({ issueKey }, 'Enriched story with Jira content');\r\n } catch (jiraErr) {\r\n // If user provided no manual story and Jira fetch failed, we can't proceed\r\n if (!storyText || storyText.length < 10) {\r\n return sendError(reply, 400, 'Jira fetch failed and no user story provided', jiraErr);\r\n }\r\n logger.warn({ err: jiraErr }, 'Failed to fetch Jira issue — proceeding with user story only');\r\n }\r\n }\r\n }\r\n\r\n // Final guard: ensure we have enough text to generate from\r\n if (!storyText || storyText.length < 10) {\r\n return reply.status(400).send({ error: 'Not enough content to generate tests. Provide a story or a valid Jira link.' });\r\n }\r\n\r\n logger.info({ suiteName: parsed.data.suiteName }, 'Story generation requested');\r\n\r\n const { suiteId, suiteName } = await generateSuiteFromStory(storyText, {\r\n rootDir,\r\n outputDir: testsDir,\r\n suiteName: parsed.data.suiteName,\r\n });\r\n\r\n return reply.status(201).send({ message: 'Suite generated successfully', suiteId, suiteName });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate suite from story', err);\r\n }\r\n });\r\n\r\n // POST /api/story/generate-bulk\r\n // Fire-and-forget: returns 202 immediately, progress via WebSocket events:\r\n // story:bulk-start → { jobId, total }\r\n // story:bulk-progress → { jobId, total, completed, failed, currentIndex, currentStory }\r\n // story:bulk-done → { jobId, total, completed, failed, failedItems }\r\n const BulkStoryItem = z.object({\r\n story: z.string().min(10),\r\n suiteName: z.string().min(1).optional(),\r\n jiraUrl: z.string().optional(),\r\n });\r\n const GenerateBulkBody = z.object({\r\n stories: z.array(BulkStoryItem).min(1).max(500),\r\n concurrency: z.number().int().min(1).max(5).default(3),\r\n });\r\n\r\n fastify.post('/story/generate-bulk', async (req, reply) => {\r\n const parsed = GenerateBulkBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n\r\n const { stories, concurrency } = parsed.data;\r\n const testsDir = path.join(rootDir, 'tests');\r\n const wsManager = (fastify as unknown as { wsManager?: { broadcast(e: string, d: unknown): void } }).wsManager;\r\n\r\n logger.info({ total: stories.length, concurrency }, 'Bulk story generation requested');\r\n\r\n // Pre-enrich any stories that have Jira URLs\r\n const enrichedStories = await Promise.all(\r\n stories.map(async (item) => {\r\n if (!item.jiraUrl) return { story: item.story, suiteName: item.suiteName };\r\n const issueKey = extractIssueKey(item.jiraUrl);\r\n if (!issueKey) return { story: item.story, suiteName: item.suiteName };\r\n try {\r\n const jiraContent = await fetchJiraIssue(issueKey);\r\n return {\r\n story: buildEnrichedStory(jiraContent, item.story),\r\n suiteName: item.suiteName ?? jiraContent.summary,\r\n };\r\n } catch {\r\n logger.warn({ issueKey }, 'Failed to fetch Jira issue for bulk item — using raw story');\r\n return { story: item.story, suiteName: item.suiteName };\r\n }\r\n }),\r\n );\r\n\r\n // Fire and forget — client tracks progress via WebSocket\r\n generateSuitesFromStories(\r\n enrichedStories,\r\n { rootDir, outputDir: testsDir },\r\n wsManager,\r\n concurrency,\r\n ).catch((err: unknown) => {\r\n logger.error({ err }, 'Bulk story generation error');\r\n });\r\n\r\n return reply.status(202).send({\r\n message: `Processing ${stories.length} stories in the background`,\r\n total: stories.length,\r\n });\r\n });\r\n\r\n // POST /api/story/swagger-preview — parse OpenAPI spec and return endpoints (no AI)\r\n fastify.post('/story/swagger-preview', async (req, reply) => {\r\n const body = req.body as { specUrl?: string };\r\n if (!body.specUrl) return reply.status(400).send({ error: 'specUrl is required' });\r\n try {\r\n const spec = await parseSwaggerSpec(body.specUrl);\r\n const tags = [...new Set(spec.endpoints.map((e) => e.tag))];\r\n return reply.send({\r\n title: spec.title,\r\n baseUrl: spec.baseUrl,\r\n totalEndpoints: spec.endpoints.length,\r\n tags,\r\n endpoints: spec.endpoints.map((e) => ({\r\n method: e.method,\r\n path: e.path,\r\n summary: e.summary,\r\n tag: e.tag,\r\n })),\r\n });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Could not fetch OpenAPI spec', err);\r\n }\r\n });\r\n\r\n // POST /api/story/generate-from-swagger — parse OpenAPI spec and generate API test suite\r\n const SwaggerBody = z.object({\r\n specUrl: z.string().min(1, 'Swagger/OpenAPI spec URL or JSON is required'),\r\n suiteName: z.string().min(1).optional(),\r\n tags: z.array(z.string()).optional(),\r\n requirements: z.string().optional(),\r\n });\r\n\r\n fastify.post('/story/generate-from-swagger', { config: { requestTimeout: 120000 } as Record<string, unknown> }, async (req, reply) => {\r\n const parsed = SwaggerBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\r\n }\r\n\r\n try {\r\n const spec = await parseSwaggerSpec(parsed.data.specUrl);\r\n logger.info({ title: spec.title, endpoints: spec.endpoints.length }, 'Parsed OpenAPI spec');\r\n\r\n // Filter by tags if specified\r\n let endpoints = spec.endpoints;\r\n if (parsed.data.tags && parsed.data.tags.length > 0) {\r\n const tagSet = new Set(parsed.data.tags.map((t) => t.toLowerCase()));\r\n endpoints = endpoints.filter((e) => tagSet.has(e.tag.toLowerCase()));\r\n }\r\n\r\n if (endpoints.length === 0) {\r\n return reply.status(400).send({ error: 'No endpoints found matching the specified tags' });\r\n }\r\n\r\n // Cap endpoints to avoid overwhelming the AI with a massive prompt\r\n const MAX_ENDPOINTS = 20;\r\n const totalEndpoints = endpoints.length;\r\n if (endpoints.length > MAX_ENDPOINTS) {\r\n logger.warn({ total: endpoints.length, max: MAX_ENDPOINTS }, 'Capping endpoints to max');\r\n endpoints = endpoints.slice(0, MAX_ENDPOINTS);\r\n }\r\n\r\n // Build a rich story from the parsed endpoints so the AI generates proper API test cases\r\n const storyLines = [\r\n `## API Test Suite: ${spec.title}`,\r\n `Base URL: ${spec.baseUrl}`,\r\n '',\r\n 'Generate API test cases for the following endpoints. Each test step should use ' +\r\n 'Playwright request API (page.request.get/post/put/delete/patch). ' +\r\n 'Include proper assertions for status codes and response bodies.',\r\n '',\r\n ];\r\n\r\n // Prepend user-provided requirements/context if present\r\n if (parsed.data.requirements?.trim()) {\r\n storyLines.push('### Additional Requirements');\r\n storyLines.push(parsed.data.requirements.trim());\r\n storyLines.push('');\r\n }\r\n\r\n for (const ep of endpoints) {\r\n storyLines.push(`### ${ep.method} ${ep.path}`);\r\n storyLines.push(` Summary: ${ep.summary}`);\r\n if (ep.parameters.length > 0) {\r\n storyLines.push(` Parameters: ${ep.parameters.map((p) => `${p.name} (${p.in}, ${p.type}${p.required ? ', required' : ''})`).join(', ')}`);\r\n }\r\n if (ep.requestBody) {\r\n storyLines.push(` Request Body: ${ep.requestBody.contentType}`);\r\n if (ep.requestBody.example) {\r\n storyLines.push(` Example: ${JSON.stringify(ep.requestBody.example)}`);\r\n }\r\n }\r\n storyLines.push(` Responses: ${ep.responses.map((r) => `${r.status} (${r.description})`).join(', ')}`);\r\n storyLines.push('');\r\n }\r\n\r\n const storyText = storyLines.join('\\n');\r\n const suiteName = parsed.data.suiteName ?? `${spec.title} API Tests`;\r\n const testsDir = path.join(rootDir, 'tests');\r\n\r\n const { suiteId } = await generateSuiteFromStory(storyText, {\r\n rootDir,\r\n outputDir: testsDir,\r\n suiteName,\r\n type: 'api',\r\n });\r\n\r\n return reply.status(201).send({\r\n message: 'API test suite generated from OpenAPI spec',\r\n suiteId,\r\n suiteName,\r\n endpointsFound: endpoints.length,\r\n totalEndpoints,\r\n specTitle: spec.title,\r\n });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate suite from OpenAPI spec', err);\r\n }\r\n });\r\n}\r\n","/**\r\n * Report routes — access stored run results.\r\n *\r\n * GET /api/report — list recent run results (metadata)\r\n * GET /api/report/:runId — get full run result\r\n * DELETE /api/report/:runId — delete a run result\r\n */\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { listResults, readResult, deleteResult } from '../../storage/result-store.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('routes/report');\r\n\r\nconst ListReportsQuery = z.object({\r\n limit: z.coerce.number().int().positive().max(100).default(20),\r\n});\r\n\r\nexport async function reportRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n\r\n // GET /api/report\r\n fastify.get('/report', async (req, reply) => {\r\n const parsed = ListReportsQuery.safeParse(req.query);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid query', details: parsed.error.issues });\r\n }\r\n try {\r\n const results = await listResults(rootDir, parsed.data.limit);\r\n return reply.send(results);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to list reports', err);\r\n }\r\n });\r\n\r\n // GET /api/report/:runId\r\n fastify.get<{ Params: { runId: string } }>('/report/:runId', async (req, reply) => {\r\n try {\r\n const result = await readResult(rootDir, req.params.runId);\r\n return reply.send(result);\r\n } catch {\r\n return reply.status(404).send({ error: `Report for run \"${req.params.runId}\" not found` });\r\n }\r\n });\r\n\r\n // DELETE /api/report/:runId\r\n fastify.delete<{ Params: { runId: string } }>('/report/:runId', async (req, reply) => {\r\n try {\r\n await deleteResult(rootDir, req.params.runId);\r\n logger.info({ runId: req.params.runId }, 'Run result deleted');\r\n return reply.status(204).send();\r\n } catch {\r\n return reply.status(404).send({ error: `Report for run \"${req.params.runId}\" not found` });\r\n }\r\n });\r\n}\r\n","/**\n * Baseline Store — saves/retrieves visual regression baselines.\n * Baselines are stored in results/baselines/{stepId}.png\n */\nimport path from 'path';\nimport fs from 'fs-extra';\n\nfunction baselinesDir(rootDir: string): string {\n return path.join(rootDir, 'results', 'baselines');\n}\n\nfunction baselinePath(rootDir: string, stepId: string): string {\n return path.join(baselinesDir(rootDir), `${stepId}.png`);\n}\n\nexport async function saveBaseline(rootDir: string, stepId: string, sourcePath: string): Promise<void> {\n const dir = baselinesDir(rootDir);\n await fs.ensureDir(dir);\n await fs.copy(sourcePath, baselinePath(rootDir, stepId), { overwrite: true });\n}\n\nexport function getBaselinePath(rootDir: string, stepId: string): string | null {\n const p = baselinePath(rootDir, stepId);\n try {\n if (fs.existsSync(p)) return p;\n } catch {\n // ignore\n }\n return null;\n}\n\nexport async function hasBaseline(rootDir: string, stepId: string): Promise<boolean> {\n return fs.pathExists(baselinePath(rootDir, stepId));\n}\n","/**\r\n * Media routes — serve captured screenshots, videos, traces, and logs.\r\n *\r\n * GET /api/results/screenshots/:filename\r\n * GET /api/results/videos/:filename\r\n * GET /api/results/traces/:filename\r\n * GET /api/results/logs/:filename\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { saveBaseline, hasBaseline } from '../../storage/baseline-store.js';\r\nimport { sendError } from '../utils.js';\r\n\r\nconst MIME: Record<string, string> = {\r\n '.png': 'image/png',\r\n '.jpg': 'image/jpeg',\r\n '.jpeg': 'image/jpeg',\r\n '.webm': 'video/webm',\r\n '.mp4': 'video/mp4',\r\n '.zip': 'application/zip',\r\n '.log': 'text/plain',\r\n '.txt': 'text/plain',\r\n};\r\n\r\ntype MediaParams = { Params: { category: string; filename: string } };\r\n\r\nexport async function mediaRoutes(fastify: FastifyInstance): Promise<void> {\r\n fastify.get<MediaParams>('/results/:category/:filename', async (req, reply) => {\r\n const { category, filename } = req.params;\r\n\r\n // Only allow safe categories\r\n if (!['screenshots', 'videos', 'traces', 'logs', 'baselines'].includes(category)) {\r\n return reply.status(404).send({ error: 'Unknown media category' });\r\n }\r\n\r\n // Prevent path traversal\r\n const safeName = path.basename(filename);\r\n const filePath = path.join(fastify.rootDir, 'results', category, safeName);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n return reply.status(404).send({ error: `File not found: ${safeName}` });\r\n }\r\n\r\n const ext = path.extname(safeName).toLowerCase();\r\n const mimeType = MIME[ext] ?? 'application/octet-stream';\r\n\r\n // For zip (traces) add download header\r\n if (ext === '.zip') {\r\n void reply.header('Content-Disposition', `attachment; filename=\"${safeName}\"`);\r\n }\r\n\r\n const stat = await fs.stat(filePath);\r\n void reply.header('Content-Length', stat.size);\r\n\r\n return reply.type(mimeType).send(fs.createReadStream(filePath));\r\n });\r\n\r\n // POST /api/baselines/:stepId/capture\r\n fastify.post<{ Params: { stepId: string } }>('/baselines/:stepId/capture', async (req, reply) => {\r\n try {\r\n const body = req.body as { screenshotPath?: string };\r\n if (!body?.screenshotPath) return reply.status(400).send({ error: 'screenshotPath required' });\r\n const fullPath = path.isAbsolute(body.screenshotPath)\r\n ? body.screenshotPath\r\n : path.join(fastify.rootDir, body.screenshotPath);\r\n if (!(await fs.pathExists(fullPath))) return reply.status(404).send({ error: 'Screenshot not found' });\r\n await saveBaseline(fastify.rootDir, req.params.stepId, fullPath);\r\n return reply.send({ saved: true });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to save baseline', err);\r\n }\r\n });\r\n\r\n // GET /api/baselines/:stepId\r\n fastify.get<{ Params: { stepId: string } }>('/baselines/:stepId', async (req, reply) => {\r\n try {\r\n const exists = await hasBaseline(fastify.rootDir, req.params.stepId);\r\n if (!exists) return reply.send({ hasBaseline: false });\r\n // Include file mtime as capturedAt so frontend can bust the image cache\r\n const filePath = path.join(fastify.rootDir, 'results', 'baselines', `${req.params.stepId}.png`);\r\n const stat = await fs.stat(filePath).catch(() => null);\r\n return reply.send({ hasBaseline: true, capturedAt: stat?.mtimeMs ?? Date.now() });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to check baseline', err);\r\n }\r\n });\r\n}\r\n","/**\r\n * Xray / Jira REST API Client\r\n *\r\n * Handles all communication with Jira (for issue creation) and Xray (for test steps/linking).\r\n * Supports both Xray Cloud and Xray Server/DC.\r\n */\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport type { XrayCreateTestResponse, XrayCreateTestSetResponse } from '../types/xray.js';\r\nimport type { TestCase, TestStep, TestSuite } from '../types/suite.js';\r\n\r\nconst logger = createChildLogger('xray-client');\r\n\r\nexport interface XrayClientConfig {\r\n jiraBaseUrl: string; // e.g. https://your-domain.atlassian.net\r\n jiraEmail: string;\r\n jiraApiToken: string;\r\n xrayClientId?: string; // Xray Cloud only\r\n xrayClientSecret?: string; // Xray Cloud only\r\n projectKey: string;\r\n testIssueType?: string; // default: \"Test\"\r\n testSetIssueType?: string; // default: \"Test Set\"\r\n}\r\n\r\ninterface AdfDocument {\r\n type: 'doc';\r\n version: 1;\r\n content: AdfNode[];\r\n}\r\n\r\ninterface AdfNode {\r\n type: string;\r\n content?: AdfNode[];\r\n text?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Convert plain text to Atlassian Document Format (ADF) — required by Jira REST API v3 */\r\nfunction toAdf(text: string): AdfDocument {\r\n const paragraphs: AdfNode[] = text.split('\\n').map((line) => ({\r\n type: 'paragraph',\r\n content: line.trim()\r\n ? [{ type: 'text', text: line }]\r\n : [],\r\n }));\r\n return { type: 'doc', version: 1, content: paragraphs };\r\n}\r\n\r\ninterface JiraIssueFields {\r\n project: { key: string };\r\n summary: string;\r\n description?: AdfDocument;\r\n issuetype: { name: string };\r\n labels?: string[];\r\n [key: string]: unknown;\r\n}\r\n\r\ninterface JiraIssue {\r\n id: string;\r\n key: string;\r\n self: string;\r\n fields?: Record<string, unknown>;\r\n}\r\n\r\nexport class XrayClient {\r\n private readonly config: XrayClientConfig;\r\n private readonly authHeader: string;\r\n private xrayToken: string | null = null;\r\n\r\n constructor(config: XrayClientConfig) {\r\n // Normalize: strip trailing slashes from base URL\r\n this.config = {\r\n ...config,\r\n jiraBaseUrl: config.jiraBaseUrl.replace(/\\/+$/, ''),\r\n projectKey: config.projectKey.trim().toUpperCase(),\r\n };\r\n // Basic auth for Jira Cloud REST API\r\n this.authHeader = 'Basic ' + Buffer.from(`${config.jiraEmail}:${config.jiraApiToken}`).toString('base64');\r\n }\r\n\r\n // ─── Jira REST API helpers ──────────────────────────────────────────────────\r\n\r\n private async jiraRequest<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n ): Promise<T> {\r\n const url = `${this.config.jiraBaseUrl}/rest/api/3${path}`;\r\n logger.debug({ method, url }, 'Jira API request');\r\n\r\n const headers: Record<string, string> = {\r\n 'Authorization': this.authHeader,\r\n 'Accept': 'application/json',\r\n };\r\n if (body !== undefined) {\r\n headers['Content-Type'] = 'application/json';\r\n }\r\n\r\n const res = await fetch(url, {\r\n method,\r\n headers,\r\n body: body !== undefined ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n logger.error({ status: res.status, url, body: text }, 'Jira API error');\r\n throw new Error(`Jira API ${method} ${path} → ${res.status}: ${text}`);\r\n }\r\n\r\n if (res.status === 204) return undefined as T;\r\n return res.json() as Promise<T>;\r\n }\r\n\r\n // ─── Xray Cloud authentication ────────────────────────────────────────────\r\n\r\n private async getXrayToken(): Promise<string> {\r\n if (this.xrayToken) return this.xrayToken;\r\n\r\n if (!this.config.xrayClientId || !this.config.xrayClientSecret) {\r\n // Xray Server/DC uses Jira auth directly\r\n return '';\r\n }\r\n\r\n const res = await fetch('https://xray.cloud.getxray.app/api/v2/authenticate', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n client_id: this.config.xrayClientId,\r\n client_secret: this.config.xrayClientSecret,\r\n }),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n throw new Error(`Xray auth failed: ${res.status} — ${text}`);\r\n }\r\n\r\n this.xrayToken = (await res.json()) as string;\r\n return this.xrayToken;\r\n }\r\n\r\n // ─── Xray API helpers ─────────────────────────────────────────────────────\r\n\r\n private async xrayRequest<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n ): Promise<T> {\r\n const token = await this.getXrayToken();\r\n const baseUrl = token\r\n ? 'https://xray.cloud.getxray.app/api/v2'\r\n : `${this.config.jiraBaseUrl}/rest/raven/2.0/api`;\r\n\r\n const url = `${baseUrl}${path}`;\r\n logger.debug({ method, url }, 'Xray API request');\r\n\r\n const headers: Record<string, string> = {\r\n 'Accept': 'application/json',\r\n };\r\n if (token) {\r\n headers['Authorization'] = `Bearer ${token}`;\r\n } else {\r\n headers['Authorization'] = this.authHeader;\r\n }\r\n if (body !== undefined) {\r\n headers['Content-Type'] = 'application/json';\r\n }\r\n\r\n const res = await fetch(url, {\r\n method,\r\n headers,\r\n body: body !== undefined ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n logger.error({ status: res.status, url, body: text }, 'Xray API error');\r\n throw new Error(`Xray API ${method} ${path} → ${res.status}: ${text}`);\r\n }\r\n\r\n if (res.status === 204) return undefined as T;\r\n return res.json() as Promise<T>;\r\n }\r\n\r\n // ─── Jira issue search ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Search for a Jira issue by summary and issue type within the project.\r\n * Used to prevent duplicates.\r\n */\r\n async findIssueByKey(issueKey: string): Promise<JiraIssue | null> {\r\n try {\r\n return await this.jiraRequest<JiraIssue>('GET', `/issue/${issueKey}`);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Search for issues by JQL.\r\n */\r\n async searchIssues(jql: string, maxResults = 50): Promise<JiraIssue[]> {\r\n const result = await this.jiraRequest<{ issues: JiraIssue[] }>('POST', '/search', {\r\n jql,\r\n maxResults,\r\n fields: ['summary', 'status', 'issuetype', 'labels', 'updated'],\r\n });\r\n return result.issues;\r\n }\r\n\r\n // ─── Create Test (issueType = \"Test\") ──────────────────────────────────────\r\n\r\n /**\r\n * Creates a Test issue. For Xray Cloud: uses GraphQL `createTest` mutation which\r\n * creates the Jira issue AND the Xray entity in one call (with steps + folder).\r\n * For Server/DC: uses Jira REST API.\r\n */\r\n async createTest(testCase: TestCase, suiteName: string, folderPath?: string): Promise<XrayCreateTestResponse> {\r\n if (this.isXrayCloud) {\r\n return this.createTestCloud(testCase, suiteName, folderPath);\r\n }\r\n return this.createTestServerDC(testCase, suiteName);\r\n }\r\n\r\n /** Xray Cloud: createTest GraphQL — creates issue + steps + folder in one call */\r\n private async createTestCloud(testCase: TestCase, suiteName: string, folderPath?: string): Promise<XrayCreateTestResponse> {\r\n const summary = `[${suiteName}] ${testCase.name}`;\r\n const description = testCase.description || `Automated test case: ${testCase.name}`;\r\n\r\n // Build steps array for GraphQL\r\n const stepsGql = testCase.steps.length > 0\r\n ? `steps: [${testCase.steps.map((s) =>\r\n `{ action: ${JSON.stringify(s.instruction)}, data: ${JSON.stringify(s.generatedCode ? `Strategy: ${s.strategy}` : '')}, result: \"Step completes successfully\" }`\r\n ).join(',\\n ')}],`\r\n : '';\r\n\r\n // Build folder path\r\n const folderGql = folderPath ? `folderPath: ${JSON.stringify(folderPath)},` : '';\r\n\r\n const mutation = `mutation {\r\n createTest(\r\n testType: { name: \"Manual\" },\r\n ${folderGql}\r\n ${stepsGql}\r\n jira: {\r\n fields: {\r\n summary: ${JSON.stringify(summary)},\r\n description: ${JSON.stringify(description)},\r\n project: { key: ${JSON.stringify(this.config.projectKey)} }\r\n }\r\n }\r\n ) {\r\n test {\r\n issueId\r\n jira(fields: [\"key\"])\r\n }\r\n warnings\r\n }\r\n }`;\r\n\r\n logger.info({ caseName: testCase.name, projectKey: this.config.projectKey, folderPath }, 'Creating Test via Xray Cloud GraphQL');\r\n\r\n const result = await this.xrayGraphQL<{\r\n createTest: {\r\n test: { issueId: string; jira: Record<string, unknown> };\r\n warnings: string[];\r\n };\r\n }>(mutation);\r\n\r\n if (!result?.createTest?.test) {\r\n throw new Error('Xray createTest returned no test data');\r\n }\r\n\r\n const test = result.createTest.test;\r\n const jiraKey = (test.jira as { key?: string })?.key ?? '';\r\n const warnings = result.createTest.warnings;\r\n\r\n if (warnings && warnings.length > 0) {\r\n logger.warn({ warnings, jiraKey }, 'Xray createTest warnings');\r\n }\r\n\r\n logger.info({ issueId: test.issueId, jiraKey, stepCount: testCase.steps.length, folderPath }, 'Xray Test created via GraphQL');\r\n\r\n return { id: test.issueId, key: jiraKey, self: '' };\r\n }\r\n\r\n /** Xray Server/DC: create via Jira REST API */\r\n private async createTestServerDC(testCase: TestCase, suiteName: string): Promise<XrayCreateTestResponse> {\r\n const issueType = this.config.testIssueType ?? 'Test';\r\n const fields: JiraIssueFields = {\r\n project: { key: this.config.projectKey },\r\n summary: `[${suiteName}] ${testCase.name}`,\r\n description: toAdf(testCase.description || `Automated test case: ${testCase.name}`),\r\n issuetype: { name: issueType },\r\n labels: ['assuremind', ...testCase.tags],\r\n };\r\n\r\n logger.info({ caseName: testCase.name, projectKey: this.config.projectKey }, 'Creating Xray Test via Jira REST');\r\n const result = await this.jiraRequest<JiraIssue>('POST', '/issue', { fields });\r\n\r\n if (testCase.steps.length > 0) {\r\n await this.addTestStepsServerDC(result.key, testCase.steps);\r\n }\r\n\r\n return { id: result.id, key: result.key, self: result.self };\r\n }\r\n\r\n /**\r\n * Updates an existing Test issue in Jira.\r\n */\r\n async updateTest(testIssue: { key: string; id: string }, testCase: TestCase, suiteName: string): Promise<void> {\r\n const fields: Partial<JiraIssueFields> = {\r\n summary: `[${suiteName}] ${testCase.name}`,\r\n description: toAdf(testCase.description || `Automated test case: ${testCase.name}`),\r\n labels: ['assuremind', ...testCase.tags],\r\n };\r\n\r\n logger.info({ issueKey: testIssue.key, caseName: testCase.name }, 'Updating Xray Test');\r\n await this.jiraRequest('PUT', `/issue/${testIssue.key}`, { fields });\r\n\r\n if (testCase.steps.length > 0) {\r\n await this.replaceTestSteps(testIssue, testCase.steps);\r\n }\r\n }\r\n\r\n // ─── Create Test Set (grouping) ────────────────────────────────────────────\r\n\r\n /**\r\n * Creates a Test Set. For Xray Cloud: uses GraphQL `createTestSet` mutation.\r\n * For Server/DC: uses Jira REST API.\r\n * @param testIssueIds — optional Xray issueIds of tests to include (Cloud only)\r\n */\r\n async createTestSet(suite: TestSuite, testIssueIds?: string[]): Promise<XrayCreateTestSetResponse> {\r\n if (this.isXrayCloud) {\r\n return this.createTestSetCloud(suite, testIssueIds);\r\n }\r\n return this.createTestSetServerDC(suite);\r\n }\r\n\r\n /** Xray Cloud: createTestSet GraphQL */\r\n private async createTestSetCloud(suite: TestSuite, testIssueIds?: string[]): Promise<XrayCreateTestSetResponse> {\r\n const testsGql = testIssueIds && testIssueIds.length > 0\r\n ? `testIssueIds: [${testIssueIds.map((id) => `\"${id}\"`).join(', ')}],`\r\n : '';\r\n\r\n const mutation = `mutation {\r\n createTestSet(\r\n ${testsGql}\r\n jira: {\r\n fields: {\r\n summary: ${JSON.stringify(suite.name)},\r\n description: ${JSON.stringify(suite.description || `Automated test suite: ${suite.name}`)},\r\n project: { key: ${JSON.stringify(this.config.projectKey)} }\r\n }\r\n }\r\n ) {\r\n testSet {\r\n issueId\r\n jira(fields: [\"key\"])\r\n }\r\n warnings\r\n }\r\n }`;\r\n\r\n logger.info({ suiteName: suite.name, projectKey: this.config.projectKey, testCount: testIssueIds?.length }, 'Creating Test Set via Xray Cloud GraphQL');\r\n\r\n const result = await this.xrayGraphQL<{\r\n createTestSet: {\r\n testSet: { issueId: string; jira: Record<string, unknown> };\r\n warnings: string[];\r\n };\r\n }>(mutation);\r\n\r\n if (!result?.createTestSet?.testSet) {\r\n throw new Error('Xray createTestSet returned no data');\r\n }\r\n\r\n const testSet = result.createTestSet.testSet;\r\n const jiraKey = (testSet.jira as { key?: string })?.key ?? '';\r\n const warnings = result.createTestSet.warnings;\r\n\r\n if (warnings && warnings.length > 0) {\r\n logger.warn({ warnings, jiraKey }, 'Xray createTestSet warnings');\r\n }\r\n\r\n logger.info({ issueId: testSet.issueId, jiraKey }, 'Xray Test Set created via GraphQL');\r\n\r\n return { id: testSet.issueId, key: jiraKey, self: '' };\r\n }\r\n\r\n /** Xray Server/DC: create via Jira REST API */\r\n private async createTestSetServerDC(suite: TestSuite): Promise<XrayCreateTestSetResponse> {\r\n const issueType = this.config.testSetIssueType ?? 'Test Set';\r\n const fields: JiraIssueFields = {\r\n project: { key: this.config.projectKey },\r\n summary: suite.name,\r\n description: toAdf(suite.description || `Automated test suite: ${suite.name}`),\r\n issuetype: { name: issueType },\r\n labels: ['assuremind', ...suite.tags],\r\n };\r\n\r\n logger.info({ suiteName: suite.name, projectKey: this.config.projectKey }, 'Creating Xray Test Set via Jira REST');\r\n const result = await this.jiraRequest<JiraIssue>('POST', '/issue', { fields });\r\n return { id: result.id, key: result.key, self: result.self };\r\n }\r\n\r\n /**\r\n * Updates an existing Test Set issue in Jira.\r\n */\r\n async updateTestSet(issueKey: string, suite: TestSuite): Promise<void> {\r\n const fields: Partial<JiraIssueFields> = {\r\n summary: suite.name,\r\n description: toAdf(suite.description || `Automated test suite: ${suite.name}`),\r\n labels: ['assuremind', ...suite.tags],\r\n };\r\n\r\n logger.info({ issueKey, suiteName: suite.name }, 'Updating Xray Test Set');\r\n await this.jiraRequest('PUT', `/issue/${issueKey}`, { fields });\r\n }\r\n\r\n // ─── Test Steps ────────────────────────────────────────────────────────────\r\n\r\n /** Whether this instance is configured for Xray Cloud (has client ID/secret) */\r\n private get isXrayCloud(): boolean {\r\n return !!(this.config.xrayClientId && this.config.xrayClientSecret);\r\n }\r\n\r\n /**\r\n * Adds test steps to an Xray Test issue.\r\n * @param testIssue — { key: issue key, id: Jira numeric ID }\r\n * Xray Cloud uses GraphQL API (needs Xray internal ID); Server/DC uses REST (needs key).\r\n */\r\n async addTestSteps(testIssue: { key: string; id: string }, steps: TestStep[]): Promise<void> {\r\n if (this.isXrayCloud) {\r\n // Resolve Xray internal ID from the Jira issue key\r\n const xrayId = await this.resolveXrayIssueId(testIssue.key, 'Test');\r\n if (!xrayId) {\r\n logger.warn({ testKey: testIssue.key }, 'Cannot add steps — Test not found in Xray yet');\r\n return;\r\n }\r\n await this.addTestStepsCloud(xrayId, steps);\r\n } else {\r\n await this.addTestStepsServerDC(testIssue.key, steps);\r\n }\r\n }\r\n\r\n /** Xray Cloud — use GraphQL addTestStep (one at a time) */\r\n private async addTestStepsCloud(xrayIssueId: string, steps: TestStep[]): Promise<void> {\r\n let added = 0;\r\n for (const step of steps) {\r\n const action = step.instruction;\r\n const data = step.generatedCode ? `Generated code (strategy: ${step.strategy})` : '';\r\n const result = 'Step completes successfully';\r\n\r\n try {\r\n await this.xrayGraphQL(\r\n `mutation {\r\n addTestStep(\r\n issueId: \"${xrayIssueId}\",\r\n step: {\r\n action: ${JSON.stringify(action)},\r\n data: ${JSON.stringify(data)},\r\n result: ${JSON.stringify(result)}\r\n }\r\n ) {\r\n id\r\n action\r\n }\r\n }`,\r\n );\r\n added++;\r\n } catch (err) {\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n if (errMsg.includes('not found')) {\r\n logger.warn({ xrayIssueId }, 'Xray issue not found during step add — aborting');\r\n break;\r\n }\r\n logger.warn({ xrayIssueId, step: action, err: errMsg }, 'Failed to add test step');\r\n }\r\n }\r\n if (added > 0) {\r\n logger.info({ xrayIssueId, added, total: steps.length }, 'Test steps added via Xray Cloud GraphQL');\r\n } else if (steps.length > 0) {\r\n logger.warn({ xrayIssueId }, 'Failed to add any steps');\r\n }\r\n }\r\n\r\n /** Xray Server/DC — use REST API /test/{key}/step */\r\n private async addTestStepsServerDC(testIssueKey: string, steps: TestStep[]): Promise<void> {\r\n const xraySteps = steps.map((s, i) => ({\r\n index: i + 1,\r\n action: s.instruction,\r\n data: s.generatedCode ? `Generated code (strategy: ${s.strategy})` : '',\r\n result: 'Step completes successfully',\r\n }));\r\n\r\n try {\r\n await this.xrayRequest('PUT', `/test/${testIssueKey}/step`, xraySteps);\r\n logger.debug({ testIssueKey, stepCount: steps.length }, 'Test steps added');\r\n } catch (err) {\r\n logger.warn({ testIssueKey, err }, 'Bulk step add failed, trying one-by-one');\r\n for (const step of xraySteps) {\r\n try {\r\n await this.xrayRequest('POST', `/test/${testIssueKey}/step`, step);\r\n } catch (stepErr) {\r\n logger.warn({ testIssueKey, step: step.index, err: stepErr }, 'Individual step add failed');\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Replaces all test steps on an Xray Test issue.\r\n */\r\n async replaceTestSteps(testIssue: { key: string; id: string }, steps: TestStep[]): Promise<void> {\r\n if (this.isXrayCloud) {\r\n // Resolve Xray internal ID\r\n const xrayId = await this.resolveXrayIssueId(testIssue.key, 'Test');\r\n if (!xrayId) {\r\n logger.warn({ testKey: testIssue.key }, 'Cannot replace steps — Test not found in Xray');\r\n return;\r\n }\r\n await this.addTestStepsCloud(xrayId, steps);\r\n return;\r\n }\r\n\r\n // Server/DC: Delete existing then re-add\r\n try {\r\n const existing = await this.xrayRequest<Array<{ id: number }>>('GET', `/test/${testIssue.key}/step`);\r\n for (const step of existing) {\r\n await this.xrayRequest('DELETE', `/test/${testIssue.key}/step/${step.id}`);\r\n }\r\n } catch {\r\n logger.debug({ testIssueKey: testIssue.key }, 'No existing steps to delete (or endpoint unavailable)');\r\n }\r\n\r\n await this.addTestStepsServerDC(testIssue.key, steps);\r\n }\r\n\r\n // ─── Link Tests to Test Set ────────────────────────────────────────────────\r\n\r\n /**\r\n * Links test issues to a Test Set.\r\n * @param testSet — { key: issue key, id: numeric issue ID }\r\n * @param tests — array of { key, id } for each test\r\n */\r\n async linkTestsToTestSet(testSet: { key: string; id: string }, tests: Array<{ key: string; id: string }>): Promise<void> {\r\n if (tests.length === 0) return;\r\n\r\n if (this.isXrayCloud) {\r\n await this.linkTestsCloud(testSet, tests);\r\n } else {\r\n try {\r\n await this.xrayRequest('POST', `/testset/${testSet.key}/test`, {\r\n add: tests.map((t) => t.key),\r\n });\r\n logger.info({ testSetKey: testSet.key, count: tests.length }, 'Tests linked to Test Set');\r\n } catch (err) {\r\n logger.warn({ testSetKey: testSet.key, err }, 'Xray link API failed, trying Jira issue links');\r\n await this.linkViaJiraIssueLinks(testSet.key, tests.map((t) => t.key));\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Xray Cloud: link tests to test set via GraphQL.\r\n * Resolves Xray internal IDs first (they differ from Jira numeric IDs).\r\n */\r\n private async linkTestsCloud(testSet: { key: string; id: string }, tests: Array<{ key: string; id: string }>): Promise<void> {\r\n logger.info({ testSetKey: testSet.key, testKeys: tests.map((t) => t.key) }, 'Resolving Xray IDs for linking');\r\n\r\n // Resolve the Test Set's Xray internal ID\r\n const xrayTestSetId = await this.resolveXrayIssueId(testSet.key, 'Test Set');\r\n if (!xrayTestSetId) {\r\n logger.error({ testSetKey: testSet.key }, 'Cannot link — Test Set not found in Xray');\r\n return;\r\n }\r\n\r\n // Resolve each Test's Xray internal ID\r\n const xrayTestIds: string[] = [];\r\n for (const test of tests) {\r\n const xrayTestId = await this.resolveXrayIssueId(test.key, 'Test');\r\n if (xrayTestId) {\r\n xrayTestIds.push(xrayTestId);\r\n } else {\r\n logger.warn({ testKey: test.key }, 'Could not resolve Xray ID for test — skipping');\r\n }\r\n }\r\n\r\n if (xrayTestIds.length === 0) {\r\n logger.warn({ testSetKey: testSet.key }, 'No test IDs resolved — skipping link');\r\n return;\r\n }\r\n\r\n try {\r\n const result = await this.xrayGraphQL<{ addTestsToTestSet: { addedTests: string[]; warning: string } }>(\r\n `mutation {\r\n addTestsToTestSet(\r\n issueId: \"${xrayTestSetId}\",\r\n testIssueIds: [${xrayTestIds.map((id) => `\"${id}\"`).join(', ')}]\r\n ) {\r\n addedTests\r\n warning\r\n }\r\n }`,\r\n );\r\n if (result) {\r\n logger.info({\r\n testSetKey: testSet.key, xrayTestSetId, count: xrayTestIds.length,\r\n added: result.addTestsToTestSet?.addedTests?.length,\r\n warning: result.addTestsToTestSet?.warning,\r\n }, 'Tests linked to Test Set via Xray Cloud');\r\n }\r\n } catch (err) {\r\n logger.error({ testSetKey: testSet.key, xrayTestSetId, err: err instanceof Error ? err.message : String(err) }, 'linkTestsCloud failed');\r\n }\r\n }\r\n\r\n private sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n\r\n /** Fallback: link tests via Jira issue links */\r\n private async linkViaJiraIssueLinks(testSetKey: string, testKeys: string[]): Promise<void> {\r\n for (const testKey of testKeys) {\r\n try {\r\n await this.jiraRequest('POST', '/issueLink', {\r\n type: { name: 'Test Set' },\r\n inwardIssue: { key: testSetKey },\r\n outwardIssue: { key: testKey },\r\n });\r\n } catch (linkErr) {\r\n logger.error({ testSetKey, testKey, err: linkErr }, 'Failed to link test to test set');\r\n }\r\n }\r\n }\r\n\r\n // ─── Folder Management (Xray Cloud) ──────────────────────────────────────\r\n\r\n /**\r\n * Creates a folder in the Xray Test Repository and adds tests to it.\r\n * Resolves Xray internal IDs from Jira issue keys.\r\n * @param folderName — folder name (will be created as /folderName)\r\n * @param tests — array of { key, id } for each test\r\n */\r\n async createFolderAndAddTests(folderName: string, tests: Array<{ key: string; id: string }>): Promise<void> {\r\n if (!this.isXrayCloud) {\r\n logger.debug('Folder creation skipped — only supported on Xray Cloud');\r\n return;\r\n }\r\n if (tests.length === 0) return;\r\n\r\n const folderPath = `/${folderName}`;\r\n\r\n try {\r\n // Get project ID (Xray Cloud GraphQL needs numeric project ID)\r\n const project = await this.jiraRequest<{ id: string }>('GET', `/project/${this.config.projectKey}`);\r\n const projectId = project.id;\r\n\r\n // Create folder — handle \"already exists\" gracefully\r\n try {\r\n await this.xrayGraphQL(\r\n `mutation {\r\n createFolder(\r\n projectId: \"${projectId}\",\r\n path: ${JSON.stringify(folderPath)}\r\n ) {\r\n folder {\r\n name\r\n path\r\n }\r\n }\r\n }`,\r\n );\r\n logger.info({ folderPath, projectId }, 'Test Repository folder created');\r\n } catch (folderErr) {\r\n const errMsg = folderErr instanceof Error ? folderErr.message : String(folderErr);\r\n if (errMsg.includes('already exists')) {\r\n logger.info({ folderPath }, 'Test Repository folder already exists — reusing');\r\n } else {\r\n throw folderErr;\r\n }\r\n }\r\n\r\n // Resolve Xray internal IDs for each test\r\n const xrayTestIds: string[] = [];\r\n for (const test of tests) {\r\n const xrayId = await this.resolveXrayIssueId(test.key, 'Test');\r\n if (xrayId) {\r\n xrayTestIds.push(xrayId);\r\n } else {\r\n logger.warn({ testKey: test.key }, 'Could not resolve Xray ID for folder — skipping');\r\n }\r\n }\r\n\r\n if (xrayTestIds.length === 0) {\r\n logger.warn({ folderPath }, 'No Xray IDs resolved — cannot add tests to folder');\r\n return;\r\n }\r\n\r\n logger.info({ folderPath, xrayTestIds }, 'Adding tests to folder with resolved Xray IDs');\r\n\r\n try {\r\n await this.xrayGraphQL(\r\n `mutation {\r\n addTestsToFolder(\r\n projectId: \"${projectId}\",\r\n path: ${JSON.stringify(folderPath)},\r\n testIssueIds: [${xrayTestIds.map((id) => `\"${id}\"`).join(', ')}]\r\n ) {\r\n folder { name }\r\n warnings\r\n }\r\n }`,\r\n );\r\n logger.info({ folderPath, count: xrayTestIds.length }, 'Tests added to folder');\r\n } catch (addErr) {\r\n logger.warn({ folderPath, err: addErr instanceof Error ? addErr.message : String(addErr) }, 'Failed to add tests to folder');\r\n }\r\n } catch (err) {\r\n // Non-fatal — tests are still created, just not organized into a folder\r\n logger.error({ folderName, err: err instanceof Error ? err.message : String(err) }, 'FAILED to create folder or add tests — tests exist but are unorganized');\r\n }\r\n }\r\n\r\n // ─── Xray Cloud GraphQL helper ────────────────────────────────────────────\r\n\r\n /** Execute an Xray Cloud GraphQL mutation/query */\r\n private async xrayGraphQL<T = unknown>(query: string): Promise<T | null> {\r\n const token = await this.getXrayToken();\r\n const graphqlUrl = 'https://xray.cloud.getxray.app/api/v2/graphql';\r\n\r\n const res = await fetch(graphqlUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({ query }),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n logger.warn({ status: res.status, body: text }, 'Xray Cloud GraphQL request failed');\r\n throw new Error(`Xray GraphQL → ${res.status}: ${text}`);\r\n }\r\n\r\n const result = await res.json() as { data?: T; errors?: Array<{ message: string }> };\r\n if (result.errors && result.errors.length > 0) {\r\n logger.warn({ errors: result.errors }, 'Xray Cloud GraphQL returned errors');\r\n throw new Error(`Xray GraphQL errors: ${result.errors.map((e) => e.message).join('; ')}`);\r\n }\r\n\r\n return result.data ?? null;\r\n }\r\n\r\n // ─── Xray Cloud ID Resolution ────────────────────────────────────────────\r\n\r\n /**\r\n * Resolves a Jira issue key to an Xray Cloud internal issueId.\r\n * Xray Cloud GraphQL mutations use internal IDs, NOT Jira numeric IDs.\r\n * Retries because Xray needs time to index newly created Jira issues.\r\n */\r\n async resolveXrayIssueId(jiraKey: string, type: 'Test' | 'Test Set' = 'Test'): Promise<string | null> {\r\n if (!this.isXrayCloud) return null;\r\n\r\n const queryName = type === 'Test Set' ? 'getTestSets' : 'getTests';\r\n const resultField = type === 'Test Set' ? 'getTestSets' : 'getTests';\r\n\r\n const delays = [0, 5000, 10000, 20000]; // immediate, then 5s, 10s, 20s retries\r\n for (let attempt = 0; attempt < delays.length; attempt++) {\r\n if (delays[attempt]! > 0) {\r\n logger.info({ jiraKey, attempt, delay: delays[attempt] }, `Waiting ${delays[attempt]! / 1000}s before retry`);\r\n await this.sleep(delays[attempt]!);\r\n }\r\n\r\n try {\r\n const gql = `{\r\n ${queryName}(jql: \"key = ${jiraKey}\", limit: 1) {\r\n total\r\n results {\r\n issueId\r\n jira(fields: [\"key\", \"summary\"])\r\n }\r\n }\r\n }`;\r\n logger.info({ jiraKey, attempt, query: queryName }, `Querying Xray for ${type} issueId`);\r\n\r\n const result = await this.xrayGraphQL<Record<string, { total: number; results: Array<{ issueId: string; jira: unknown }> }>>(gql);\r\n\r\n // Log the raw response for debugging\r\n const queryResult = result?.[resultField];\r\n logger.info({ jiraKey, attempt, total: queryResult?.total, resultCount: queryResult?.results?.length, raw: JSON.stringify(queryResult) }, `Xray ${queryName} response`);\r\n\r\n const items = queryResult?.results;\r\n if (items && items.length > 0 && items[0]!.issueId) {\r\n logger.info({ jiraKey, xrayIssueId: items[0]!.issueId, attempt }, `Resolved Xray issueId for ${type}`);\r\n return items[0]!.issueId;\r\n }\r\n logger.warn({ jiraKey, attempt, total: queryResult?.total }, `Xray has not indexed ${type} yet — no results`);\r\n } catch (err) {\r\n logger.warn({ jiraKey, attempt, err: err instanceof Error ? err.message : String(err) }, `resolveXrayIssueId attempt ${attempt} failed`);\r\n }\r\n }\r\n\r\n logger.error({ jiraKey }, `Could not resolve Xray issueId for ${type} after ${delays.length} attempts`);\r\n return null;\r\n }\r\n\r\n // ─── Validation ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Validates the Jira/Xray connection by fetching the project and listing issue types.\r\n */\r\n async validate(): Promise<{ valid: boolean; error?: string; issueTypes?: string[] }> {\r\n try {\r\n const project = await this.jiraRequest<{ issueTypes?: { name: string }[] }>('GET', `/project/${this.config.projectKey}`);\r\n const issueTypes = (project.issueTypes ?? []).map((it) => it.name);\r\n return { valid: true, issueTypes };\r\n } catch (err) {\r\n return {\r\n valid: false,\r\n error: `Cannot connect to Jira project \"${this.config.projectKey}\": ${err instanceof Error ? err.message : String(err)}`,\r\n };\r\n }\r\n }\r\n}\r\n","import { z } from 'zod';\r\n\r\n// ─── Xray Sync Status ────────────────────────────────────────────────────────\r\n\r\nexport const XraySyncStatus = z.enum([\r\n 'not-created',\r\n 'created',\r\n 'synced',\r\n 'update-pending',\r\n]);\r\nexport type XraySyncStatus = z.infer<typeof XraySyncStatus>;\r\n\r\n// ─── Xray Mapping — links Assuremind entities to Jira/Xray issue IDs ──────────\r\n\r\nexport const XrayCaseMappingSchema = z.object({\r\n caseId: z.string().min(1),\r\n xrayTestId: z.string().min(1), // Jira issue key, e.g. \"PROJ-123\"\r\n xrayTestIssueId: z.string().min(1), // Jira issue numeric ID\r\n lastSyncedAt: z.string().datetime(),\r\n lastSyncHash: z.string(), // content hash to detect changes\r\n});\r\n\r\nexport const XraySuiteMappingSchema = z.object({\r\n suiteId: z.string().min(1),\r\n xrayTestSetId: z.string().min(1), // Jira issue key, e.g. \"PROJ-100\"\r\n xrayTestSetIssueId: z.string().min(1), // Jira issue numeric ID\r\n lastSyncedAt: z.string().datetime(),\r\n lastSyncHash: z.string(),\r\n cases: z.array(XrayCaseMappingSchema).default([]),\r\n});\r\n\r\nexport const XrayMappingFileSchema = z.object({\r\n projectKey: z.string().min(1),\r\n suites: z.array(XraySuiteMappingSchema).default([]),\r\n updatedAt: z.string().datetime(),\r\n});\r\n\r\nexport type XrayCaseMapping = z.infer<typeof XrayCaseMappingSchema>;\r\nexport type XraySuiteMapping = z.infer<typeof XraySuiteMappingSchema>;\r\nexport type XrayMappingFile = z.infer<typeof XrayMappingFileSchema>;\r\n\r\n// ─── Xray API response types ────────────────────────────────────────────────\r\n\r\nexport interface XrayCreateTestResponse {\r\n id: string;\r\n key: string;\r\n self: string;\r\n}\r\n\r\nexport interface XrayCreateTestSetResponse {\r\n id: string;\r\n key: string;\r\n self: string;\r\n}\r\n\r\n// ─── Xray operation result ──────────────────────────────────────────────────\r\n\r\nexport interface XrayOperationResult {\r\n success: boolean;\r\n suiteId?: string;\r\n caseId?: string;\r\n xrayKey?: string; // Jira issue key, e.g. \"PROJ-123\"\r\n xrayId?: string; // Jira issue numeric ID, e.g. \"10200\"\r\n action: 'created' | 'synced' | 'skipped' | 'failed';\r\n error?: string;\r\n}\r\n\r\nexport interface XrayBulkResult {\r\n total: number;\r\n created: number;\r\n synced: number;\r\n skipped: number;\r\n failed: number;\r\n results: XrayOperationResult[];\r\n}\r\n\r\n// ─── Xray status for UI display ─────────────────────────────────────────────\r\n\r\nexport interface XraySuiteStatus {\r\n suiteId: string;\r\n status: XraySyncStatus;\r\n xrayTestSetId: string | null;\r\n lastSyncedAt: string | null;\r\n cases: XrayCaseStatus[];\r\n}\r\n\r\nexport interface XrayCaseStatus {\r\n caseId: string;\r\n status: XraySyncStatus;\r\n xrayTestId: string | null;\r\n lastSyncedAt: string | null;\r\n}\r\n","/**\r\n * Xray Mapping Store — persists the Assuremind ↔ Xray/Jira mapping as a JSON file.\r\n *\r\n * File location: <rootDir>/assuremind-data/xray-mapping.json\r\n */\r\nimport path from 'path';\r\nimport fs from 'fs-extra';\r\nimport {\r\n XrayMappingFileSchema,\r\n type XrayMappingFile,\r\n type XraySuiteMapping,\r\n type XrayCaseMapping,\r\n} from '../types/xray.js';\r\nimport { atomicWriteJson, readJson } from './utils.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('xray-store');\r\n\r\nconst MAPPING_FILE = 'xray-mapping.json';\r\n\r\nfunction mappingPath(rootDir: string): string {\r\n return path.join(rootDir, 'assuremind-data', MAPPING_FILE);\r\n}\r\n\r\n/**\r\n * Reads the xray-mapping.json. Returns empty mapping if file does not exist.\r\n */\r\nexport async function readXrayMapping(rootDir: string): Promise<XrayMappingFile> {\r\n const filePath = mappingPath(rootDir);\r\n\r\n if (!(await fs.pathExists(filePath))) {\r\n return {\r\n projectKey: '',\r\n suites: [],\r\n updatedAt: new Date().toISOString(),\r\n };\r\n }\r\n\r\n const raw = await readJson(filePath);\r\n const result = XrayMappingFileSchema.safeParse(raw);\r\n\r\n if (!result.success) {\r\n logger.warn({ path: filePath, errors: result.error.issues }, 'Invalid xray-mapping.json — returning empty');\r\n return { projectKey: '', suites: [], updatedAt: new Date().toISOString() };\r\n }\r\n\r\n return result.data;\r\n}\r\n\r\n/**\r\n * Writes the xray-mapping.json atomically.\r\n */\r\nexport async function writeXrayMapping(rootDir: string, mapping: XrayMappingFile): Promise<void> {\r\n const filePath = mappingPath(rootDir);\r\n await fs.ensureDir(path.dirname(filePath));\r\n const data = { ...mapping, updatedAt: new Date().toISOString() };\r\n await atomicWriteJson(filePath, data);\r\n logger.debug({ path: filePath }, 'Xray mapping written');\r\n}\r\n\r\n/**\r\n * Finds a suite mapping by Assuremind suite ID. Returns undefined if not mapped.\r\n */\r\nexport function findSuiteMapping(\r\n mapping: XrayMappingFile,\r\n suiteId: string,\r\n): XraySuiteMapping | undefined {\r\n return mapping.suites.find((s) => s.suiteId === suiteId);\r\n}\r\n\r\n/**\r\n * Finds a case mapping by Assuremind case ID. Returns undefined if not mapped.\r\n */\r\nexport function findCaseMapping(\r\n mapping: XrayMappingFile,\r\n caseId: string,\r\n): { suiteMapping: XraySuiteMapping; caseMapping: XrayCaseMapping } | undefined {\r\n for (const suite of mapping.suites) {\r\n const caseMapping = suite.cases.find((c) => c.caseId === caseId);\r\n if (caseMapping) return { suiteMapping: suite, caseMapping };\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Upserts a suite mapping.\r\n */\r\nexport function upsertSuiteMapping(\r\n mapping: XrayMappingFile,\r\n suiteMapping: XraySuiteMapping,\r\n): XrayMappingFile {\r\n const idx = mapping.suites.findIndex((s) => s.suiteId === suiteMapping.suiteId);\r\n const suites = [...mapping.suites];\r\n if (idx >= 0) {\r\n suites[idx] = suiteMapping;\r\n } else {\r\n suites.push(suiteMapping);\r\n }\r\n return { ...mapping, suites, updatedAt: new Date().toISOString() };\r\n}\r\n\r\n/**\r\n * Upserts a case mapping within a suite mapping.\r\n */\r\nexport function upsertCaseMapping(\r\n suiteMapping: XraySuiteMapping,\r\n caseMapping: XrayCaseMapping,\r\n): XraySuiteMapping {\r\n const idx = suiteMapping.cases.findIndex((c) => c.caseId === caseMapping.caseId);\r\n const cases = [...suiteMapping.cases];\r\n if (idx >= 0) {\r\n cases[idx] = caseMapping;\r\n } else {\r\n cases.push(caseMapping);\r\n }\r\n return { ...suiteMapping, cases };\r\n}\r\n","/**\r\n * Xray Integration Service\r\n *\r\n * Orchestrates create/sync operations between Assuremind and Xray/Jira.\r\n * Handles duplicate prevention, change detection, and mapping persistence.\r\n */\r\nimport crypto from 'crypto';\r\nimport { XrayClient, type XrayClientConfig } from './client.js';\r\nimport {\r\n readXrayMapping,\r\n writeXrayMapping,\r\n findSuiteMapping,\r\n findCaseMapping,\r\n upsertSuiteMapping,\r\n upsertCaseMapping,\r\n} from '../storage/xray-store.js';\r\nimport { listSuites, readSuite, findSuiteDirById } from '../storage/suite-store.js';\r\nimport { listCases } from '../storage/case-store.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport type { TestSuite, TestCase } from '../types/suite.js';\r\nimport type {\r\n XrayMappingFile,\r\n XraySuiteMapping,\r\n XrayOperationResult,\r\n XrayBulkResult,\r\n XraySuiteStatus,\r\n XrayCaseStatus,\r\n XraySyncStatus,\r\n} from '../types/xray.js';\r\n\r\nconst logger = createChildLogger('xray-service');\r\n\r\n/**\r\n * Computes a content hash for change detection.\r\n */\r\nfunction contentHash(obj: unknown): string {\r\n return crypto.createHash('sha256').update(JSON.stringify(obj)).digest('hex').slice(0, 16);\r\n}\r\n\r\n/**\r\n * Computes a hash for a suite (name + description + tags).\r\n */\r\nfunction suiteHash(suite: TestSuite): string {\r\n return contentHash({ name: suite.name, description: suite.description, tags: suite.tags });\r\n}\r\n\r\n/**\r\n * Computes a hash for a case (name + description + tags + priority + steps).\r\n */\r\nfunction caseHash(tc: TestCase): string {\r\n return contentHash({\r\n name: tc.name,\r\n description: tc.description,\r\n tags: tc.tags,\r\n priority: tc.priority,\r\n steps: tc.steps.map((s) => ({ instruction: s.instruction, code: s.generatedCode })),\r\n });\r\n}\r\n\r\nexport class XrayService {\r\n private readonly client: XrayClient;\r\n private readonly rootDir: string;\r\n private readonly testsDir: string;\r\n private readonly projectKey: string;\r\n\r\n constructor(rootDir: string, config: XrayClientConfig) {\r\n this.rootDir = rootDir;\r\n this.testsDir = `${rootDir}/tests`;\r\n this.projectKey = config.projectKey.trim().toUpperCase();\r\n this.client = new XrayClient(config);\r\n }\r\n\r\n /** Read mapping and ensure projectKey is always set from config */\r\n private async readMapping(): Promise<XrayMappingFile> {\r\n const mapping = await readXrayMapping(this.rootDir);\r\n if (!mapping.projectKey) {\r\n mapping.projectKey = this.projectKey;\r\n }\r\n return mapping;\r\n }\r\n\r\n // ─── Status queries ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Returns the Xray sync status for all suites.\r\n */\r\n async getAllStatuses(): Promise<XraySuiteStatus[]> {\r\n const mapping = await this.readMapping();\r\n const suites = await listSuites(this.testsDir);\r\n const statuses: XraySuiteStatus[] = [];\r\n\r\n for (const suite of suites) {\r\n statuses.push(await this.getSuiteStatus(suite, mapping));\r\n }\r\n\r\n return statuses;\r\n }\r\n\r\n /**\r\n * Returns the Xray sync status for a single suite.\r\n */\r\n async getSuiteStatusById(suiteId: string): Promise<XraySuiteStatus | null> {\r\n const suiteDir = await findSuiteDirById(this.testsDir, suiteId);\r\n if (!suiteDir) return null;\r\n\r\n const suite = await readSuite(suiteDir);\r\n const mapping = await this.readMapping();\r\n return this.getSuiteStatus(suite, mapping);\r\n }\r\n\r\n private async getSuiteStatus(suite: TestSuite, mapping: XrayMappingFile): Promise<XraySuiteStatus> {\r\n const sm = findSuiteMapping(mapping, suite.id);\r\n const suiteDir = await findSuiteDirById(this.testsDir, suite.id);\r\n const cases = suiteDir ? await listCases(suiteDir) : [];\r\n\r\n let suiteStatus: XraySyncStatus = 'not-created';\r\n if (sm) {\r\n const currentHash = suiteHash(suite);\r\n suiteStatus = currentHash === sm.lastSyncHash ? 'synced' : 'update-pending';\r\n }\r\n\r\n const caseStatuses: XrayCaseStatus[] = cases.map((tc) => {\r\n const cm = sm?.cases.find((c) => c.caseId === tc.id);\r\n let status: XraySyncStatus = 'not-created';\r\n if (cm) {\r\n const currentHash = caseHash(tc);\r\n status = currentHash === cm.lastSyncHash ? 'synced' : 'update-pending';\r\n }\r\n return {\r\n caseId: tc.id,\r\n status,\r\n xrayTestId: cm?.xrayTestId ?? null,\r\n lastSyncedAt: cm?.lastSyncedAt ?? null,\r\n };\r\n });\r\n\r\n return {\r\n suiteId: suite.id,\r\n status: suiteStatus,\r\n xrayTestSetId: sm?.xrayTestSetId ?? null,\r\n lastSyncedAt: sm?.lastSyncedAt ?? null,\r\n cases: caseStatuses,\r\n };\r\n }\r\n\r\n // ─── Create operations ─────────────────────────────────────────────────────\r\n\r\n /**\r\n * Creates ALL suites and their cases in Xray. Skips already-created items.\r\n */\r\n async createAll(): Promise<XrayBulkResult> {\r\n const suites = await listSuites(this.testsDir);\r\n const allResults: XrayOperationResult[] = [];\r\n\r\n for (const suite of suites) {\r\n const results = await this.createSuite(suite.id);\r\n allResults.push(...results.results);\r\n }\r\n\r\n return this.summarizeResults(allResults);\r\n }\r\n\r\n /**\r\n * Creates a single suite and its cases in Xray.\r\n * For Xray Cloud: uses GraphQL createTest (with steps + folder) then createTestSet (with links).\r\n * This creates everything in one shot — no deferred operations needed.\r\n */\r\n async createSuite(suiteId: string): Promise<XrayBulkResult> {\r\n let mapping = await this.readMapping();\r\n const suiteDir = await findSuiteDirById(this.testsDir, suiteId);\r\n if (!suiteDir) {\r\n return this.summarizeResults([{\r\n success: false, suiteId, action: 'failed', error: 'Suite not found',\r\n }]);\r\n }\r\n\r\n const suite = await readSuite(suiteDir);\r\n const cases = await listCases(suiteDir);\r\n const results: XrayOperationResult[] = [];\r\n\r\n // Check if suite already mapped — delegate to sync so changes get pushed\r\n let sm = findSuiteMapping(mapping, suiteId);\r\n if (sm) {\r\n logger.info({ suiteId }, 'Suite already mapped in Xray — delegating to sync');\r\n return this.syncSuite(suiteId);\r\n }\r\n\r\n // Step 1: Create all test cases (with steps + folder placement via GraphQL)\r\n const folderPath = `/${suite.name}`;\r\n const createdTestIssueIds: string[] = [];\r\n\r\n for (const tc of cases) {\r\n const existing = findCaseMapping(mapping, tc.id);\r\n if (existing) {\r\n results.push({ success: true, caseId: tc.id, xrayKey: existing.caseMapping.xrayTestId, action: 'skipped' });\r\n continue;\r\n }\r\n\r\n try {\r\n const test = await this.client.createTest(tc, suite.name, folderPath);\r\n const now = new Date().toISOString();\r\n const cm = {\r\n caseId: tc.id,\r\n xrayTestId: test.key,\r\n xrayTestIssueId: test.id,\r\n lastSyncedAt: now,\r\n lastSyncHash: caseHash(tc),\r\n };\r\n\r\n // Ensure sm exists for case mapping\r\n if (!sm) {\r\n sm = { suiteId, xrayTestSetId: '', xrayTestSetIssueId: '', lastSyncedAt: now, lastSyncHash: suiteHash(suite), cases: [] };\r\n }\r\n sm = upsertCaseMapping(sm, cm);\r\n mapping = upsertSuiteMapping(mapping, sm);\r\n await writeXrayMapping(this.rootDir, mapping);\r\n\r\n createdTestIssueIds.push(test.id);\r\n results.push({ success: true, caseId: tc.id, xrayKey: test.key, xrayId: test.id, action: 'created' });\r\n logger.info({ caseId: tc.id, xrayKey: test.key, xrayId: test.id }, 'Test created');\r\n } catch (err) {\r\n results.push({\r\n success: false, caseId: tc.id, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n }\r\n\r\n // Step 2: Ensure tests are in the correct folder (backup for folderPath in createTest)\r\n // Collect ALL test {key, id} pairs (including previously created ones)\r\n const allTestPairs: Array<{ key: string; id: string }> = [];\r\n const latestSm = findSuiteMapping(mapping, suiteId);\r\n if (latestSm) {\r\n for (const cm of latestSm.cases) {\r\n allTestPairs.push({ key: cm.xrayTestId, id: cm.xrayTestIssueId });\r\n }\r\n }\r\n if (allTestPairs.length > 0) {\r\n try {\r\n await this.client.createFolderAndAddTests(suite.name, allTestPairs);\r\n logger.info({ folderPath, testCount: allTestPairs.length }, 'Tests organized into folder');\r\n } catch (err) {\r\n logger.warn({ folderPath, err: err instanceof Error ? err.message : String(err) }, 'Folder organization failed (non-fatal)');\r\n }\r\n }\r\n\r\n // Step 3: Create the Test Set (if not yet created) — link all test issueIds\r\n if (!findSuiteMapping(mapping, suiteId)?.xrayTestSetId) {\r\n try {\r\n const testSet = await this.client.createTestSet(suite, createdTestIssueIds.length > 0 ? createdTestIssueIds : undefined);\r\n const now = new Date().toISOString();\r\n sm = {\r\n ...sm!,\r\n xrayTestSetId: testSet.key,\r\n xrayTestSetIssueId: testSet.id,\r\n lastSyncedAt: now,\r\n lastSyncHash: suiteHash(suite),\r\n };\r\n mapping = upsertSuiteMapping(mapping, sm);\r\n await writeXrayMapping(this.rootDir, mapping);\r\n results.push({ success: true, suiteId, xrayKey: testSet.key, action: 'created' });\r\n logger.info({ suiteId, xrayKey: testSet.key, testCount: createdTestIssueIds.length }, 'Test Set created with linked tests');\r\n } catch (err) {\r\n results.push({\r\n success: false, suiteId, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n }\r\n\r\n return this.summarizeResults(results);\r\n }\r\n\r\n /**\r\n * Creates a single test case in Xray. Skips if already created.\r\n */\r\n async createSingleCase(suiteId: string, caseId: string): Promise<XrayBulkResult> {\r\n let mapping = await this.readMapping();\r\n const suiteDir = await findSuiteDirById(this.testsDir, suiteId);\r\n if (!suiteDir) {\r\n return this.summarizeResults([{\r\n success: false, caseId, action: 'failed', error: 'Suite not found',\r\n }]);\r\n }\r\n\r\n const suite = await readSuite(suiteDir);\r\n const cases = await listCases(suiteDir);\r\n const tc = cases.find((c) => c.id === caseId);\r\n if (!tc) {\r\n return this.summarizeResults([{\r\n success: false, caseId, action: 'failed', error: 'Test case not found',\r\n }]);\r\n }\r\n\r\n // Ensure suite (Test Set) is created first\r\n let sm = findSuiteMapping(mapping, suiteId);\r\n if (!sm) {\r\n try {\r\n const testSet = await this.client.createTestSet(suite);\r\n const now = new Date().toISOString();\r\n sm = {\r\n suiteId,\r\n xrayTestSetId: testSet.key,\r\n xrayTestSetIssueId: testSet.id,\r\n lastSyncedAt: now,\r\n lastSyncHash: suiteHash(suite),\r\n cases: [],\r\n };\r\n mapping = upsertSuiteMapping(mapping, sm);\r\n await writeXrayMapping(this.rootDir, mapping);\r\n } catch (err) {\r\n return this.summarizeResults([{\r\n success: false, suiteId, action: 'failed',\r\n error: `Failed to create parent Test Set: ${err instanceof Error ? err.message : String(err)}`,\r\n }]);\r\n }\r\n }\r\n\r\n // Create the test case via GraphQL (with steps + folder in one call)\r\n const folderPath = `/${suite.name}`;\r\n const caseResult = await this.createCase(suiteId, tc, suite.name, mapping, sm, folderPath);\r\n\r\n // Ensure test is in the correct folder\r\n if (caseResult.result.xrayKey && caseResult.result.xrayId) {\r\n try {\r\n await this.client.createFolderAndAddTests(suite.name, [\r\n { key: caseResult.result.xrayKey, id: caseResult.result.xrayId },\r\n ]);\r\n } catch (err) {\r\n logger.warn({ err: err instanceof Error ? err.message : String(err) }, 'Folder organization failed for single case (non-fatal)');\r\n }\r\n }\r\n\r\n // Link to test set if we have the Xray issueId\r\n if (caseResult.result.xrayId && sm.xrayTestSetIssueId) {\r\n try {\r\n await this.client.linkTestsToTestSet(\r\n { key: sm.xrayTestSetId, id: sm.xrayTestSetIssueId },\r\n [{ key: caseResult.result.xrayKey ?? '', id: caseResult.result.xrayId }],\r\n );\r\n } catch (err) {\r\n logger.warn({ err: err instanceof Error ? err.message : String(err) }, 'Failed to link test to test set');\r\n }\r\n }\r\n\r\n return this.summarizeResults([caseResult.result]);\r\n }\r\n\r\n private async createCase(\r\n _suiteId: string,\r\n tc: TestCase,\r\n suiteName: string,\r\n mapping: XrayMappingFile,\r\n sm: XraySuiteMapping,\r\n folderPath?: string,\r\n ): Promise<{ result: XrayOperationResult; mapping: XrayMappingFile }> {\r\n const existing = findCaseMapping(mapping, tc.id);\r\n if (existing) {\r\n return {\r\n result: {\r\n success: true, caseId: tc.id, xrayKey: existing.caseMapping.xrayTestId, action: 'skipped',\r\n },\r\n mapping,\r\n };\r\n }\r\n\r\n try {\r\n const test = await this.client.createTest(tc, suiteName, folderPath);\r\n const now = new Date().toISOString();\r\n const cm = {\r\n caseId: tc.id,\r\n xrayTestId: test.key,\r\n xrayTestIssueId: test.id,\r\n lastSyncedAt: now,\r\n lastSyncHash: caseHash(tc),\r\n };\r\n const updatedSm = upsertCaseMapping(sm, cm);\r\n const updatedMapping = upsertSuiteMapping(mapping, updatedSm);\r\n await writeXrayMapping(this.rootDir, updatedMapping);\r\n logger.info({ caseId: tc.id, xrayKey: test.key, xrayId: test.id }, 'Test created');\r\n return {\r\n result: { success: true, caseId: tc.id, xrayKey: test.key, xrayId: test.id, action: 'created' },\r\n mapping: updatedMapping,\r\n };\r\n } catch (err) {\r\n return {\r\n result: {\r\n success: false, caseId: tc.id, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n },\r\n mapping,\r\n };\r\n }\r\n }\r\n\r\n // ─── Sync operations ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Syncs ALL suites and cases. Only updates items that have changed.\r\n */\r\n async syncAll(): Promise<XrayBulkResult> {\r\n const suites = await listSuites(this.testsDir);\r\n const allResults: XrayOperationResult[] = [];\r\n\r\n for (const suite of suites) {\r\n const results = await this.syncSuite(suite.id);\r\n allResults.push(...results.results);\r\n }\r\n\r\n return this.summarizeResults(allResults);\r\n }\r\n\r\n /**\r\n * Syncs a single suite and its cases. Only updates changed items.\r\n */\r\n async syncSuite(suiteId: string): Promise<XrayBulkResult> {\r\n let mapping = await this.readMapping();\r\n const suiteDir = await findSuiteDirById(this.testsDir, suiteId);\r\n if (!suiteDir) {\r\n return this.summarizeResults([{\r\n success: false, suiteId, action: 'failed', error: 'Suite not found',\r\n }]);\r\n }\r\n\r\n const suite = await readSuite(suiteDir);\r\n const cases = await listCases(suiteDir);\r\n const results: XrayOperationResult[] = [];\r\n\r\n let sm = findSuiteMapping(mapping, suiteId);\r\n if (!sm) {\r\n // Not created yet — create instead\r\n return this.createSuite(suiteId);\r\n }\r\n\r\n // If Test Set was never created (xrayTestSetId is empty), create it now\r\n if (!sm.xrayTestSetId) {\r\n try {\r\n const allIssueIds = sm.cases.map((c) => c.xrayTestIssueId).filter(Boolean);\r\n const testSet = await this.client.createTestSet(suite, allIssueIds.length > 0 ? allIssueIds : undefined);\r\n const now = new Date().toISOString();\r\n sm = {\r\n ...sm,\r\n xrayTestSetId: testSet.key,\r\n xrayTestSetIssueId: testSet.id,\r\n lastSyncedAt: now,\r\n lastSyncHash: suiteHash(suite),\r\n };\r\n mapping = upsertSuiteMapping(mapping, sm);\r\n await writeXrayMapping(this.rootDir, mapping);\r\n results.push({ success: true, suiteId, xrayKey: testSet.key, action: 'created' });\r\n logger.info({ suiteId, xrayKey: testSet.key }, 'Test Set created during sync (was missing)');\r\n } catch (err) {\r\n results.push({\r\n success: false, suiteId, action: 'failed',\r\n error: `Failed to create Test Set: ${err instanceof Error ? err.message : String(err)}`,\r\n });\r\n // Continue with case sync even if Test Set creation failed\r\n }\r\n }\r\n\r\n // Sync suite metadata if changed\r\n const currentSuiteHash = suiteHash(suite);\r\n if (sm.xrayTestSetId && currentSuiteHash !== sm.lastSyncHash) {\r\n try {\r\n await this.client.updateTestSet(sm.xrayTestSetId, suite);\r\n sm = {\r\n ...sm,\r\n lastSyncedAt: new Date().toISOString(),\r\n lastSyncHash: currentSuiteHash,\r\n };\r\n mapping = upsertSuiteMapping(mapping, sm);\r\n await writeXrayMapping(this.rootDir, mapping);\r\n results.push({ success: true, suiteId, xrayKey: sm.xrayTestSetId, action: 'synced' });\r\n } catch (err) {\r\n results.push({\r\n success: false, suiteId, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n } else if (currentSuiteHash === sm.lastSyncHash) {\r\n results.push({ success: true, suiteId, xrayKey: sm.xrayTestSetId, action: 'skipped' });\r\n }\r\n\r\n // Sync cases\r\n const newTestKeys: string[] = [];\r\n for (const tc of cases) {\r\n const cm = sm.cases.find((c) => c.caseId === tc.id);\r\n\r\n if (!cm) {\r\n // Case not created yet — create it\r\n const caseResult = await this.createCase(suiteId, tc, suite.name, mapping, sm);\r\n results.push(caseResult.result);\r\n mapping = caseResult.mapping;\r\n sm = findSuiteMapping(mapping, suiteId) ?? sm;\r\n if (caseResult.result.xrayKey) newTestKeys.push(caseResult.result.xrayKey);\r\n continue;\r\n }\r\n\r\n // Check if case changed\r\n const currentCaseHash = caseHash(tc);\r\n if (currentCaseHash === cm.lastSyncHash) {\r\n results.push({\r\n success: true, caseId: tc.id, xrayKey: cm.xrayTestId, action: 'skipped',\r\n });\r\n continue;\r\n }\r\n\r\n // Update the case\r\n try {\r\n await this.client.updateTest({ key: cm.xrayTestId, id: cm.xrayTestIssueId }, tc, suite.name);\r\n const updatedCm = {\r\n ...cm,\r\n lastSyncedAt: new Date().toISOString(),\r\n lastSyncHash: currentCaseHash,\r\n };\r\n const updatedSm = upsertCaseMapping(sm, updatedCm);\r\n mapping = upsertSuiteMapping(mapping, updatedSm);\r\n sm = updatedSm;\r\n await writeXrayMapping(this.rootDir, mapping);\r\n results.push({\r\n success: true, caseId: tc.id, xrayKey: cm.xrayTestId, action: 'synced',\r\n });\r\n } catch (err) {\r\n results.push({\r\n success: false, caseId: tc.id, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n }\r\n\r\n // Link newly created tests to test set and organize into folder\r\n if (newTestKeys.length > 0) {\r\n // Link to test set\r\n if (sm.xrayTestSetId && sm.xrayTestSetIssueId) {\r\n try {\r\n const updatedSm = findSuiteMapping(mapping, suiteId);\r\n const newTests = newTestKeys\r\n .map((key) => {\r\n const cm = updatedSm?.cases.find((c) => c.xrayTestId === key);\r\n return cm ? { key: cm.xrayTestId, id: cm.xrayTestIssueId } : null;\r\n })\r\n .filter((t): t is { key: string; id: string } => t !== null);\r\n\r\n if (newTests.length > 0) {\r\n await this.client.linkTestsToTestSet(\r\n { key: sm.xrayTestSetId, id: sm.xrayTestSetIssueId },\r\n newTests,\r\n );\r\n\r\n // Add newly created tests to the suite folder\r\n try {\r\n await this.client.createFolderAndAddTests(suite.name, newTests);\r\n } catch (folderErr) {\r\n logger.warn({ err: folderErr instanceof Error ? folderErr.message : String(folderErr) }, 'Folder organization failed for synced tests (non-fatal)');\r\n }\r\n }\r\n } catch (err) {\r\n logger.warn({ err }, 'Failed to link new tests to test set');\r\n }\r\n }\r\n }\r\n\r\n return this.summarizeResults(results);\r\n }\r\n\r\n /**\r\n * Syncs a single test case. Only updates if changed.\r\n */\r\n async syncSingleCase(suiteId: string, caseId: string): Promise<XrayBulkResult> {\r\n const mapping = await this.readMapping();\r\n const suiteDir = await findSuiteDirById(this.testsDir, suiteId);\r\n if (!suiteDir) {\r\n return this.summarizeResults([{\r\n success: false, caseId, action: 'failed', error: 'Suite not found',\r\n }]);\r\n }\r\n\r\n const suite = await readSuite(suiteDir);\r\n const cases = await listCases(suiteDir);\r\n const tc = cases.find((c) => c.id === caseId);\r\n if (!tc) {\r\n return this.summarizeResults([{\r\n success: false, caseId, action: 'failed', error: 'Test case not found',\r\n }]);\r\n }\r\n\r\n const existing = findCaseMapping(mapping, caseId);\r\n if (!existing) {\r\n // Not created yet — create it\r\n return this.createSingleCase(suiteId, caseId);\r\n }\r\n\r\n // Check if changed\r\n const currentHash = caseHash(tc);\r\n if (currentHash === existing.caseMapping.lastSyncHash) {\r\n return this.summarizeResults([{\r\n success: true, caseId, xrayKey: existing.caseMapping.xrayTestId, action: 'skipped',\r\n }]);\r\n }\r\n\r\n try {\r\n await this.client.updateTest({ key: existing.caseMapping.xrayTestId, id: existing.caseMapping.xrayTestIssueId }, tc, suite.name);\r\n const updatedCm = {\r\n ...existing.caseMapping,\r\n lastSyncedAt: new Date().toISOString(),\r\n lastSyncHash: currentHash,\r\n };\r\n const updatedSm = upsertCaseMapping(existing.suiteMapping, updatedCm);\r\n const updatedMapping = upsertSuiteMapping(mapping, updatedSm);\r\n await writeXrayMapping(this.rootDir, updatedMapping);\r\n\r\n return this.summarizeResults([{\r\n success: true, caseId, xrayKey: existing.caseMapping.xrayTestId, action: 'synced',\r\n }]);\r\n } catch (err) {\r\n return this.summarizeResults([{\r\n success: false, caseId, action: 'failed',\r\n error: err instanceof Error ? err.message : String(err),\r\n }]);\r\n }\r\n }\r\n\r\n // ─── Validate connection ───────────────────────────────────────────────────\r\n\r\n async validate(): Promise<{ valid: boolean; error?: string }> {\r\n return this.client.validate();\r\n }\r\n\r\n // ─── Helpers ───────────────────────────────────────────────────────────────\r\n\r\n private summarizeResults(results: XrayOperationResult[]): XrayBulkResult {\r\n return {\r\n total: results.length,\r\n created: results.filter((r) => r.action === 'created').length,\r\n synced: results.filter((r) => r.action === 'synced').length,\r\n skipped: results.filter((r) => r.action === 'skipped').length,\r\n failed: results.filter((r) => r.action === 'failed').length,\r\n results,\r\n };\r\n }\r\n}\r\n","/**\r\n * Xray routes — Create / Sync test suites and cases to Jira Xray.\r\n *\r\n * GET /api/xray/status — get sync status for all suites\r\n * GET /api/xray/status/:suiteId — get sync status for one suite\r\n * POST /api/xray/create-all — create all suites+cases in Xray\r\n * POST /api/xray/create/suite/:suiteId — create one suite+cases in Xray\r\n * POST /api/xray/create/case/:suiteId/:caseId — create one case in Xray\r\n * POST /api/xray/sync-all — sync all suites+cases to Xray\r\n * POST /api/xray/sync/suite/:suiteId — sync one suite+cases to Xray\r\n * POST /api/xray/sync/case/:suiteId/:caseId — sync one case to Xray\r\n * GET /api/xray/validate — validate Jira/Xray connection\r\n */\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { XrayService } from '../../xray/service.js';\r\nimport type { XrayClientConfig } from '../../xray/client.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('xray-routes');\r\n\r\nfunction getXrayConfig(): XrayClientConfig | null {\r\n const jiraBaseUrl = process.env['JIRA_BASE_URL'];\r\n const jiraEmail = process.env['JIRA_EMAIL'];\r\n const jiraApiToken = process.env['JIRA_API_TOKEN'];\r\n const projectKey = process.env['XRAY_PROJECT_KEY'];\r\n\r\n if (!jiraBaseUrl || !jiraEmail || !jiraApiToken || !projectKey) {\r\n return null;\r\n }\r\n\r\n return {\r\n jiraBaseUrl: jiraBaseUrl.replace(/\\/+$/, ''),\r\n jiraEmail,\r\n jiraApiToken,\r\n projectKey: projectKey.trim().toUpperCase(),\r\n xrayClientId: process.env['XRAY_CLIENT_ID'] ?? undefined,\r\n xrayClientSecret: process.env['XRAY_CLIENT_SECRET'] ?? undefined,\r\n testIssueType: process.env['XRAY_TEST_ISSUE_TYPE'] ?? 'Test',\r\n testSetIssueType: process.env['XRAY_TEST_SET_ISSUE_TYPE'] ?? 'Test Set',\r\n };\r\n}\r\n\r\nexport async function xrayRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n\r\n function createService(): XrayService | null {\r\n const config = getXrayConfig();\r\n if (!config) return null;\r\n return new XrayService(rootDir, config);\r\n }\r\n\r\n function requireService(reply: { status: (code: number) => { send: (body: unknown) => unknown } }): XrayService | null {\r\n const service = createService();\r\n if (!service) {\r\n reply.status(400).send({\r\n error: 'Xray integration not configured',\r\n details: 'Set JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN, and XRAY_PROJECT_KEY in your .env file.',\r\n });\r\n return null;\r\n }\r\n return service;\r\n }\r\n\r\n // GET /api/xray/enabled — check if Jira/Xray env vars are configured\r\n fastify.get('/xray/enabled', async (_req, reply) => {\r\n const config = getXrayConfig();\r\n return reply.send({ enabled: config !== null });\r\n });\r\n\r\n // GET /api/xray/status — all suites sync status\r\n fastify.get('/xray/status', async (_req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n const statuses = await service.getAllStatuses();\r\n return reply.send(statuses);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get Xray status', err);\r\n }\r\n });\r\n\r\n // GET /api/xray/status/:suiteId — single suite sync status\r\n fastify.get<{ Params: { suiteId: string } }>('/xray/status/:suiteId', async (req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n const status = await service.getSuiteStatusById(req.params.suiteId);\r\n if (!status) return reply.status(404).send({ error: 'Suite not found' });\r\n return reply.send(status);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get suite Xray status', err);\r\n }\r\n });\r\n\r\n // POST /api/xray/create-all — create all suites + cases\r\n fastify.post('/xray/create-all', async (_req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n logger.info('Creating all suites and cases in Xray');\r\n const result = await service.createAll();\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to create in Xray', err);\r\n }\r\n });\r\n\r\n // POST /api/xray/create/suite/:suiteId — create one suite + cases\r\n fastify.post<{ Params: { suiteId: string } }>('/xray/create/suite/:suiteId', async (req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n logger.info({ suiteId: req.params.suiteId }, 'Creating suite in Xray');\r\n const result = await service.createSuite(req.params.suiteId);\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to create suite in Xray', err);\r\n }\r\n });\r\n\r\n // POST /api/xray/create/case/:suiteId/:caseId — create one case\r\n fastify.post<{ Params: { suiteId: string; caseId: string } }>(\r\n '/xray/create/case/:suiteId/:caseId',\r\n async (req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n const result = await service.createSingleCase(req.params.suiteId, req.params.caseId);\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to create case in Xray', err);\r\n }\r\n },\r\n );\r\n\r\n // POST /api/xray/sync-all — sync all suites + cases\r\n fastify.post('/xray/sync-all', async (_req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n logger.info('Syncing all suites and cases with Xray');\r\n const result = await service.syncAll();\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to sync with Xray', err);\r\n }\r\n });\r\n\r\n // POST /api/xray/sync/suite/:suiteId — sync one suite + cases\r\n fastify.post<{ Params: { suiteId: string } }>('/xray/sync/suite/:suiteId', async (req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n logger.info({ suiteId: req.params.suiteId }, 'Syncing suite with Xray');\r\n const result = await service.syncSuite(req.params.suiteId);\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to sync suite with Xray', err);\r\n }\r\n });\r\n\r\n // POST /api/xray/sync/case/:suiteId/:caseId — sync one case\r\n fastify.post<{ Params: { suiteId: string; caseId: string } }>(\r\n '/xray/sync/case/:suiteId/:caseId',\r\n async (req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n const result = await service.syncSingleCase(req.params.suiteId, req.params.caseId);\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to sync case with Xray', err);\r\n }\r\n },\r\n );\r\n\r\n // GET /api/xray/validate — validate Jira/Xray connection\r\n fastify.get('/xray/validate', async (_req, reply) => {\r\n const service = requireService(reply);\r\n if (!service) return;\r\n try {\r\n const result = await service.validate();\r\n return reply.send(result);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to validate Xray connection', err);\r\n }\r\n });\r\n}\r\n","/**\r\n * Git Service — wraps simple-git for all repository operations.\r\n *\r\n * Broadcasts real-time progress via WebSocketManager for:\r\n * git:log { step, status, message?, timestamp }\r\n * git:conflict { files: string[] }\r\n * git:operation-done { operation: string }\r\n */\r\nimport simpleGit, { type SimpleGit, type StatusResult } from 'simple-git';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport type { WebSocketManager } from '../server/websocket.js';\r\n\r\nconst logger = createChildLogger('git-service');\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\nexport interface GitStatusResult {\r\n branch: string;\r\n tracking: string | null;\r\n isClean: boolean;\r\n modified: string[];\r\n added: string[];\r\n deleted: string[];\r\n untracked: string[];\r\n staged: string[];\r\n ahead: number;\r\n behind: number;\r\n conflicted: string[];\r\n}\r\n\r\nexport interface GitBranchesResult {\r\n current: string;\r\n all: string[];\r\n remote: string[];\r\n}\r\n\r\nexport interface GitLogEntry {\r\n hash: string;\r\n shortHash: string;\r\n date: string;\r\n message: string;\r\n author: string;\r\n}\r\n\r\nexport interface ConflictContent {\r\n ours: string;\r\n theirs: string;\r\n}\r\n\r\ntype LogStatus = 'running' | 'done' | 'error';\r\n\r\n// ─── Service ──────────────────────────────────────────────────────────────────\r\n\r\nexport class GitService {\r\n private readonly git: SimpleGit;\r\n private readonly rootDir: string;\r\n private readonly wsManager?: WebSocketManager;\r\n\r\n constructor(rootDir: string, wsManager?: WebSocketManager) {\r\n this.rootDir = rootDir;\r\n this.wsManager = wsManager;\r\n this.git = simpleGit({\r\n baseDir: rootDir,\r\n binary: 'git',\r\n maxConcurrentProcesses: 6,\r\n trimmed: false,\r\n });\r\n }\r\n\r\n // ─── Broadcast helpers ────────────────────────────────────────────────────\r\n\r\n private broadcastLog(step: string, status: LogStatus, message?: string): void {\r\n this.wsManager?.broadcast('git:log', { step, status, message, timestamp: Date.now() });\r\n }\r\n\r\n private broadcastConflict(files: string[]): void {\r\n this.wsManager?.broadcast('git:conflict', { files });\r\n }\r\n\r\n private broadcastDone(operation: string): void {\r\n this.wsManager?.broadcast('git:operation-done', { operation });\r\n }\r\n\r\n // ─── Status queries ───────────────────────────────────────────────────────\r\n\r\n async getStatus(): Promise<GitStatusResult> {\r\n const status: StatusResult = await this.git.status();\r\n return {\r\n branch: status.current ?? 'HEAD (detached)',\r\n tracking: status.tracking ?? null,\r\n isClean: status.isClean(),\r\n modified: status.modified,\r\n added: status.created,\r\n deleted: status.deleted,\r\n untracked: status.not_added,\r\n staged: status.staged,\r\n ahead: status.ahead,\r\n behind: status.behind,\r\n conflicted: status.conflicted,\r\n };\r\n }\r\n\r\n async getBranches(): Promise<GitBranchesResult> {\r\n const local = await this.git.branchLocal();\r\n let remote: string[] = [];\r\n try {\r\n const allBranches = await this.git.branch(['-r']);\r\n remote = allBranches.all;\r\n } catch {\r\n // Remote might not be configured\r\n }\r\n return {\r\n current: local.current,\r\n all: local.all,\r\n remote,\r\n };\r\n }\r\n\r\n // ─── Branch operations ────────────────────────────────────────────────────\r\n\r\n async checkout(branch: string): Promise<void> {\r\n this.broadcastLog('Checkout branch', 'running');\r\n try {\r\n await this.git.checkout(branch);\r\n this.broadcastLog('Checkout branch', 'done', branch);\r\n logger.info({ branch }, 'Switched branch');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n this.broadcastLog('Checkout branch', 'error', msg);\r\n throw err;\r\n }\r\n }\r\n\r\n // ─── Commit ───────────────────────────────────────────────────────────────\r\n\r\n async commit(message: string): Promise<string> {\r\n this.broadcastLog('Stage files', 'running');\r\n await this.git.add('.');\r\n this.broadcastLog('Stage files', 'done');\r\n\r\n this.broadcastLog('Create commit', 'running');\r\n try {\r\n const result = await this.git.commit(message);\r\n const hash = result.commit || 'unknown';\r\n this.broadcastLog('Create commit', 'done', hash);\r\n this.broadcastDone('commit');\r\n logger.info({ hash, message }, 'Commit created');\r\n return hash;\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n this.broadcastLog('Create commit', 'error', msg);\r\n throw err;\r\n }\r\n }\r\n\r\n // ─── Pull ─────────────────────────────────────────────────────────────────\r\n\r\n async pull(rebase = false): Promise<void> {\r\n const label = rebase ? 'Pull with rebase' : 'Pull latest changes';\r\n this.broadcastLog(label, 'running');\r\n try {\r\n const opts = rebase ? { '--rebase': null as unknown as undefined } : {};\r\n await this.git.pull(undefined, undefined, opts);\r\n this.broadcastLog(label, 'done', rebase ? 'Rebase successful' : 'Pull successful');\r\n this.broadcastDone('pull');\r\n logger.info({ rebase }, 'Pull completed');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n if (msg.includes('CONFLICT') || msg.includes('conflict') || msg.includes('could not apply')) {\r\n this.broadcastLog(label, 'error', 'Merge conflict detected');\r\n const status = await this.git.status();\r\n if (status.conflicted.length > 0) {\r\n this.broadcastConflict(status.conflicted);\r\n }\r\n } else {\r\n this.broadcastLog(label, 'error', msg);\r\n }\r\n throw err;\r\n }\r\n }\r\n\r\n // ─── Push ─────────────────────────────────────────────────────────────────\r\n\r\n async push(): Promise<void> {\r\n this.broadcastLog('Push to origin', 'running');\r\n try {\r\n await this.git.push();\r\n this.broadcastLog('Push to origin', 'done');\r\n this.broadcastDone('push');\r\n logger.info('Push completed');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n this.broadcastLog('Push to origin', 'error', msg);\r\n throw err;\r\n }\r\n }\r\n\r\n // ─── Full Sync (the recommended combined flow) ────────────────────────────\r\n\r\n async fullSync(message: string): Promise<void> {\r\n try {\r\n // Step 1: Pull with rebase\r\n this.broadcastLog('Pull with rebase', 'running');\r\n try {\r\n await this.git.pull(undefined, undefined, { '--rebase': null as unknown as undefined });\r\n this.broadcastLog('Pull with rebase', 'done', 'Rebase successful');\r\n } catch (pullErr) {\r\n const msg = pullErr instanceof Error ? pullErr.message : String(pullErr);\r\n if (msg.includes('CONFLICT') || msg.includes('conflict') || msg.includes('could not apply')) {\r\n this.broadcastLog('Pull with rebase', 'error', 'Merge conflict detected');\r\n const status = await this.git.status();\r\n if (status.conflicted.length > 0) {\r\n this.broadcastConflict(status.conflicted);\r\n }\r\n throw pullErr;\r\n }\r\n // Non-conflict pull error (e.g., no remote) — continue anyway\r\n this.broadcastLog('Pull with rebase', 'done', 'Skipped (no remote or up to date)');\r\n }\r\n\r\n // Step 2: Stage all files\r\n this.broadcastLog('Stage files', 'running');\r\n await this.git.add('.');\r\n this.broadcastLog('Stage files', 'done');\r\n\r\n // Step 3: Commit\r\n this.broadcastLog('Create commit', 'running');\r\n const status = await this.git.status();\r\n if (status.isClean()) {\r\n this.broadcastLog('Create commit', 'done', 'Nothing to commit (clean)');\r\n } else {\r\n const result = await this.git.commit(message);\r\n this.broadcastLog('Create commit', 'done', result.commit || 'done');\r\n }\r\n\r\n // Step 4: Push\r\n this.broadcastLog('Push to origin', 'running');\r\n try {\r\n await this.git.push();\r\n this.broadcastLog('Push to origin', 'done');\r\n } catch (pushErr) {\r\n const msg = pushErr instanceof Error ? pushErr.message : String(pushErr);\r\n this.broadcastLog('Push to origin', 'error', msg);\r\n throw pushErr;\r\n }\r\n\r\n this.broadcastDone('full-sync');\r\n logger.info('Full sync completed');\r\n } catch (err) {\r\n this.broadcastDone('full-sync');\r\n throw err;\r\n }\r\n }\r\n\r\n // ─── Log / History ────────────────────────────────────────────────────────\r\n\r\n async getLog(count = 30): Promise<GitLogEntry[]> {\r\n const log = await this.git.log({ maxCount: count });\r\n return log.all.map((entry) => ({\r\n hash: entry.hash,\r\n shortHash: entry.hash.slice(0, 7),\r\n date: entry.date,\r\n message: entry.message,\r\n author: entry.author_name,\r\n }));\r\n }\r\n\r\n // ─── Diff ─────────────────────────────────────────────────────────────────\r\n\r\n async getDiff(staged = false): Promise<string> {\r\n if (staged) {\r\n return this.git.diff(['--cached']);\r\n }\r\n // Show both staged + unstaged diff\r\n const unstaged = await this.git.diff();\r\n const stagedDiff = await this.git.diff(['--cached']);\r\n return [stagedDiff, unstaged].filter(Boolean).join('\\n');\r\n }\r\n\r\n // ─── Conflict handling ────────────────────────────────────────────────────\r\n\r\n async getConflictedFiles(): Promise<string[]> {\r\n const status = await this.git.status();\r\n return status.conflicted;\r\n }\r\n\r\n async getFileConflictContent(filePath: string): Promise<ConflictContent> {\r\n const fullPath = path.join(this.rootDir, filePath);\r\n const content = await fs.readFile(fullPath, 'utf-8');\r\n\r\n let ours = '';\r\n let theirs = '';\r\n let section: 'none' | 'ours' | 'theirs' = 'none';\r\n\r\n for (const line of content.split('\\n')) {\r\n if (line.startsWith('<<<<<<<')) {\r\n section = 'ours';\r\n continue;\r\n }\r\n if (line.startsWith('=======')) {\r\n section = 'theirs';\r\n continue;\r\n }\r\n if (line.startsWith('>>>>>>>')) {\r\n section = 'none';\r\n continue;\r\n }\r\n\r\n if (section === 'ours') {\r\n ours += line + '\\n';\r\n } else if (section === 'theirs') {\r\n theirs += line + '\\n';\r\n }\r\n }\r\n\r\n return { ours: ours.trimEnd(), theirs: theirs.trimEnd() };\r\n }\r\n\r\n async resolveConflict(filePath: string, resolvedContent: string): Promise<void> {\r\n const fullPath = path.join(this.rootDir, filePath);\r\n await fs.writeFile(fullPath, resolvedContent, 'utf-8');\r\n await this.git.add(filePath);\r\n logger.info({ filePath }, 'Conflict resolved');\r\n }\r\n\r\n async continueRebase(): Promise<void> {\r\n this.broadcastLog('Continuing rebase...', 'running');\r\n try {\r\n await this.git.rebase(['--continue']);\r\n this.broadcastLog('Rebase continued', 'done');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n this.broadcastLog(`Rebase continue failed: ${msg}`, 'error');\r\n throw err;\r\n }\r\n }\r\n\r\n async abortRebase(): Promise<void> {\r\n this.broadcastLog('Aborting rebase...', 'running');\r\n try {\r\n await this.git.rebase(['--abort']);\r\n this.broadcastLog('Rebase aborted', 'done');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n this.broadcastLog(`Rebase abort failed: ${msg}`, 'error');\r\n throw err;\r\n }\r\n }\r\n}\r\n","/**\r\n * Git AI helpers — generate commit messages and resolve conflicts using LLM.\r\n */\r\nimport { createProvider } from '../ai/router.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\nimport type { PageContext } from '../types/ai.js';\r\n\r\nconst logger = createChildLogger('git-ai');\r\n\r\n/** Minimal PageContext so we can reuse the AIProvider.generateCode() interface. */\r\nfunction fakePageContext(content: string): PageContext {\r\n return {\r\n url: 'git://local',\r\n title: 'Git Operations',\r\n interactiveElements: '',\r\n htmlSnapshot: content,\r\n previousSteps: [],\r\n };\r\n}\r\n\r\n/**\r\n * Generates a conventional commit message from a git diff.\r\n * Returns a single-line commit message (or short multi-line for complex diffs).\r\n */\r\nexport async function generateCommitMessage(diff: string): Promise<string> {\r\n if (!diff.trim()) {\r\n return 'chore: update files';\r\n }\r\n\r\n // Truncate very large diffs to stay within token limits\r\n const maxDiffLen = 8000;\r\n const truncatedDiff = diff.length > maxDiffLen\r\n ? diff.slice(0, maxDiffLen) + '\\n... (diff truncated)'\r\n : diff;\r\n\r\n const instruction = [\r\n 'You are a developer writing a git commit message. Write it the way a human would — natural, specific, and varied.',\r\n 'Use Conventional Commits format: type(scope): description',\r\n 'Types: feat, fix, chore, refactor, docs, test, style, perf, ci, build',\r\n '',\r\n 'Rules:',\r\n '- Be specific about WHAT changed, not generic',\r\n '- Vary your word choices — don\\'t always start with \"add\", \"update\", or \"fix\"',\r\n '- Use active voice: \"streamline login flow\" not \"login flow was streamlined\"',\r\n '- Keep it under 72 characters',\r\n '- Sound like a real developer, not a robot',\r\n '- Each message should feel unique even for similar changes',\r\n '',\r\n 'Bad examples (too generic): \"update files\", \"fix bug\", \"make changes\"',\r\n 'Good examples: \"feat(cart): wire up quantity stepper with debounced save\", \"fix(auth): guard against expired refresh tokens on silent renew\", \"refactor: collapse duplicated validation into shared helper\"',\r\n '',\r\n 'Return ONLY the commit message. No quotes, no explanation, no markdown.',\r\n '',\r\n 'Diff:',\r\n '```',\r\n truncatedDiff,\r\n '```',\r\n ].join('\\n');\r\n\r\n try {\r\n const provider = createProvider(undefined, { temperature: 0.4 });\r\n const result = await provider.generateCode(instruction, fakePageContext(truncatedDiff));\r\n // Clean up: remove surrounding quotes, backticks, \"Commit message:\" prefixes\r\n let cleaned = result.trim();\r\n cleaned = cleaned.replace(/^[\"'`]+|[\"'`]+$/g, '');\r\n cleaned = cleaned.replace(/^(commit message:?\\s*)/i, '');\r\n // Take first line only\r\n cleaned = cleaned.split('\\n')[0].trim();\r\n logger.info({ messageLength: cleaned.length }, 'AI commit message generated');\r\n return cleaned || 'chore: update files';\r\n } catch (err) {\r\n logger.warn({ err: err instanceof Error ? err.message : String(err) }, 'AI commit message generation failed');\r\n return 'chore: update files';\r\n }\r\n}\r\n\r\n/**\r\n * Resolves a merge conflict using AI by merging both versions intelligently.\r\n * Returns the resolved file content.\r\n */\r\nexport async function resolveConflictWithAI(\r\n ours: string,\r\n theirs: string,\r\n filePath: string,\r\n): Promise<string> {\r\n const instruction = [\r\n `Merge these two conflicting versions of the file \"${filePath}\" into a single resolved version.`,\r\n 'Combine changes from both sides intelligently. Preserve the intent of both changes.',\r\n 'Return ONLY the merged file content, no explanation, no markdown code blocks.',\r\n '',\r\n '=== LOCAL VERSION (ours) ===',\r\n ours,\r\n '',\r\n '=== INCOMING VERSION (theirs) ===',\r\n theirs,\r\n ].join('\\n');\r\n\r\n const context = fakePageContext(`Conflict in: ${filePath}\\n\\nOurs:\\n${ours}\\n\\nTheirs:\\n${theirs}`);\r\n\r\n try {\r\n const provider = createProvider(undefined, { temperature: 0.4 });\r\n let result = await provider.generateCode(instruction, context);\r\n // Strip markdown code fences if present\r\n result = result.replace(/^```[\\w]*\\n?/, '').replace(/\\n?```$/, '');\r\n logger.info({ filePath, resultLength: result.length }, 'AI conflict resolution generated');\r\n return result;\r\n } catch (err) {\r\n logger.warn({ filePath, err: err instanceof Error ? err.message : String(err) }, 'AI conflict resolution failed');\r\n throw err;\r\n }\r\n}\r\n","/**\r\n * Git routes — Git Control Center API endpoints.\r\n *\r\n * GET /api/git/status — file changes, branch, status\r\n * GET /api/git/branches — local + remote branches\r\n * POST /api/git/checkout — switch branch\r\n * POST /api/git/commit — stage all + commit\r\n * POST /api/git/pull — pull (optional rebase)\r\n * POST /api/git/push — push to remote\r\n * POST /api/git/full-sync — combined pull+commit+push\r\n * GET /api/git/log — commit history\r\n * GET /api/git/diff — file diff\r\n * POST /api/git/resolve-conflict — write resolved content\r\n * POST /api/git/continue-rebase — continue after conflict\r\n * POST /api/git/abort-rebase — abort rebase\r\n * POST /api/git/generate-commit-message — AI commit message\r\n * POST /api/git/resolve-conflict-ai — AI conflict resolution\r\n */\r\nimport path from 'path';\r\nimport { z } from 'zod';\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { GitService } from '../../git/service.js';\r\nimport { generateCommitMessage, resolveConflictWithAI } from '../../git/ai.js';\r\nimport { sendError } from '../utils.js';\r\nimport { createChildLogger } from '../../utils/logger.js';\r\n\r\nconst logger = createChildLogger('git-routes');\r\n\r\nconst CheckoutBody = z.object({ branch: z.string().min(1) });\r\nconst CommitBody = z.object({ message: z.string().min(1) });\r\nconst PullBody = z.object({ rebase: z.boolean().optional() });\r\nconst FullSyncBody = z.object({ message: z.string().min(1) });\r\nconst ResolveConflictBody = z.object({ filePath: z.string().min(1), content: z.string() });\r\nconst ResolveConflictAIBody = z.object({\r\n filePath: z.string().min(1),\r\n ours: z.string(),\r\n theirs: z.string(),\r\n});\r\n\r\nexport async function gitRoutes(fastify: FastifyInstance): Promise<void> {\r\n const rootDir = fastify.rootDir;\r\n const wsManager = fastify.wsManager;\r\n const service = new GitService(rootDir, wsManager);\r\n\r\n /** Check if rootDir is inside a git repo. Cache result to avoid repeated fs checks. */\r\n let _isGitRepo: boolean | null = null;\r\n const isGitRepo = async (): Promise<boolean> => {\r\n if (_isGitRepo !== null) return _isGitRepo;\r\n try {\r\n await service.getStatus();\r\n _isGitRepo = true;\r\n } catch {\r\n _isGitRepo = false;\r\n logger.info('Project directory is not a git repository — git features disabled');\r\n }\r\n return _isGitRepo;\r\n };\r\n\r\n const NOT_A_REPO = { error: 'not-a-git-repo', message: 'Project directory is not a git repository. Run \"git init\" to enable git features.' };\r\n\r\n // ─── Status & Info ──────────────────────────────────────────────────────\r\n\r\n // GET /api/git/status\r\n fastify.get('/git/status', async (_req, reply) => {\r\n try {\r\n if (!(await isGitRepo())) return reply.code(200).send({ branch: '', tracking: null, isClean: true, modified: [], added: [], deleted: [], untracked: [], staged: [], ahead: 0, behind: 0, conflicted: [], notARepo: true });\r\n const status = await service.getStatus();\r\n return reply.send(status);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get git status', err);\r\n }\r\n });\r\n\r\n // GET /api/git/branches\r\n fastify.get('/git/branches', async (_req, reply) => {\r\n try {\r\n if (!(await isGitRepo())) return reply.code(200).send({ current: '', all: [], remote: [] });\r\n const branches = await service.getBranches();\r\n return reply.send(branches);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get branches', err);\r\n }\r\n });\r\n\r\n // GET /api/git/log\r\n fastify.get<{ Querystring: { count?: string } }>('/git/log', async (req, reply) => {\r\n try {\r\n if (!(await isGitRepo())) return reply.code(200).send([]);\r\n const count = req.query.count ? parseInt(req.query.count, 10) : undefined;\r\n const log = await service.getLog(count);\r\n return reply.send(log);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get git log', err);\r\n }\r\n });\r\n\r\n // GET /api/git/diff\r\n fastify.get<{ Querystring: { staged?: string } }>('/git/diff', async (req, reply) => {\r\n try {\r\n const staged = req.query.staged === 'true';\r\n const diff = await service.getDiff(staged);\r\n return reply.send({ diff });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get diff', err);\r\n }\r\n });\r\n\r\n // ─── Branch ─────────────────────────────────────────────────────────────\r\n\r\n // POST /api/git/checkout\r\n fastify.post('/git/checkout', async (req, reply) => {\r\n const parsed = CheckoutBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n await service.checkout(parsed.data.branch);\r\n return reply.send({ success: true, branch: parsed.data.branch });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to checkout branch', err);\r\n }\r\n });\r\n\r\n // ─── Core operations ────────────────────────────────────────────────────\r\n\r\n // POST /api/git/commit\r\n fastify.post('/git/commit', async (req, reply) => {\r\n const parsed = CommitBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n const hash = await service.commit(parsed.data.message);\r\n return reply.send({ success: true, hash });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to commit', err);\r\n }\r\n });\r\n\r\n // POST /api/git/pull\r\n fastify.post('/git/pull', async (req, reply) => {\r\n const parsed = PullBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n await service.pull(parsed.data.rebase);\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n // If conflict, return 409 with conflicted files\r\n const status = await service.getStatus().catch(() => null);\r\n if (status && status.conflicted.length > 0) {\r\n return reply.status(409).send({ error: 'Merge conflict', conflicted: status.conflicted });\r\n }\r\n return sendError(reply, 500, 'Failed to pull', err);\r\n }\r\n });\r\n\r\n // POST /api/git/push\r\n fastify.post('/git/push', async (_req, reply) => {\r\n try {\r\n await service.push();\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to push', err);\r\n }\r\n });\r\n\r\n // POST /api/git/full-sync\r\n fastify.post('/git/full-sync', async (req, reply) => {\r\n const parsed = FullSyncBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n await service.fullSync(parsed.data.message);\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n const status = await service.getStatus().catch(() => null);\r\n if (status && status.conflicted.length > 0) {\r\n return reply.status(409).send({ error: 'Merge conflict', conflicted: status.conflicted });\r\n }\r\n return sendError(reply, 500, 'Full sync failed', err);\r\n }\r\n });\r\n\r\n // ─── Conflict resolution ────────────────────────────────────────────────\r\n\r\n // POST /api/git/resolve-conflict\r\n fastify.post('/git/resolve-conflict', async (req, reply) => {\r\n const parsed = ResolveConflictBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n await service.resolveConflict(parsed.data.filePath, parsed.data.content);\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to resolve conflict', err);\r\n }\r\n });\r\n\r\n // POST /api/git/continue-rebase\r\n fastify.post('/git/continue-rebase', async (_req, reply) => {\r\n try {\r\n await service.continueRebase();\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to continue rebase', err);\r\n }\r\n });\r\n\r\n // POST /api/git/abort-rebase\r\n fastify.post('/git/abort-rebase', async (_req, reply) => {\r\n try {\r\n await service.abortRebase();\r\n return reply.send({ success: true });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to abort rebase', err);\r\n }\r\n });\r\n\r\n // GET /api/git/conflict-content/:filePath\r\n fastify.get<{ Params: { '*': string } }>('/git/conflict-content/*', async (req, reply) => {\r\n try {\r\n const filePath = req.params['*'];\r\n if (!filePath) return reply.status(400).send({ error: 'File path required' });\r\n const content = await service.getFileConflictContent(filePath);\r\n return reply.send(content);\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to get conflict content', err);\r\n }\r\n });\r\n\r\n // ─── AI-powered ─────────────────────────────────────────────────────────\r\n\r\n // POST /api/git/generate-commit-message\r\n fastify.post('/git/generate-commit-message', async (_req, reply) => {\r\n try {\r\n const diff = await service.getDiff();\r\n const message = await generateCommitMessage(diff);\r\n return reply.send({ message });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to generate commit message', err);\r\n }\r\n });\r\n\r\n // POST /api/git/resolve-conflict-ai\r\n fastify.post('/git/resolve-conflict-ai', async (req, reply) => {\r\n const parsed = ResolveConflictAIBody.safeParse(req.body);\r\n if (!parsed.success) {\r\n return reply.status(400).send({ error: 'Invalid body', details: parsed.error.issues });\r\n }\r\n try {\r\n const resolved = await resolveConflictWithAI(\r\n parsed.data.ours,\r\n parsed.data.theirs,\r\n parsed.data.filePath,\r\n );\r\n return reply.send({ resolved });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to AI-resolve conflict', err);\r\n }\r\n });\r\n\r\n // GET /api/git/impact\r\n fastify.get('/git/impact', async (_req, reply) => {\r\n try {\r\n const { execa } = await import('execa');\r\n const { stdout } = await execa('git', ['diff', '--name-only', 'HEAD'], { cwd: rootDir });\r\n const changedFiles = stdout.split('\\n').filter(Boolean);\r\n\r\n const { listSuiteDirs, readSuite } = await import('../../storage/suite-store.js');\r\n const { listCases } = await import('../../storage/case-store.js');\r\n const testsDir = path.join(rootDir, 'tests');\r\n const suiteDirs = await listSuiteDirs(testsDir);\r\n\r\n const impacted: Array<{ caseId: string; caseName: string; suiteId: string; suiteName: string; reason: string }> = [];\r\n\r\n for (const suiteDir of suiteDirs) {\r\n try {\r\n const suite = await readSuite(suiteDir);\r\n const cases = await listCases(suiteDir);\r\n for (const tc of cases) {\r\n const allText = [tc.name, tc.description ?? '', ...tc.steps.map((s) => s.instruction)].join(' ').toLowerCase();\r\n for (const file of changedFiles) {\r\n const basename = path.basename(file).toLowerCase();\r\n const dirname = path.dirname(file).toLowerCase();\r\n if (allText.includes(basename) || allText.includes(dirname)) {\r\n impacted.push({ caseId: tc.id, caseName: tc.name, suiteId: suite.id, suiteName: suite.name, reason: `Mentions \"${file}\"` });\r\n break;\r\n }\r\n }\r\n }\r\n } catch {\r\n // Skip unreadable suites\r\n }\r\n }\r\n\r\n return reply.send({ changedFiles, impactedCases: impacted });\r\n } catch (err) {\r\n return sendError(reply, 500, 'Failed to analyze impact', err);\r\n }\r\n });\r\n}\r\n","/**\n * Data-file routes — upload, list, read, edit, and delete data files\n * for data-driven testing.\n *\n * Files are stored in <rootDir>/tests/data/\n *\n * GET /api/data-files — list all data files\n * GET /api/data-files/:filename — read file content (parsed)\n * POST /api/data-files/upload — upload a JSON or CSV file\n * PUT /api/data-files/:filename — overwrite file content\n * DELETE /api/data-files/:filename — delete a data file\n */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { z } from 'zod';\nimport type { FastifyInstance } from 'fastify';\nimport { sendError } from '../utils.js';\nimport { createChildLogger } from '../../utils/logger.js';\n\nconst logger = createChildLogger('routes/data-files');\n\nconst ALLOWED_EXTENSIONS = ['.json', '.csv'];\n\nfunction parseCSV(content: string): Record<string, string>[] {\n const lines = content.trim().split('\\n').map((l) => l.trim()).filter(Boolean);\n if (lines.length < 2) return [];\n const headers = lines[0].split(',').map((h) => h.trim().replace(/^\"|\"$/g, ''));\n return lines.slice(1).map((line) => {\n // Simple CSV parse (handles quoted values)\n const values: string[] = [];\n let current = '';\n let inQuotes = false;\n for (const ch of line) {\n if (ch === '\"') { inQuotes = !inQuotes; continue; }\n if (ch === ',' && !inQuotes) { values.push(current.trim()); current = ''; continue; }\n current += ch;\n }\n values.push(current.trim());\n const row: Record<string, string> = {};\n headers.forEach((h, i) => { row[h] = values[i] ?? ''; });\n return row;\n });\n}\n\nexport async function dataFileRoutes(fastify: FastifyInstance): Promise<void> {\n const rootDir = fastify.rootDir;\n const dataDir = path.join(rootDir, 'tests', 'data');\n\n // Ensure data directory exists\n await fs.ensureDir(dataDir);\n\n // GET /api/data-files — list all data files\n fastify.get('/data-files', async (_req, reply) => {\n try {\n await fs.ensureDir(dataDir);\n const entries = await fs.readdir(dataDir, { withFileTypes: true });\n const files = entries\n .filter((e) => e.isFile() && ALLOWED_EXTENSIONS.some((ext) => e.name.endsWith(ext)))\n .map((e) => ({\n name: e.name,\n type: e.name.endsWith('.csv') ? 'csv' : 'json',\n path: `data/${e.name}`,\n }));\n return reply.send(files);\n } catch (err) {\n return sendError(reply, 500, 'Failed to list data files', err);\n }\n });\n\n // GET /api/data-files/:filename — read and parse a data file\n fastify.get<{ Params: { filename: string } }>('/data-files/:filename', async (req, reply) => {\n try {\n const filename = path.basename(req.params.filename); // prevent traversal\n const filePath = path.join(dataDir, filename);\n if (!(await fs.pathExists(filePath))) {\n return reply.status(404).send({ error: `Data file \"${filename}\" not found` });\n }\n\n const raw = await fs.readFile(filePath, 'utf8');\n let rows: Record<string, string>[];\n\n if (filename.endsWith('.csv')) {\n rows = parseCSV(raw);\n } else {\n const parsed = JSON.parse(raw);\n rows = Array.isArray(parsed)\n ? parsed.map((r: Record<string, unknown>) =>\n Object.fromEntries(Object.entries(r).map(([k, v]) => [k, String(v)])))\n : [];\n }\n\n return reply.send({ filename, raw, rows, rowCount: rows.length });\n } catch (err) {\n return sendError(reply, 500, 'Failed to read data file', err);\n }\n });\n\n // POST /api/data-files/upload — upload a JSON or CSV file\n fastify.post('/data-files/upload', async (req, reply) => {\n try {\n const body = req.body as Record<string, unknown>;\n const filename = String(body.filename ?? '').trim();\n const content = String(body.content ?? '');\n\n if (!filename) {\n return reply.status(400).send({ error: 'filename is required' });\n }\n\n const ext = path.extname(filename).toLowerCase();\n if (!ALLOWED_EXTENSIONS.includes(ext)) {\n return reply.status(400).send({ error: `Only ${ALLOWED_EXTENSIONS.join(', ')} files are allowed` });\n }\n\n const safeName = path.basename(filename); // prevent traversal\n const filePath = path.join(dataDir, safeName);\n await fs.ensureDir(dataDir);\n await fs.writeFile(filePath, content, 'utf8');\n\n // Parse to return row count\n let rowCount = 0;\n try {\n if (ext === '.csv') {\n rowCount = parseCSV(content).length;\n } else {\n const parsed = JSON.parse(content);\n rowCount = Array.isArray(parsed) ? parsed.length : 0;\n }\n } catch { /* ignore parse errors */ }\n\n logger.info({ filename: safeName, rowCount }, 'Data file uploaded');\n return reply.status(201).send({\n filename: safeName,\n path: `data/${safeName}`,\n rowCount,\n });\n } catch (err) {\n return sendError(reply, 500, 'Failed to upload data file', err);\n }\n });\n\n // PUT /api/data-files/:filename — overwrite file content (inline edit)\n fastify.put<{ Params: { filename: string } }>('/data-files/:filename', async (req, reply) => {\n try {\n const filename = path.basename(req.params.filename);\n const filePath = path.join(dataDir, filename);\n\n const body = req.body as Record<string, unknown>;\n const content = String(body.content ?? '');\n\n await fs.ensureDir(dataDir);\n await fs.writeFile(filePath, content, 'utf8');\n\n logger.info({ filename }, 'Data file updated');\n return reply.send({ filename, path: `data/${filename}` });\n } catch (err) {\n return sendError(reply, 500, 'Failed to update data file', err);\n }\n });\n\n // DELETE /api/data-files/:filename\n fastify.delete<{ Params: { filename: string } }>('/data-files/:filename', async (req, reply) => {\n try {\n const filename = path.basename(req.params.filename);\n const filePath = path.join(dataDir, filename);\n if (!(await fs.pathExists(filePath))) {\n return reply.status(404).send({ error: `Data file \"${filename}\" not found` });\n }\n await fs.remove(filePath);\n logger.info({ filename }, 'Data file deleted');\n return reply.status(204).send();\n } catch (err) {\n return sendError(reply, 500, 'Failed to delete data file', err);\n }\n });\n}\n","/**\n * Search routes — full-text search across suites, cases, and steps.\n *\n * GET /api/search?q=<query>\n */\nimport path from 'path';\nimport type { FastifyInstance } from 'fastify';\nimport { listSuiteDirs, readSuite } from '../../storage/suite-store.js';\nimport { listCases } from '../../storage/case-store.js';\nimport { sendError } from '../utils.js';\n\ninterface SearchResult {\n type: 'suite' | 'case' | 'step';\n suiteId: string;\n suiteName: string;\n caseId?: string;\n caseName?: string;\n stepId?: string;\n instruction?: string;\n matchedOn: 'name' | 'description' | 'tag' | 'instruction';\n}\n\nfunction matchWeight(matchedOn: SearchResult['matchedOn']): number {\n switch (matchedOn) {\n case 'name': return 0;\n case 'description': return 1;\n case 'tag': return 2;\n case 'instruction': return 3;\n }\n}\n\nexport async function searchRoutes(fastify: FastifyInstance): Promise<void> {\n const testsDir = path.join(fastify.rootDir, 'tests');\n\n // GET /api/search?q=<query>\n fastify.get<{ Querystring: { q?: string } }>('/search', async (req, reply) => {\n const q = (req.query.q ?? '').trim();\n\n if (q.length < 2) {\n return reply.send([]);\n }\n\n try {\n const pattern = new RegExp(q.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'i');\n const suiteDirs = await listSuiteDirs(testsDir);\n const results: SearchResult[] = [];\n\n for (const suiteDir of suiteDirs) {\n let suite;\n try {\n suite = await readSuite(suiteDir);\n } catch {\n continue;\n }\n\n // Match suite-level fields\n if (pattern.test(suite.name)) {\n results.push({ type: 'suite', suiteId: suite.id, suiteName: suite.name, matchedOn: 'name' });\n } else if (suite.description && pattern.test(suite.description)) {\n results.push({ type: 'suite', suiteId: suite.id, suiteName: suite.name, matchedOn: 'description' });\n } else if (suite.tags?.some((t) => pattern.test(t))) {\n results.push({ type: 'suite', suiteId: suite.id, suiteName: suite.name, matchedOn: 'tag' });\n }\n\n // Load cases for this suite\n let cases;\n try {\n cases = await listCases(suiteDir);\n } catch {\n cases = [];\n }\n\n for (const tc of cases) {\n // Match case-level fields\n if (pattern.test(tc.name)) {\n results.push({ type: 'case', suiteId: suite.id, suiteName: suite.name, caseId: tc.id, caseName: tc.name, matchedOn: 'name' });\n } else if (tc.description && pattern.test(tc.description)) {\n results.push({ type: 'case', suiteId: suite.id, suiteName: suite.name, caseId: tc.id, caseName: tc.name, matchedOn: 'description' });\n } else if (tc.tags?.some((t) => pattern.test(t))) {\n results.push({ type: 'case', suiteId: suite.id, suiteName: suite.name, caseId: tc.id, caseName: tc.name, matchedOn: 'tag' });\n }\n\n // Match step-level instructions\n for (const step of tc.steps ?? []) {\n if (step.instruction && pattern.test(step.instruction)) {\n results.push({\n type: 'step',\n suiteId: suite.id,\n suiteName: suite.name,\n caseId: tc.id,\n caseName: tc.name,\n stepId: step.id,\n instruction: step.instruction,\n matchedOn: 'instruction',\n });\n }\n }\n }\n\n if (results.length >= 20) break;\n }\n\n // Sort: name matches first, then description, then tag, then instruction\n results.sort((a, b) => matchWeight(a.matchedOn) - matchWeight(b.matchedOn));\n\n return reply.send(results.slice(0, 20));\n } catch (err) {\n return sendError(reply, 500, 'Search failed', err);\n }\n });\n}\n","/**\n * CI Config routes — generate CI/CD configuration files.\n *\n * POST /api/ci-config\n */\nimport { z } from 'zod';\nimport type { FastifyInstance } from 'fastify';\nimport { sendError } from '../utils.js';\n\nconst CiConfigBody = z.object({\n platform: z.enum(['github', 'gitlab', 'jenkins']),\n browsers: z.array(z.string()).default(['chromium']),\n parallel: z.number().int().positive().default(2),\n headed: z.boolean().default(false),\n env: z.string().optional(),\n device: z.string().optional(),\n});\n\nfunction buildRunFlags(browsers: string[], parallel: number, device?: string): string {\n const parts = [`--all`, `--browser ${browsers.join(' ')}`, `--parallel ${parallel}`, `--ci`];\n if (device) parts.push(`--device \"${device}\"`);\n return parts.join(' ');\n}\n\nfunction generateGitHubActions(browsers: string[], parallel: number, device?: string): string {\n const runFlags = buildRunFlags(browsers, parallel, device);\n const deviceNote = device ? `\\n # Device emulation: ${device}` : '';\n return `name: Assuremind Tests\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: '20'\n - run: npm ci\n - run: npx playwright install --with-deps${deviceNote}\n - run: npx assuremind run ${runFlags}\n - uses: actions/upload-artifact@v4\n if: always()\n with:\n name: assuremind-results\n path: results/\n`;\n}\n\nfunction generateGitLabCI(browsers: string[], parallel: number, device?: string): string {\n const runFlags = buildRunFlags(browsers, parallel, device);\n const deviceNote = device ? `\\n # Device emulation: ${device}` : '';\n return `stages: [test]\ntest:\n stage: test\n image: mcr.microsoft.com/playwright:v1.40.0-jammy${deviceNote}\n script:\n - npm ci\n - npx assuremind run ${runFlags}\n artifacts:\n when: always\n paths: [results/]\n expire_in: 7 days\n`;\n}\n\nfunction generateJenkins(browsers: string[], parallel: number, device?: string): string {\n const runFlags = buildRunFlags(browsers, parallel, device);\n const deviceNote = device ? `\\n // Device emulation: ${device}` : '';\n return `pipeline {\n agent any\n stages {\n stage('Install') { steps { sh 'npm ci' } }\n stage('Test') {${deviceNote}\n steps { sh 'npx assuremind run ${runFlags}' }\n }\n }\n post { always { archiveArtifacts artifacts: 'results/**', allowEmptyArchive: true } }\n}\n`;\n}\n\nconst PLATFORM_FILENAMES: Record<string, string> = {\n github: '.github/workflows/assuremind.yml',\n gitlab: '.gitlab-ci.yml',\n jenkins: 'Jenkinsfile',\n};\n\nexport async function ciConfigRoutes(fastify: FastifyInstance): Promise<void> {\n // POST /api/ci-config\n fastify.post('/ci-config', async (req, reply) => {\n const parsed = CiConfigBody.safeParse(req.body);\n if (!parsed.success) {\n return reply.status(400).send({ error: 'Invalid CI config request', details: parsed.error.issues });\n }\n\n try {\n const { platform, browsers, parallel, device } = parsed.data;\n let yaml: string;\n\n if (platform === 'github') {\n yaml = generateGitHubActions(browsers, parallel, device);\n } else if (platform === 'gitlab') {\n yaml = generateGitLabCI(browsers, parallel, device);\n } else {\n yaml = generateJenkins(browsers, parallel, device);\n }\n\n return reply.send({ yaml, filename: PLATFORM_FILENAMES[platform] });\n } catch (err) {\n return sendError(reply, 500, 'Failed to generate CI config', err);\n }\n });\n}\n","/**\n * Templates routes — static built-in test case templates.\n *\n * GET /api/templates\n */\nimport type { FastifyInstance } from 'fastify';\nimport { sendError } from '../utils.js';\n\nconst TEMPLATES = [\n {\n id: 'user-login',\n name: 'User Login',\n description: 'Standard login flow with credential validation',\n category: 'auth',\n steps: [\n { instruction: 'Navigate to the login page' },\n { instruction: 'Enter the username in the username field' },\n { instruction: 'Enter the password in the password field' },\n { instruction: 'Click the login button' },\n { instruction: 'Verify the dashboard page is displayed' },\n ],\n },\n {\n id: 'crud-record',\n name: 'CRUD Operations',\n description: 'Create, read, update, and delete a record',\n category: 'crud',\n steps: [\n { instruction: 'Navigate to the records list page' },\n { instruction: 'Click the Create New button' },\n { instruction: 'Fill in the required fields' },\n { instruction: 'Click Save to create the record' },\n { instruction: 'Verify the record appears in the list' },\n { instruction: 'Click on the record to open it' },\n { instruction: 'Edit one of the fields' },\n { instruction: 'Save the changes' },\n { instruction: 'Delete the record' },\n { instruction: 'Verify the record is no longer in the list' },\n ],\n },\n {\n id: 'page-navigation',\n name: 'Page Navigation',\n description: 'Verify navigation between key pages',\n category: 'navigation',\n steps: [\n { instruction: 'Navigate to the home page' },\n { instruction: 'Click the main navigation menu item' },\n { instruction: 'Verify the correct page title is shown' },\n { instruction: 'Use the browser back button' },\n { instruction: 'Verify returning to the home page' },\n ],\n },\n {\n id: 'form-submission',\n name: 'Form Submission',\n description: 'Fill and submit a form with validation',\n category: 'form',\n steps: [\n { instruction: 'Navigate to the form page' },\n { instruction: 'Fill in all required fields' },\n { instruction: 'Attempt to submit the form with empty fields first' },\n { instruction: 'Verify validation error messages are shown' },\n { instruction: 'Fill in all required fields correctly' },\n { instruction: 'Click the submit button' },\n { instruction: 'Verify the success message is displayed' },\n ],\n },\n {\n id: 'api-health-check',\n name: 'REST API Health Check',\n description: 'Verify API endpoints return expected responses',\n category: 'api',\n steps: [\n { instruction: 'Send a GET request to the health check endpoint' },\n { instruction: 'Verify the response status is 200' },\n { instruction: 'Verify the response body contains status ok' },\n { instruction: 'Send a GET request to the main API endpoint' },\n { instruction: 'Verify the response contains the expected data structure' },\n ],\n },\n];\n\nexport async function templatesRoutes(fastify: FastifyInstance): Promise<void> {\n // GET /api/templates\n fastify.get('/templates', async (_req, reply) => {\n try {\n return reply.send(TEMPLATES);\n } catch (err) {\n return sendError(reply, 500, 'Failed to list templates', err);\n }\n });\n}\n","/**\n * Flakiness Tracker route.\n * GET /api/flakiness?suiteId=&caseId=\n */\nimport path from 'path';\nimport type { FastifyInstance } from 'fastify';\nimport { listResultIds, readResult } from '../../storage/result-store.js';\nimport { sendError } from '../utils.js';\n\ninterface StepFlakiness {\n stepId: string;\n instruction: string;\n passRate: number;\n runs: number;\n flaky: boolean;\n}\n\ninterface CaseFlakiness {\n caseId: string;\n caseName: string;\n passRate: number;\n runs: number;\n flaky: boolean;\n steps: StepFlakiness[];\n}\n\ninterface FlakinessReport {\n cases: CaseFlakiness[];\n generatedAt: string;\n}\n\nexport async function flakinessRoutes(fastify: FastifyInstance): Promise<void> {\n const rootDir = fastify.rootDir;\n\n fastify.get<{ Querystring: { suiteId?: string; caseId?: string } }>('/flakiness', async (req, reply) => {\n try {\n const { suiteId, caseId } = req.query;\n\n // Load last 20 run IDs\n const allIds = await listResultIds(rootDir);\n const recentIds = allIds.slice(0, 20);\n\n // Aggregate pass/fail per (caseId, stepId)\n const caseMap = new Map<string, { caseName: string; passes: number; failures: number }>();\n const stepMap = new Map<string, Map<string, { instruction: string; passes: number; failures: number }>>();\n\n for (const runId of recentIds) {\n try {\n const result = await readResult(rootDir, runId);\n for (const suite of result.suites) {\n if (suiteId && suite.suiteId !== suiteId) continue;\n for (const tc of suite.cases) {\n if (caseId && tc.caseId !== caseId) continue;\n const existing = caseMap.get(tc.caseId) ?? { caseName: tc.caseName, passes: 0, failures: 0 };\n if (tc.status === 'passed') existing.passes++;\n else if (tc.status === 'failed') existing.failures++;\n caseMap.set(tc.caseId, existing);\n\n if (!stepMap.has(tc.caseId)) stepMap.set(tc.caseId, new Map());\n const caseSteps = stepMap.get(tc.caseId)!;\n\n for (const step of tc.steps) {\n const es = caseSteps.get(step.stepId) ?? { instruction: step.instruction, passes: 0, failures: 0 };\n if (step.status === 'passed') es.passes++;\n else if (step.status === 'failed') es.failures++;\n caseSteps.set(step.stepId, es);\n }\n }\n }\n } catch {\n // Skip unreadable runs\n }\n }\n\n const cases: CaseFlakiness[] = [];\n for (const [tcId, data] of caseMap) {\n const runs = data.passes + data.failures;\n const passRate = runs > 0 ? data.passes / runs : 1;\n const flaky = runs >= 3 && passRate > 0 && passRate < 1.0;\n\n const caseStepsMap = stepMap.get(tcId);\n const steps: StepFlakiness[] = [];\n if (caseStepsMap) {\n for (const [stepId, sd] of caseStepsMap) {\n const stepRuns = sd.passes + sd.failures;\n const stepPassRate = stepRuns > 0 ? sd.passes / stepRuns : 1;\n const stepFlaky = stepRuns >= 3 && stepPassRate > 0 && stepPassRate < 1.0;\n steps.push({ stepId, instruction: sd.instruction, passRate: stepPassRate, runs: stepRuns, flaky: stepFlaky });\n }\n }\n\n cases.push({ caseId: tcId, caseName: data.caseName, passRate, runs, flaky, steps });\n }\n\n const report: FlakinessReport = { cases, generatedAt: new Date().toISOString() };\n return reply.send(report);\n } catch (err) {\n return sendError(reply, 500, 'Failed to compute flakiness', err);\n }\n });\n}\n","/**\n * Step Library Store — persists reusable step templates in tests/.step-library.json\n */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { v4 as uuidv4 } from 'uuid';\nimport { z } from 'zod';\nimport { atomicWriteJson } from './utils.js';\n\nconst LibraryStepSchema = z.object({\n id: z.string(),\n name: z.string().min(1),\n instruction: z.string().min(1),\n tags: z.array(z.string()).default([]),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nexport type LibraryStep = z.infer<typeof LibraryStepSchema>;\n\nfunction libraryPath(rootDir: string): string {\n return path.join(rootDir, 'tests', '.step-library.json');\n}\n\nexport async function readLibrary(rootDir: string): Promise<LibraryStep[]> {\n const filePath = libraryPath(rootDir);\n if (!(await fs.pathExists(filePath))) return [];\n try {\n const raw = await fs.readJson(filePath);\n if (!Array.isArray(raw)) return [];\n return raw.map((item: unknown) => LibraryStepSchema.parse(item));\n } catch {\n return [];\n }\n}\n\nexport async function writeLibrary(rootDir: string, steps: LibraryStep[]): Promise<void> {\n const filePath = libraryPath(rootDir);\n await fs.ensureDir(path.dirname(filePath));\n await atomicWriteJson(filePath, steps);\n}\n\nexport async function addStep(\n rootDir: string,\n data: { name: string; instruction: string; tags?: string[] },\n): Promise<LibraryStep> {\n const steps = await readLibrary(rootDir);\n const now = new Date().toISOString();\n const step: LibraryStep = {\n id: uuidv4(),\n name: data.name,\n instruction: data.instruction,\n tags: data.tags ?? [],\n createdAt: now,\n updatedAt: now,\n };\n steps.push(step);\n await writeLibrary(rootDir, steps);\n return step;\n}\n\nexport async function updateStep(\n rootDir: string,\n id: string,\n updates: Partial<{ name: string; instruction: string; tags: string[] }>,\n): Promise<LibraryStep> {\n const steps = await readLibrary(rootDir);\n const idx = steps.findIndex((s) => s.id === id);\n if (idx < 0) throw new Error(`Library step \"${id}\" not found`);\n steps[idx] = { ...steps[idx], ...updates, updatedAt: new Date().toISOString() };\n await writeLibrary(rootDir, steps);\n return steps[idx];\n}\n\nexport async function deleteStep(rootDir: string, id: string): Promise<void> {\n const steps = await readLibrary(rootDir);\n const filtered = steps.filter((s) => s.id !== id);\n await writeLibrary(rootDir, filtered);\n}\n","/**\n * Step Library routes.\n * GET /api/step-library\n * POST /api/step-library\n * PATCH /api/step-library/:id\n * DELETE /api/step-library/:id\n */\nimport { z } from 'zod';\nimport type { FastifyInstance } from 'fastify';\nimport {\n readLibrary,\n addStep,\n updateStep,\n deleteStep,\n} from '../../storage/step-library-store.js';\nimport { sendError } from '../utils.js';\n\nconst CreateBody = z.object({\n name: z.string().min(1),\n instruction: z.string().min(1),\n tags: z.array(z.string()).optional(),\n});\n\nconst UpdateBody = z.object({\n name: z.string().min(1).optional(),\n instruction: z.string().min(1).optional(),\n tags: z.array(z.string()).optional(),\n});\n\nexport async function stepLibraryRoutes(fastify: FastifyInstance): Promise<void> {\n const rootDir = fastify.rootDir;\n\n // GET /api/step-library\n fastify.get('/step-library', async (_req, reply) => {\n try {\n const steps = await readLibrary(rootDir);\n return reply.send(steps);\n } catch (err) {\n return sendError(reply, 500, 'Failed to list step library', err);\n }\n });\n\n // POST /api/step-library\n fastify.post('/step-library', async (req, reply) => {\n const parsed = CreateBody.safeParse(req.body);\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\n try {\n const step = await addStep(rootDir, parsed.data);\n return reply.status(201).send(step);\n } catch (err) {\n return sendError(reply, 500, 'Failed to create library step', err);\n }\n });\n\n // PATCH /api/step-library/:id\n fastify.patch<{ Params: { id: string } }>('/step-library/:id', async (req, reply) => {\n const parsed = UpdateBody.safeParse(req.body);\n if (!parsed.success) return reply.status(400).send({ error: 'Invalid request', details: parsed.error.issues });\n try {\n const step = await updateStep(rootDir, req.params.id, parsed.data);\n return reply.send(step);\n } catch (err) {\n return sendError(reply, 500, 'Failed to update library step', err);\n }\n });\n\n // DELETE /api/step-library/:id\n fastify.delete<{ Params: { id: string } }>('/step-library/:id', async (req, reply) => {\n try {\n await deleteStep(rootDir, req.params.id);\n return reply.status(204).send();\n } catch (err) {\n return sendError(reply, 500, 'Failed to delete library step', err);\n }\n });\n}\n","/**\r\n * Fastify server bootstrap — registers all plugins, routes, and WebSocket support.\r\n *\r\n * Exposes:\r\n * startServer({ port, rootDir }) → ServerInstance\r\n */\r\nimport Fastify from 'fastify';\r\nimport cors from '@fastify/cors';\r\nimport websocketPlugin from '@fastify/websocket';\r\nimport './types.js';\r\nimport { WebSocketManager } from './websocket.js';\r\nimport { registerStatic } from './static.js';\r\nimport { configRoutes } from './routes/config.js';\r\nimport { suiteRoutes } from './routes/suites.js';\r\nimport { caseRoutes } from './routes/cases.js';\r\nimport { stepRoutes } from './routes/steps.js';\r\nimport { hookRoutes } from './routes/hooks.js';\r\nimport { variableRoutes } from './routes/variables.js';\r\nimport { healingRoutes } from './routes/healing.js';\r\nimport { runRoutes } from './routes/run.js';\r\nimport { storyRoutes } from './routes/story.js';\r\nimport { reportRoutes } from './routes/report.js';\r\nimport { mediaRoutes } from './routes/media.js';\r\nimport { xrayRoutes } from './routes/xray.js';\r\nimport { gitRoutes } from './routes/git.js';\r\nimport { dataFileRoutes } from './routes/data-files.js';\r\nimport { searchRoutes } from './routes/search.js';\r\nimport { ciConfigRoutes } from './routes/ci-config.js';\r\nimport { templatesRoutes } from './routes/templates.js';\r\nimport { flakinessRoutes } from './routes/flakiness.js';\r\nimport { stepLibraryRoutes } from './routes/step-library.js';\r\nimport { createChildLogger } from '../utils/logger.js';\r\n\r\nconst logger = createChildLogger('server');\r\n\r\nexport interface ServerInstance {\r\n close(): Promise<void>;\r\n}\r\n\r\nexport interface StartServerOptions {\r\n port: number;\r\n rootDir: string;\r\n}\r\n\r\nexport async function startServer(options: StartServerOptions): Promise<ServerInstance> {\r\n const { port, rootDir } = options;\r\n\r\n const fastify = Fastify({\r\n logger: false, // We use our own pino logger\r\n });\r\n\r\n // ── Decorators ──────────────────────────────────────────────────────────────\r\n const wsManager = new WebSocketManager();\r\n fastify.decorate('rootDir', rootDir);\r\n fastify.decorate('wsManager', wsManager);\r\n\r\n // ── Plugins ─────────────────────────────────────────────────────────────────\r\n await fastify.register(cors, {\r\n origin: true,\r\n methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\r\n });\r\n\r\n await fastify.register(websocketPlugin);\r\n\r\n // ── WebSocket endpoint ───────────────────────────────────────────────────────\r\n fastify.get('/ws', { websocket: true }, (socket) => {\r\n wsManager.add(socket);\r\n });\r\n\r\n // ── API routes ───────────────────────────────────────────────────────────────\r\n await fastify.register(configRoutes, { prefix: '/api' });\r\n await fastify.register(suiteRoutes, { prefix: '/api' });\r\n await fastify.register(caseRoutes, { prefix: '/api' });\r\n await fastify.register(stepRoutes, { prefix: '/api' });\r\n await fastify.register(hookRoutes, { prefix: '/api' });\r\n await fastify.register(variableRoutes, { prefix: '/api' });\r\n await fastify.register(healingRoutes, { prefix: '/api' });\r\n await fastify.register(runRoutes, { prefix: '/api' });\r\n await fastify.register(storyRoutes, { prefix: '/api' });\r\n await fastify.register(reportRoutes, { prefix: '/api' });\r\n await fastify.register(mediaRoutes, { prefix: '/api' });\r\n await fastify.register(xrayRoutes, { prefix: '/api' });\r\n await fastify.register(gitRoutes, { prefix: '/api' });\r\n await fastify.register(dataFileRoutes, { prefix: '/api' });\r\n await fastify.register(searchRoutes, { prefix: '/api' });\r\n await fastify.register(ciConfigRoutes, { prefix: '/api' });\r\n await fastify.register(templatesRoutes, { prefix: '/api' });\r\n await fastify.register(flakinessRoutes, { prefix: '/api' });\r\n await fastify.register(stepLibraryRoutes, { prefix: '/api' });\r\n\r\n // ── Static UI (must be registered last — catch-all) ─────────────────────────\r\n await registerStatic(fastify, rootDir);\r\n\r\n // ── Start listening ──────────────────────────────────────────────────────────\r\n await fastify.listen({ port, host: '127.0.0.1' });\r\n logger.info({ port, rootDir }, `Assuremind Studio listening on http://127.0.0.1:${port}`);\r\n\r\n return {\r\n async close() {\r\n await fastify.close();\r\n logger.info('Server closed');\r\n },\r\n };\r\n}\r\n","import open from 'open';\r\nimport { printInfo, printError, printBox, createSpinner } from './ui.js';\r\nimport { validateEnv } from '../utils/env.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\nimport { ConfigError } from '../utils/errors.js';\r\n\r\ninterface StudioOptions {\r\n port?: number;\r\n noOpen?: boolean;\r\n}\r\n\r\nexport async function runStudio(options: StudioOptions = {}): Promise<void> {\r\n // Prevent stray Playwright / async rejections from crashing the long-running\r\n // studio process. All intentional errors are handled inside the runner; this\r\n // only catches the rare secondary rejection (e.g. navigation timeout fired\r\n // after the executor already caught and handled the primary error).\r\n process.on('unhandledRejection', (reason) => {\r\n const msg = reason instanceof Error ? reason.message : String(reason);\r\n // Log but do NOT exit — the server should keep running\r\n printError(`Unhandled rejection (non-fatal): ${msg}`);\r\n });\r\n\r\n process.stdout.write('\\n');\r\n printInfo('Starting Assuremind Studio…\\n');\r\n\r\n // Step 1: Validate environment\r\n try {\r\n validateEnv();\r\n } catch (err) {\r\n printError(\r\n err instanceof ConfigError\r\n ? err.message\r\n : `Environment validation failed: ${err instanceof Error ? err.message : String(err)}`,\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // Step 2: Read config\r\n let port: number;\r\n try {\r\n const config = await readConfig(process.cwd());\r\n port = options.port ?? config.studioPort;\r\n } catch (err) {\r\n printError(`Config error: ${err instanceof Error ? err.message : String(err)}`);\r\n process.exit(1);\r\n }\r\n\r\n // Step 3: Start Fastify server (implemented in Phase 5)\r\n const spinner = createSpinner('Starting server…');\r\n spinner.start();\r\n\r\n try {\r\n const { startServer } = await import('../server/index.js').catch(() => {\r\n throw new ConfigError(\r\n 'Server module is not available yet.\\n' +\r\n ' This is expected during development — Phase 5 implements the server.\\n' +\r\n ' Build the full package with \"npm run build\" first.',\r\n 'SERVER_NOT_AVAILABLE',\r\n );\r\n });\r\n\r\n const server = await startServer({ port, rootDir: process.cwd() });\r\n spinner.succeed(`Server running at http://localhost:${port}`);\r\n\r\n const url = `http://localhost:${port}`;\r\n\r\n printBox([\r\n '🧪 Assuremind Studio',\r\n '',\r\n ` URL: ${url}`,\r\n ` Port: ${port}`,\r\n '',\r\n 'Press Ctrl+C to stop',\r\n ]);\r\n\r\n if (!options.noOpen) {\r\n await open(url);\r\n }\r\n\r\n // Keep alive until interrupted\r\n await new Promise<void>((_, reject) => {\r\n process.on('SIGINT', () => {\r\n server.close().then(() => {\r\n printInfo('\\nStudio stopped.');\r\n process.exit(0);\r\n }).catch(reject);\r\n });\r\n process.on('SIGTERM', () => {\r\n server.close().then(() => process.exit(0)).catch(reject);\r\n });\r\n });\r\n } catch (err) {\r\n spinner.fail('Failed to start server');\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n}\r\n","import { printInfo, printError, printWarn, createSpinner, printBox, colors } from './ui.js';\r\nimport { validateEnv } from '../utils/env.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\nimport { ConfigError } from '../utils/errors.js';\r\nimport type { AutotestConfig } from '../types/config.js';\r\nimport type { RunConfig, RunResult, SuiteResult, TestCaseResult } from '../types/run.js';\r\n\r\nexport interface RunCommandOptions {\r\n all?: boolean;\r\n type?: string;\r\n suite?: string;\r\n tag?: string;\r\n test?: string;\r\n browser?: string[];\r\n /** Playwright device descriptor name for emulation (e.g. 'iPhone 15 Pro'). */\r\n device?: string;\r\n env?: string;\r\n parallel?: number;\r\n headed?: boolean;\r\n ci?: boolean;\r\n reporter?: string[];\r\n noHealing?: boolean;\r\n}\r\n\r\nfunction buildRunConfig(options: RunCommandOptions): RunConfig {\r\n const config: RunConfig = {};\r\n\r\n if (options.all) config.all = true;\r\n if (options.type) config.type = options.type;\r\n if (options.suite) config.suite = options.suite;\r\n if (options.tag) config.tag = options.tag;\r\n if (options.test) config.test = options.test;\r\n if (options.browser) config.browsers = options.browser;\r\n if (options.device) config.device = options.device;\r\n if (options.env) config.env = options.env;\r\n if (options.parallel !== undefined) config.parallel = options.parallel;\r\n if (options.headed) config.headed = true;\r\n if (options.ci) config.ci = true;\r\n if (options.reporter) config.reporter = options.reporter;\r\n if (options.noHealing) config.noHealing = true;\r\n\r\n return config;\r\n}\r\n\r\nfunction validateRunOptions(options: RunCommandOptions): void {\r\n // Require at least one primary selector\r\n const selectors = [options.all, options.type, options.suite, options.tag, options.test].filter(Boolean);\r\n if (selectors.length === 0) {\r\n throw new ConfigError(\r\n 'Specify what to run: --all, --type <type>, --suite <name>, --tag <tag>, or --test <name>\\n' +\r\n 'Filters can be combined: e.g. --type audit --tag regression',\r\n 'RUN_NO_SELECTOR',\r\n );\r\n }\r\n // --all is mutually exclusive with other selectors\r\n if (options.all && selectors.length > 1) {\r\n throw new ConfigError(\r\n '--all cannot be combined with other filters (--type, --suite, --tag, --test)',\r\n 'RUN_MULTIPLE_SELECTORS',\r\n );\r\n }\r\n}\r\n\r\nfunction formatDuration(ms: number): string {\r\n if (ms < 1000) return `${ms}ms`;\r\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\r\n const m = Math.floor(ms / 60_000);\r\n const s = Math.round((ms % 60_000) / 1000);\r\n return `${m}m ${s}s`;\r\n}\r\n\r\nfunction statusIcon(status: string): string {\r\n switch (status) {\r\n case 'passed': return colors.success('✓');\r\n case 'failed': return colors.error('✗');\r\n case 'skipped': return colors.warn('–');\r\n default: return colors.dim('?');\r\n }\r\n}\r\n\r\nfunction printCaseResult(tc: TestCaseResult, ci: boolean): void {\r\n const icon = statusIcon(tc.status);\r\n const duration = colors.dim(`(${formatDuration(tc.duration)})`);\r\n process.stdout.write(` ${icon} ${tc.caseName} ${duration}\\n`);\r\n\r\n if (!ci || tc.status === 'failed') {\r\n for (const step of tc.steps) {\r\n if (step.status === 'failed') {\r\n process.stdout.write(\r\n ` ${colors.error('✗')} ${colors.dim(step.instruction)}\\n`,\r\n );\r\n if (step.error) {\r\n const excerpt = step.error.split('\\n')[0]?.slice(0, 120) ?? '';\r\n process.stdout.write(` ${colors.dim(excerpt)}\\n`);\r\n }\r\n if (step.healed) {\r\n process.stdout.write(\r\n ` ${colors.warn('⚕')} ${colors.dim('Self-healed — review in Studio')}\\n`,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction printSuiteResult(suite: SuiteResult, ci: boolean): void {\r\n const icon = statusIcon(suite.status);\r\n const duration = colors.dim(`(${formatDuration(suite.duration)})`);\r\n const browser = colors.dim(`[${suite.browser}]`);\r\n process.stdout.write(\r\n `\\n ${icon} ${colors.bold(suite.suiteName)} ${browser} ${duration}\\n`,\r\n );\r\n for (const tc of suite.cases) {\r\n printCaseResult(tc, ci);\r\n }\r\n}\r\n\r\nfunction printRunSummary(result: RunResult, ci: boolean): void {\r\n const duration = formatDuration(result.duration);\r\n const passedStr = colors.success(`${result.passed} passed`);\r\n const failedStr = result.failed > 0 ? colors.error(`${result.failed} failed`) : colors.dim('0 failed');\r\n const skippedStr = result.skipped > 0 ? colors.warn(`${result.skipped} skipped`) : colors.dim('0 skipped');\r\n\r\n if (!ci) {\r\n process.stdout.write('\\n');\r\n for (const suite of result.suites) {\r\n printSuiteResult(suite, ci);\r\n }\r\n }\r\n\r\n const summaryLines = [\r\n result.status === 'passed' ? '✅ All tests passed!' : '❌ Some tests failed',\r\n '',\r\n ` ${passedStr} ${failedStr} ${skippedStr}`,\r\n ` Duration: ${duration}`,\r\n ` Run ID: ${result.runId}`,\r\n '',\r\n ` Results saved to: results/runs/${result.runId}.json`,\r\n ];\r\n\r\n printBox(summaryLines);\r\n}\r\n\r\nexport async function runRun(options: RunCommandOptions): Promise<void> {\r\n process.stdout.write('\\n');\r\n\r\n // Validate options early\r\n try {\r\n validateRunOptions(options);\r\n } catch (err) {\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n // Validate environment\r\n try {\r\n validateEnv();\r\n } catch (err) {\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n const rootDir = process.cwd();\r\n\r\n let autotestConfig;\r\n try {\r\n autotestConfig = await readConfig(rootDir);\r\n } catch (err) {\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n const runConfig = buildRunConfig(options);\r\n\r\n // Apply CLI overrides to config\r\n if (runConfig.browsers) autotestConfig.browsers = runConfig.browsers as typeof autotestConfig.browsers;\r\n if (runConfig.parallel) autotestConfig.parallel = runConfig.parallel;\r\n if (runConfig.headed) autotestConfig.headless = false;\r\n if (runConfig.noHealing) autotestConfig.healing.enabled = false;\r\n if (runConfig.device) autotestConfig.device = runConfig.device;\r\n\r\n // Describe what we are running\r\n const parts: string[] = [];\r\n if (options.all) parts.push('all suites');\r\n if (options.type) parts.push(`type \"${options.type}\"`);\r\n if (options.suite) parts.push(`suite \"${options.suite}\"`);\r\n if (options.tag) parts.push(`tag \"${options.tag}\"`);\r\n if (options.test) parts.push(`test \"${options.test}\"`);\r\n const modeLabel = parts.join(' + ') || 'all suites';\r\n\r\n const deviceLabel = autotestConfig.device ? ` | device: ${autotestConfig.device}` : '';\r\n printInfo(`Running ${modeLabel} on [${autotestConfig.browsers.join(', ')}]${deviceLabel}`);\r\n\r\n if (!options.ci) {\r\n printInfo(`Healing: ${autotestConfig.healing.enabled ? 'enabled' : 'disabled'}`);\r\n }\r\n\r\n process.stdout.write('\\n');\r\n\r\n const spinner = createSpinner('Loading test runner…');\r\n spinner.start();\r\n\r\n let runTests: (\r\n rootDir: string,\r\n runConfig: RunConfig,\r\n autotestConfig: AutotestConfig,\r\n ) => Promise<RunResult>;\r\n\r\n try {\r\n const mod = await import('../engine/runner.js');\r\n runTests = mod.runTests;\r\n spinner.succeed('Runner loaded');\r\n } catch {\r\n spinner.fail('Failed to load test runner');\r\n printError(\r\n 'Test runner could not be loaded.\\n' +\r\n ' Make sure you have run \"npm run build\" or are running from source.',\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // Live progress via a simple per-suite spinner\r\n const runSpinner = createSpinner('Running tests…');\r\n if (!options.ci) runSpinner.start();\r\n\r\n let result: RunResult;\r\n try {\r\n result = await runTests(rootDir, runConfig, autotestConfig);\r\n } catch (err) {\r\n if (!options.ci) runSpinner.fail('Run failed');\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n if (!options.ci) {\r\n if (result.status === 'passed') {\r\n runSpinner.succeed('Run complete');\r\n } else {\r\n runSpinner.fail('Run complete with failures');\r\n }\r\n }\r\n\r\n printRunSummary(result, options.ci ?? false);\r\n\r\n if (result.failed > 0) {\r\n printWarn(`${result.failed} test(s) failed. Check the report above for details.`);\r\n if (autotestConfig.healing.enabled) {\r\n printInfo('Self-healing events (if any) saved — run \"npx assuremind apply-healing\" to review.');\r\n }\r\n }\r\n\r\n process.exit(result.status === 'passed' ? 0 : 1);\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { printInfo, printError, printSuccess, createSpinner, colors } from './ui.js';\r\nimport { validateEnv } from '../utils/env.js';\r\nimport { ConfigError } from '../utils/errors.js';\r\n\r\nexport interface GenerateCommandOptions {\r\n story?: string;\r\n storyFile?: string;\r\n suite?: string;\r\n output?: string;\r\n}\r\n\r\nasync function loadStoryText(options: GenerateCommandOptions): Promise<string> {\r\n if (options.story) {\r\n return options.story;\r\n }\r\n if (options.storyFile) {\r\n const filePath = path.resolve(options.storyFile);\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new ConfigError(\r\n `Story file not found: \"${filePath}\"`,\r\n 'STORY_FILE_NOT_FOUND',\r\n );\r\n }\r\n return fs.readFile(filePath, 'utf8');\r\n }\r\n throw new ConfigError(\r\n 'Provide a story with --story \"<text>\" or --story-file <path>',\r\n 'GENERATE_NO_STORY',\r\n );\r\n}\r\n\r\nexport async function runGenerate(options: GenerateCommandOptions): Promise<void> {\r\n process.stdout.write('\\n');\r\n\r\n // Validate environment first (AI provider must be configured)\r\n try {\r\n validateEnv();\r\n } catch (err) {\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n let storyText: string;\r\n try {\r\n storyText = await loadStoryText(options);\r\n } catch (err) {\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n\r\n const rootDir = process.cwd();\r\n const outputDir = options.output\r\n ? path.resolve(options.output)\r\n : path.join(rootDir, 'tests');\r\n\r\n printInfo(`Story: ${colors.dim(`${storyText.slice(0, 80)}${storyText.length > 80 ? '…' : ''}`)}`);\r\n if (options.suite) {\r\n printInfo(`Suite name: ${options.suite}`);\r\n }\r\n printInfo(`Output: ${outputDir}`);\r\n process.stdout.write('\\n');\r\n\r\n // Load AI layer\r\n const loadSpinner = createSpinner('Loading AI layer…');\r\n loadSpinner.start();\r\n\r\n let generateSuiteFromStory: (\r\n story: string,\r\n opts: { rootDir: string; outputDir: string; suiteName?: string },\r\n ) => Promise<void>;\r\n\r\n try {\r\n const mod = await import('../ai/router.js');\r\n generateSuiteFromStory = mod.generateSuiteFromStory;\r\n loadSpinner.succeed('AI layer ready');\r\n } catch {\r\n loadSpinner.fail('Failed to load AI layer');\r\n printError(\r\n 'AI layer could not be loaded.\\n' +\r\n ' Make sure you have run \"npm run build\" or are running from source.',\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // Generate the suite\r\n const genSpinner = createSpinner(\r\n `Generating test suite${options.suite ? ` \"${options.suite}\"` : ''}…`,\r\n );\r\n genSpinner.start();\r\n\r\n try {\r\n await generateSuiteFromStory(storyText, {\r\n rootDir,\r\n outputDir,\r\n suiteName: options.suite,\r\n });\r\n\r\n genSpinner.succeed('Suite generated');\r\n\r\n // Report what was created\r\n const suiteOutputDir = options.output ?? path.join(rootDir, 'tests');\r\n printSuccess(`Test suite created in: ${path.relative(rootDir, suiteOutputDir)}`);\r\n printInfo('Open Studio or use the Test Editor to review and generate Playwright code:');\r\n process.stdout.write(` ${colors.accent('npx assuremind studio')}\\n\\n`);\r\n } catch (err) {\r\n genSpinner.fail('Generation failed');\r\n printError(err instanceof Error ? err.message : String(err));\r\n process.exit(1);\r\n }\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport { printSuccess, printError, printWarn, printInfo, colors } from './ui.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\nimport { listSuiteDirs } from '../storage/suite-store.js';\r\nimport { listCasePaths, readCase } from '../storage/case-store.js';\r\nimport { listVariableFiles, readVariables } from '../storage/variable-store.js';\r\nimport { tryGetEnv } from '../utils/env.js';\r\n\r\ninterface ValidationResult {\r\n passed: number;\r\n warnings: number;\r\n errors: number;\r\n}\r\n\r\nasync function checkConfig(rootDir: string, result: ValidationResult): Promise<void> {\r\n printInfo('Checking configuration…');\r\n\r\n if (!(await fs.pathExists(path.join(rootDir, 'autotest.config.json'))) &&\r\n !(await fs.pathExists(path.join(rootDir, 'autotest.config.ts')))) {\r\n printError(' autotest.config.ts not found — run \"npx assuremind init\" to create it');\r\n result.errors++;\r\n return;\r\n }\r\n\r\n try {\r\n const config = await readConfig(rootDir);\r\n printSuccess(` Config valid — baseUrl: ${colors.accent(config.baseUrl)}, browsers: ${config.browsers.join(', ')}`);\r\n result.passed++;\r\n } catch (err) {\r\n printError(` Config invalid: ${err instanceof Error ? err.message : String(err)}`);\r\n result.errors++;\r\n }\r\n}\r\n\r\nasync function checkEnv(result: ValidationResult): Promise<void> {\r\n printInfo('Checking environment…');\r\n\r\n if (!(await fs.pathExists('.env'))) {\r\n printWarn(' .env file not found — copy .env.example to .env and fill in your API key');\r\n result.warnings++;\r\n return;\r\n }\r\n\r\n const env = tryGetEnv();\r\n if (!env) {\r\n printError(' .env validation failed — check required variables for your AI provider');\r\n result.errors++;\r\n return;\r\n }\r\n\r\n printSuccess(` Provider: ${colors.accent(String(env.AI_PROVIDER))}, tiered: ${env.AI_TIERED_ENABLED}`);\r\n result.passed++;\r\n}\r\n\r\nasync function checkTests(rootDir: string, result: ValidationResult): Promise<void> {\r\n printInfo('Scanning test files…');\r\n\r\n const testsDir = path.join(rootDir, 'tests');\r\n if (!(await fs.pathExists(testsDir))) {\r\n printWarn(' tests/ directory not found — no tests to validate');\r\n result.warnings++;\r\n return;\r\n }\r\n\r\n const suiteDirs = await listSuiteDirs(testsDir);\r\n if (suiteDirs.length === 0) {\r\n printWarn(' No test suites found — create one in Studio');\r\n result.warnings++;\r\n return;\r\n }\r\n\r\n let totalCases = 0;\r\n let invalidCases = 0;\r\n\r\n for (const suiteDir of suiteDirs) {\r\n const casePaths = await listCasePaths(suiteDir);\r\n totalCases += casePaths.length;\r\n\r\n for (const casePath of casePaths) {\r\n try {\r\n await readCase(casePath);\r\n } catch {\r\n printError(` Invalid: ${path.relative(rootDir, casePath)}`);\r\n invalidCases++;\r\n result.errors++;\r\n }\r\n }\r\n }\r\n\r\n const validCases = totalCases - invalidCases;\r\n if (invalidCases === 0) {\r\n printSuccess(` ${suiteDirs.length} suite(s), ${totalCases} test case(s) — all valid`);\r\n result.passed++;\r\n } else {\r\n printWarn(` ${suiteDirs.length} suite(s), ${validCases}/${totalCases} cases valid`);\r\n result.warnings++;\r\n }\r\n}\r\n\r\nasync function checkVariables(rootDir: string, result: ValidationResult): Promise<void> {\r\n printInfo('Checking variable files…');\r\n\r\n const files = await listVariableFiles(rootDir);\r\n if (files.length === 0) {\r\n printWarn(' No variable files found');\r\n result.warnings++;\r\n return;\r\n }\r\n\r\n let invalid = 0;\r\n for (const file of files) {\r\n try {\r\n await readVariables(file);\r\n } catch {\r\n printError(` Invalid: ${path.relative(rootDir, file)}`);\r\n invalid++;\r\n result.errors++;\r\n }\r\n }\r\n\r\n if (invalid === 0) {\r\n printSuccess(` ${files.length} variable file(s) — all valid`);\r\n result.passed++;\r\n } else {\r\n result.warnings++;\r\n }\r\n}\r\n\r\nexport async function runValidate(): Promise<void> {\r\n const rootDir = process.cwd();\r\n process.stdout.write('\\n');\r\n\r\n const result: ValidationResult = { passed: 0, warnings: 0, errors: 0 };\r\n\r\n await checkConfig(rootDir, result);\r\n process.stdout.write('\\n');\r\n\r\n await checkEnv(result);\r\n process.stdout.write('\\n');\r\n\r\n await checkTests(rootDir, result);\r\n process.stdout.write('\\n');\r\n\r\n await checkVariables(rootDir, result);\r\n process.stdout.write('\\n');\r\n\r\n // Summary\r\n const total = result.passed + result.warnings + result.errors;\r\n const statusLine = [\r\n result.passed > 0 ? colors.success(`${result.passed} passed`) : null,\r\n result.warnings > 0 ? colors.warn(`${result.warnings} warnings`) : null,\r\n result.errors > 0 ? colors.error(`${result.errors} errors`) : null,\r\n ]\r\n .filter(Boolean)\r\n .join(colors.dim(' | '));\r\n\r\n process.stdout.write(`Validation complete (${total} checks): ${statusLine}\\n\\n`);\r\n\r\n if (result.errors > 0) {\r\n process.exit(1);\r\n }\r\n}\r\n","import { execSync } from 'child_process';\r\nimport fs from 'fs-extra';\r\nimport { printSuccess, printError, printInfo, colors, printBox } from './ui.js';\r\nimport { tryGetEnv } from '../utils/env.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\n\r\ninterface CheckResult {\r\n label: string;\r\n ok: boolean;\r\n detail: string;\r\n}\r\n\r\nfunction check(label: string, ok: boolean, detail: string): CheckResult {\r\n return { label, ok, detail };\r\n}\r\n\r\nfunction runCommand(cmd: string): string {\r\n try {\r\n return execSync(cmd, { stdio: 'pipe' }).toString().trim();\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nasync function checkNodeVersion(): Promise<CheckResult> {\r\n const version = process.version; // e.g. \"v20.11.0\"\r\n const major = parseInt(version.slice(1).split('.')[0], 10);\r\n if (major >= 18) {\r\n return check('Node.js', true, `${version} (>= 18 required)`);\r\n }\r\n return check(\r\n 'Node.js',\r\n false,\r\n `${version} is too old — upgrade to Node.js >= 18 from https://nodejs.org`,\r\n );\r\n}\r\n\r\nasync function checkNpm(): Promise<CheckResult> {\r\n const version = runCommand('npm --version');\r\n if (version) {\r\n return check('npm', true, `v${version}`);\r\n }\r\n return check('npm', false, 'npm not found — ensure Node.js is installed correctly');\r\n}\r\n\r\nasync function checkPlaywright(): Promise<CheckResult> {\r\n const output = runCommand('npx playwright --version');\r\n if (!output) {\r\n return check(\r\n 'Playwright',\r\n false,\r\n 'Not found — run \"npx assuremind init\" to install',\r\n );\r\n }\r\n\r\n // Check if browsers are installed by running a quick status check\r\n try {\r\n execSync('npx playwright install --dry-run 2>&1', { stdio: 'pipe' });\r\n return check('Playwright', true, `${output} — browsers installed`);\r\n } catch {\r\n return check(\r\n 'Playwright',\r\n false,\r\n `${output} installed but browsers may be missing — run \"npx playwright install --with-deps\"`,\r\n );\r\n }\r\n}\r\n\r\nasync function checkEnvFile(): Promise<CheckResult> {\r\n if (!(await fs.pathExists('.env'))) {\r\n return check(\r\n '.env file',\r\n false,\r\n 'Missing — copy .env.example to .env and fill in your API key',\r\n );\r\n }\r\n\r\n const env = tryGetEnv();\r\n if (!env) {\r\n return check(\r\n '.env file',\r\n false,\r\n 'Present but invalid — check required variables for your AI provider',\r\n );\r\n }\r\n\r\n return check(\r\n '.env file',\r\n true,\r\n `Provider: ${String(env.AI_PROVIDER)}, tiered: ${env.AI_TIERED_ENABLED}`,\r\n );\r\n}\r\n\r\nasync function checkConfig(): Promise<CheckResult> {\r\n try {\r\n const config = await readConfig(process.cwd());\r\n return check(\r\n 'Config',\r\n true,\r\n `baseUrl: ${config.baseUrl}, port: ${config.studioPort}`,\r\n );\r\n } catch (err) {\r\n return check(\r\n 'Config',\r\n false,\r\n err instanceof Error ? err.message : 'Config validation failed',\r\n );\r\n }\r\n}\r\n\r\nasync function checkPackageJson(): Promise<CheckResult> {\r\n if (!(await fs.pathExists('package.json'))) {\r\n return check(\r\n 'package.json',\r\n false,\r\n 'Not found — run \"npm init -y\" first',\r\n );\r\n }\r\n try {\r\n const pkg = await fs.readJson('package.json') as { name?: string; version?: string };\r\n return check('package.json', true, `${pkg.name ?? 'unnamed'} v${pkg.version ?? '?'}`);\r\n } catch {\r\n return check('package.json', false, 'Exists but is not valid JSON');\r\n }\r\n}\r\n\r\nasync function checkAIConnectivity(): Promise<CheckResult> {\r\n const env = tryGetEnv();\r\n if (!env) {\r\n return check('AI connectivity', false, 'Cannot check — .env not configured');\r\n }\r\n\r\n // Only test connectivity for providers that have a simple health check\r\n const provider = String(env.AI_PROVIDER);\r\n\r\n // Attempt a minimal HTTP ping based on provider\r\n const endpoints: Record<string, string> = {\r\n anthropic: 'https://api.anthropic.com',\r\n openai: 'https://api.openai.com',\r\n google: 'https://generativelanguage.googleapis.com',\r\n groq: 'https://api.groq.com',\r\n deepseek: 'https://api.deepseek.com',\r\n together: 'https://api.together.xyz',\r\n perplexity: 'https://api.perplexity.ai',\r\n };\r\n\r\n const endpoint = endpoints[provider];\r\n if (!endpoint) {\r\n return check('AI connectivity', true, `${provider} — skipped (local/custom provider)`);\r\n }\r\n\r\n try {\r\n const result = runCommand(`curl -s -o /dev/null -w \"%{http_code}\" --max-time 5 \"${endpoint}\"`);\r\n const code = parseInt(result, 10);\r\n // Any HTTP response (even 401/403) means the host is reachable\r\n if (code > 0) {\r\n return check('AI connectivity', true, `${provider} endpoint reachable (HTTP ${code})`);\r\n }\r\n return check(\r\n 'AI connectivity',\r\n false,\r\n `${provider} endpoint unreachable — check your network or VPN`,\r\n );\r\n } catch {\r\n return check('AI connectivity', false, `Could not reach ${provider} endpoint`);\r\n }\r\n}\r\n\r\nfunction printCheckResult(result: CheckResult): void {\r\n if (result.ok) {\r\n printSuccess(` ${colors.bold(result.label)}: ${colors.dim(result.detail)}`);\r\n } else {\r\n printError(` ${colors.bold(result.label)}: ${result.detail}`);\r\n }\r\n}\r\n\r\nexport async function runDoctor(): Promise<void> {\r\n process.stdout.write('\\n');\r\n printInfo('Running Assuremind system diagnostics…\\n');\r\n\r\n const checks = await Promise.all([\r\n checkNodeVersion(),\r\n checkNpm(),\r\n checkPackageJson(),\r\n checkPlaywright(),\r\n checkEnvFile(),\r\n checkConfig(),\r\n checkAIConnectivity(),\r\n ]);\r\n\r\n for (const result of checks) {\r\n printCheckResult(result);\r\n }\r\n\r\n const failed = checks.filter((c) => !c.ok);\r\n const passed = checks.filter((c) => c.ok);\r\n\r\n process.stdout.write('\\n');\r\n\r\n if (failed.length === 0) {\r\n printBox([\r\n '✅ All checks passed — Assuremind is ready!',\r\n '',\r\n 'Run: npx assuremind studio',\r\n ]);\r\n } else {\r\n printBox([\r\n `⚠ ${passed.length}/${checks.length} checks passed`,\r\n '',\r\n 'Fix the issues above, then run \"npx assuremind doctor\" again.',\r\n ]);\r\n process.exit(1);\r\n }\r\n}\r\n","import path from 'path';\r\nimport fs from 'fs-extra';\r\nimport readline from 'readline';\r\nimport { config as loadDotenv } from 'dotenv';\r\nimport {\r\n readPendingEvents,\r\n readHealingReport,\r\n acceptHealingEvent,\r\n rejectHealingEvent,\r\n} from '../storage/healing-store.js';\r\nimport { listSuiteDirs } from '../storage/suite-store.js';\r\nimport { listCasePaths, readCase, writeCase } from '../storage/case-store.js';\r\nimport { readConfig } from '../storage/config-store.js';\r\nimport { GitService } from '../git/service.js';\r\nimport { printSuccess, printError, printInfo, printWarn, colors } from './ui.js';\r\nimport type { HealingEvent } from '../types/healing.js';\r\n\r\ninterface ApplyOptions {\r\n from?: string;\r\n yes?: boolean;\r\n}\r\n\r\n// ─── File update logic ────────────────────────────────────────────────────────\r\n\r\nasync function findCaseFilePath(\r\n testsDir: string,\r\n caseId: string,\r\n): Promise<string | null> {\r\n const suiteDirs = await listSuiteDirs(testsDir);\r\n for (const suiteDir of suiteDirs) {\r\n const casePaths = await listCasePaths(suiteDir);\r\n for (const casePath of casePaths) {\r\n try {\r\n const tc = await readCase(casePath);\r\n if (tc.id === caseId) return casePath;\r\n } catch {\r\n // skip malformed files\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nasync function applyHealToFile(\r\n rootDir: string,\r\n event: HealingEvent,\r\n): Promise<void> {\r\n const testsDir = path.join(rootDir, 'tests');\r\n const casePath = await findCaseFilePath(testsDir, event.caseId);\r\n\r\n if (!casePath) {\r\n throw new Error(\r\n `Test case \"${event.caseId}\" not found in ${testsDir}. ` +\r\n `The file may have been deleted or renamed since the heal was recorded.`,\r\n );\r\n }\r\n\r\n const testCase = await readCase(casePath);\r\n const stepIdx = testCase.steps.findIndex((s) => s.id === event.stepId);\r\n\r\n if (stepIdx === -1) {\r\n throw new Error(\r\n `Step \"${event.stepId}\" not found in \"${testCase.name}\". ` +\r\n `The step may have been deleted since the heal was recorded.`,\r\n );\r\n }\r\n\r\n testCase.steps[stepIdx] = {\r\n ...testCase.steps[stepIdx],\r\n generatedCode: event.healedCode,\r\n lastHealed: new Date().toISOString(),\r\n };\r\n testCase.updatedAt = new Date().toISOString();\r\n\r\n await writeCase(casePath, testCase);\r\n printSuccess(\r\n ` Updated: ${path.relative(rootDir, casePath)} › step \"${testCase.steps[stepIdx].instruction}\"`,\r\n );\r\n}\r\n\r\n// ─── Interactive prompt ───────────────────────────────────────────────────────\r\n\r\nfunction ask(rl: readline.Interface, question: string): Promise<string> {\r\n return new Promise((resolve) => rl.question(question, resolve));\r\n}\r\n\r\nfunction printDiff(event: HealingEvent): void {\r\n process.stdout.write(\r\n `\\n ${colors.bold('Step:')} ${event.stepInstruction}\\n` +\r\n ` ${colors.bold('Case:')} ${event.caseId}\\n` +\r\n ` ${colors.dim('Error:')} ${event.error}\\n\\n` +\r\n ` ${colors.error('- ' + event.failedCode)}\\n` +\r\n ` ${colors.success('+ ' + event.healedCode)}\\n`,\r\n );\r\n}\r\n\r\nasync function processInteractively(\r\n rootDir: string,\r\n events: HealingEvent[],\r\n acceptAll: boolean,\r\n): Promise<{ accepted: number; rejected: number; skipped: number }> {\r\n const stats = { accepted: 0, rejected: 0, skipped: 0 };\r\n\r\n const rl = readline.createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n try {\r\n for (let i = 0; i < events.length; i++) {\r\n const event = events[i];\r\n process.stdout.write(\r\n `\\n${colors.accent(`[${i + 1}/${events.length}]`)} Healing event ${colors.dim(event.id)}\\n`,\r\n );\r\n printDiff(event);\r\n\r\n let answer: string;\r\n\r\n if (acceptAll) {\r\n answer = 'y';\r\n process.stdout.write(` Accept? ${colors.dim('(auto-accepting all)')} y\\n`);\r\n } else {\r\n answer = (\r\n await ask(rl, ` Accept? ${colors.dim('(y)es / (n)o / (a)ll / (q)uit')} > `)\r\n )\r\n .trim()\r\n .toLowerCase();\r\n }\r\n\r\n if (answer === 'q' || answer === 'quit') {\r\n printWarn(` Stopping — ${events.length - i} heals remaining`);\r\n stats.skipped += events.length - i;\r\n break;\r\n }\r\n\r\n if (answer === 'a' || answer === 'all') {\r\n acceptAll = true;\r\n answer = 'y';\r\n }\r\n\r\n if (answer === 'y' || answer === 'yes') {\r\n try {\r\n await applyHealToFile(rootDir, event);\r\n await acceptHealingEvent(rootDir, event.id);\r\n stats.accepted++;\r\n } catch (err) {\r\n printError(` Failed to apply: ${err instanceof Error ? err.message : String(err)}`);\r\n stats.skipped++;\r\n }\r\n } else {\r\n await rejectHealingEvent(rootDir, event.id);\r\n printInfo(` Rejected — step will keep original code`);\r\n stats.rejected++;\r\n }\r\n }\r\n } finally {\r\n rl.close();\r\n }\r\n\r\n return stats;\r\n}\r\n\r\n// ─── Auto PR on CI Heal ───────────────────────────────────────────────────────\r\n\r\nasync function createHealingPR(\r\n rootDir: string,\r\n acceptedCount: number,\r\n): Promise<void> {\r\n const token = process.env.GITHUB_TOKEN;\r\n const owner = process.env.GITHUB_REPO_OWNER;\r\n const repo = process.env.GITHUB_REPO_NAME;\r\n const baseBranch = process.env.GITHUB_BASE_BRANCH || 'main';\r\n\r\n if (!token || !owner || !repo) {\r\n printWarn(\r\n 'Auto PR skipped — missing GITHUB_TOKEN, GITHUB_REPO_OWNER, or GITHUB_REPO_NAME in .env',\r\n );\r\n return;\r\n }\r\n\r\n const git = new GitService(rootDir);\r\n const timestamp = Date.now();\r\n const branchName = `fix/self-heal-${timestamp}`;\r\n\r\n try {\r\n // 1. Create and checkout a new branch\r\n printInfo('Creating healing branch...');\r\n const simpleGitRaw = (git as any).git as import('simple-git').SimpleGit;\r\n await simpleGitRaw.checkoutLocalBranch(branchName);\r\n\r\n // 2. Stage and commit healed files\r\n printInfo('Committing healed code...');\r\n const commitMsg = `fix: apply ${acceptedCount} self-healed selector(s)\\n\\nAuto-generated by AutoMind self-healing engine.`;\r\n await git.commit(commitMsg);\r\n\r\n // 3. Push the branch to remote\r\n printInfo('Pushing branch to remote...');\r\n await simpleGitRaw.push('origin', branchName, ['--set-upstream']);\r\n\r\n // 4. Create PR via GitHub REST API\r\n printInfo('Creating pull request...');\r\n const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n Accept: 'application/vnd.github+json',\r\n 'Content-Type': 'application/json',\r\n 'X-GitHub-Api-Version': '2022-11-28',\r\n },\r\n body: JSON.stringify({\r\n title: `fix: self-healed ${acceptedCount} broken selector(s)`,\r\n body:\r\n `## Self-Healing Auto PR\\n\\n` +\r\n `AutoMind detected and fixed **${acceptedCount}** broken test selector(s) during CI execution.\\n\\n` +\r\n `### What changed\\n` +\r\n `- Healed selectors were automatically updated in test case files\\n` +\r\n `- Changes were validated by the self-healing engine (6-level cascade)\\n\\n` +\r\n `### Action required\\n` +\r\n `Review the changes and merge if the fixes look correct.\\n\\n` +\r\n `---\\n` +\r\n `🤖 *Auto-generated by AutoMind*`,\r\n head: branchName,\r\n base: baseBranch,\r\n }),\r\n });\r\n\r\n if (response.ok) {\r\n const pr = (await response.json()) as { html_url: string; number: number };\r\n printSuccess(`Pull request created: ${pr.html_url}`);\r\n } else {\r\n const err = (await response.json()) as { message?: string };\r\n printError(`Failed to create PR: ${err.message || response.statusText}`);\r\n }\r\n\r\n // 5. Switch back to original branch\r\n await git.checkout(baseBranch);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n printError(`Auto PR failed: ${msg}`);\r\n // Try to switch back to base branch\r\n try {\r\n await git.checkout(baseBranch);\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n}\r\n\r\n// ─── Command entry point ──────────────────────────────────────────────────────\r\n\r\nexport async function runApplyHealing(options: ApplyOptions): Promise<void> {\r\n const rootDir = process.cwd();\r\n // Load .env so GITHUB_TOKEN etc. are available for auto PR\r\n loadDotenv({ path: path.join(rootDir, '.env') });\r\n process.stdout.write('\\n');\r\n\r\n let events: HealingEvent[];\r\n\r\n if (options.from) {\r\n // Load from a specific healing report file\r\n const reportPath = path.resolve(options.from);\r\n if (!(await fs.pathExists(reportPath))) {\r\n printError(`Healing report not found: ${reportPath}`);\r\n process.exit(1);\r\n }\r\n try {\r\n const rawRunId = path.basename(reportPath, '.json').replace('healing-report-', '');\r\n const report = await readHealingReport(rootDir, rawRunId);\r\n events = report.events.filter((e) => e.status === 'pending');\r\n } catch {\r\n // Try reading as a raw events array\r\n const raw = await fs.readJson(reportPath) as { events?: HealingEvent[] } | HealingEvent[];\r\n events = Array.isArray(raw)\r\n ? raw.filter((e) => e.status === 'pending')\r\n : (raw.events ?? []).filter((e) => e.status === 'pending');\r\n }\r\n } else {\r\n events = (await readPendingEvents(rootDir)).filter((e) => e.status === 'pending');\r\n }\r\n\r\n if (events.length === 0) {\r\n printInfo('No pending healing events found — nothing to apply.');\r\n return;\r\n }\r\n\r\n printInfo(`Found ${colors.bold(String(events.length))} pending healing event(s).\\n`);\r\n\r\n const stats = await processInteractively(rootDir, events, options.yes ?? false);\r\n\r\n process.stdout.write('\\n');\r\n printInfo(\r\n `Done: ${colors.success(String(stats.accepted) + ' accepted')}, ` +\r\n `${colors.error(String(stats.rejected) + ' rejected')}, ` +\r\n `${colors.dim(String(stats.skipped) + ' skipped')}`,\r\n );\r\n process.stdout.write('\\n');\r\n\r\n // Auto PR: if heals were accepted and autoPR is enabled in config\r\n if (stats.accepted > 0) {\r\n try {\r\n const config = await readConfig(rootDir);\r\n if (config.healing.autoPR) {\r\n printInfo('Auto PR enabled — creating pull request with healed code...\\n');\r\n await createHealingPR(rootDir, stats.accepted);\r\n }\r\n } catch {\r\n // Config read failed — skip auto PR silently\r\n }\r\n }\r\n}\r\n","import { Command } from 'commander';\r\nimport { createRequire } from 'module';\r\nimport { handleFatalError } from './ui.js';\r\n\r\nconst require = createRequire(__filename);\r\n// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\nconst pkg = require('../../package.json') as { version: string; description: string };\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('assuremind')\r\n .description(pkg.description)\r\n .version(pkg.version, '-v, --version', 'Print version number');\r\n\r\n// ─── init ─────────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('init')\r\n .description('Initialise Assuremind in the current project')\r\n .option('--skip-playwright', 'Skip Playwright browser installation')\r\n .action(async (options: { skipPlaywright?: boolean }) => {\r\n const { runInit } = await import('./init.js');\r\n await runInit({ skipPlaywright: options.skipPlaywright }).catch(handleFatalError);\r\n });\r\n\r\n// ─── studio ───────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('studio')\r\n .description('Open the Assuremind web UI')\r\n .option('-p, --port <number>', 'Override studio port', parseInt)\r\n .option('--no-open', 'Do not open browser automatically')\r\n .action(async (options: { port?: number; open?: boolean }) => {\r\n const { runStudio } = await import('./studio.js');\r\n await runStudio({\r\n port: options.port,\r\n noOpen: options.open === false,\r\n }).catch(handleFatalError);\r\n });\r\n\r\n// ─── run ──────────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('run')\r\n .description('Run tests from the command line')\r\n .option('--all', 'Run all test suites')\r\n .option('--type <type>', 'Filter suites by type: ui, api, audit, performance')\r\n .option('--suite <name>', 'Run suite(s) matching name (case-insensitive partial match) or ID')\r\n .option('--tag <tag>', 'Run all tests matching a tag')\r\n .option('--test <name>', 'Run test(s) matching name (case-insensitive partial match) or ID')\r\n .option('--browser <list...>', 'Browser(s) to use: chromium, firefox, webkit')\r\n .option('--device <name>', 'Emulate a device (e.g. \"iPhone 15 Pro\", \"Pixel 7\", \"iPad Pro 11\")')\r\n .option('--env <name>', 'Environment to use (dev, staging, prod)')\r\n .option('--parallel <n>', 'Number of parallel workers', parseInt)\r\n .option('--headed', 'Run in headed (visible) mode')\r\n .option('--ci', 'CI mode — no interactive prompts, exit code reflects pass/fail')\r\n .option('--reporter <list...>', 'Reporter(s): allure, html, json')\r\n .option('--no-healing', 'Disable self-healing for this run')\r\n .addHelpText('after', `\r\nExamples:\r\n assuremind run --all\r\n assuremind run --type ui\r\n assuremind run --type audit\r\n assuremind run --suite \"My Suite\"\r\n assuremind run --tag smoke\r\n assuremind run --tag regression\r\n assuremind run --test \"Login with valid credentials\"\r\n assuremind run --type audit --tag regression\r\n assuremind run --suite \"Orange HRM\" --tag smoke\r\n assuremind run --all --browser chromium --headed\r\n assuremind run --all --device \"iPhone 15 Pro\" --browser chromium\r\n assuremind run --tag smoke --device \"Pixel 7\"\r\n assuremind run --all --device \"iPad Pro 11\" --browser webkit\r\n\r\nFilters are combinable (AND logic — all specified filters must match).\r\nDevice names must match Playwright device descriptors exactly (case-sensitive).\r\n`)\r\n .action(async (options) => {\r\n const { runRun } = await import('./run.js');\r\n await runRun({\r\n all: options.all as boolean | undefined,\r\n type: options.type as string | undefined,\r\n suite: options.suite as string | undefined,\r\n tag: options.tag as string | undefined,\r\n test: options.test as string | undefined,\r\n browser: options.browser as string[] | undefined,\r\n device: options.device as string | undefined,\r\n env: options.env as string | undefined,\r\n parallel: options.parallel as number | undefined,\r\n headed: options.headed as boolean | undefined,\r\n ci: options.ci as boolean | undefined,\r\n reporter: options.reporter as string[] | undefined,\r\n noHealing: options.noHealing as boolean | undefined,\r\n }).catch(handleFatalError);\r\n });\r\n\r\n// ─── generate ─────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('generate')\r\n .description('Generate test cases from a user story')\r\n .option('--story <text>', 'User story text (plain English)')\r\n .option('--story-file <path>', 'Path to a file containing the user story')\r\n .option('--suite <name>', 'Name of the suite to create')\r\n .option('--output <path>', 'Output directory (default: tests/)')\r\n .action(async (options: { story?: string; storyFile?: string; suite?: string; output?: string }) => {\r\n const { runGenerate } = await import('./generate.js');\r\n await runGenerate(options).catch(handleFatalError);\r\n });\r\n\r\n// ─── validate ─────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('validate')\r\n .description('Validate config, environment, and test files')\r\n .action(async () => {\r\n const { runValidate } = await import('./validate.js');\r\n await runValidate().catch(handleFatalError);\r\n });\r\n\r\n// ─── doctor ───────────────────────────────────────────────────────────────────\r\nprogram\r\n .command('doctor')\r\n .description('Check system requirements and configuration health')\r\n .action(async () => {\r\n const { runDoctor } = await import('./doctor.js');\r\n await runDoctor().catch(handleFatalError);\r\n });\r\n\r\n// ─── apply-healing ────────────────────────────────────────────────────────────\r\nprogram\r\n .command('apply-healing')\r\n .description('Review and apply self-healing suggestions to test files')\r\n .option('--from <path>', 'Path to a specific healing report JSON file')\r\n .option('-y, --yes', 'Accept all pending heals without prompting')\r\n .action(async (options: { from?: string; yes?: boolean }) => {\r\n const { runApplyHealing } = await import('./apply-healing.js');\r\n await runApplyHealing(options).catch(handleFatalError);\r\n });\r\n\r\nprogram.parse(process.argv);\r\n"],"mappings":"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","names":["ora","chalk","path","fs","DEFAULT_CONFIG","path","import_zod","loadDotenv","path","fs","import_fs_extra","import_path","pino","path","fs","import_path","import_fs_extra","path","fs","logger","import_path","import_fs_extra","logger","path","fs","logger","import_path","import_fs_extra","logger","init_utils","init_config","init_utils","import_zod","path","fs","logger","now","uuidv4","import_path","import_fs_extra","path","import_path","import_zod","init_utils","fs","logger","now","uuidv4","path","import_path","import_fs_extra","import_uuid","path","import_path","import_zod","init_utils","import_zod","fs","logger","path","import_path","import_fs_extra","import_path","import_fs_extra","logger","path","fs","logger","logger","import_zod","init_types","SYSTEM_PROMPT","SYSTEM_PROMPT","SYSTEM_PROMPT","init_types","Anthropic","OpenAI","import_openai","OpenAI","import_openai","OpenAI","import_openai","OpenAI","AnthropicProvider","OpenAIProvider","GoogleProvider","AzureOpenAIProvider","BedrockProvider","DeepSeekProvider","GroqProvider","TogetherProvider","QwenProvider","PerplexityProvider","OllamaProvider","CustomProvider","logger","path","fs","randomUUID","import_path","import_fs_extra","path","import_path","import_crypto","import_zod","init_utils","path","fs","logger","import_path","import_fs_extra","import_crypto","path","AddStepBody","ReorderBody","UpdateStepBody","import_path","import_zod","init_utils","import_zod","init_utils","import_zod","path","logger","fs","import_path","import_fs_extra","path","logger","fs","listSuiteDirs","import_path","import_zod","init_healing","init_utils","import_zod","path","logger","fs","import_path","import_fs_extra","logger","pwRequest","logger","import_crypto","logger","import_path","import_crypto","import_fs_extra","logger","path","fs","stop","path","fs","logger","import_path","import_fs_extra","import_child_process","logger","code","sanitized","logger","path","import_path","path","fs","logger","import_path","import_fs_extra","exports","module","exports","module","exports","module","debug","exports","module","exports","module","exports","module","exports","module","useColors","debug","exports","module","isWindows","colors","process","debug","exports","module","fs","exports","module","fs","isWsl","isWsl","childProcess","path","import_path","import_child_process","init_utils","path","escapeRegExp","fs","import_fs","import_path","import_child_process","init_utils","fs","import_child_process","isWsl","isWindows","init_utils","path","logger","fs","launch","import_path","import_crypto","import_fs_extra","logger","import_zod","init_run","init_utils","logger","yaml","logger","path","import_path","import_zod","init_utils","logger","import_zod","init_utils","path","fs","import_path","import_fs_extra","path","fs","import_path","import_fs_extra","init_utils","logger","path","import_zod","path","fs","logger","import_path","import_fs_extra","crypto","import_crypto","logger","now","logger","init_xray","init_utils","import_fs_extra","import_path","logger","init_service","simpleGit","status","path","fs","logger","logger","listSuiteDirs","readSuite","listCases","path","import_path","import_zod","init_service","init_utils","path","fs","logger","import_path","import_fs_extra","init_utils","path","import_path","init_utils","yaml","import_zod","init_utils","init_utils","init_utils","path","fs","now","uuidv4","import_path","import_fs_extra","import_uuid","import_zod","import_zod","init_utils","Fastify","cors","websocketPlugin","logger","init_config","init_healing","init_run","init_xray","startServer","open","runTests","init_run","path","fs","generateSuiteFromStory","import_path","import_fs_extra","fs","path","import_path","import_fs_extra","fs","checkConfig","pkg","import_child_process","import_fs_extra","path","readline","loadDotenv","fs","import_path","import_fs_extra","import_dotenv","init_service","require","runInit","runStudio","runRun","runGenerate","runValidate","runDoctor","runApplyHealing"]}
|