@blockyfy/stg-cli 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/scanner.ts","../src/salt.ts","../src/deterministic-id.ts","../src/mutator.ts","../src/reverser.ts","../src/secrets.ts","../src/store.ts","../src/config.ts","../src/audit.ts","../src/proxy.ts","../src/auth.ts","../src/session-store.ts","../src/git-context.ts","../src/commands/login.ts","../src/backend-client.ts","../src/log-uploader.ts","../src/start-client-instructions.ts","../src/version.ts","../src/token-footer.ts","../src/banner.ts","../src/commands/status.ts","../src/commands/upgrade.ts","../src/commands/credits.ts","../src/commands/logout.ts"],"sourcesContent":["/**\r\n * Pretense CLI — Entry Point\r\n *\r\n * AI firewall CLI that mutates proprietary code identifiers before\r\n * sending to LLM APIs. Commands: init, start, scan, mutate, reverse,\r\n * audit, status, usage, tokens, upgrade, credits, login, logout, version.\r\n */\r\n\r\n// ─── Node version preflight (must run before any other imports execute) ─────\r\n{\r\n const major = parseInt(process.versions.node.split(\".\")[0]!, 10);\r\n if (Number.isNaN(major) || major < 18) {\r\n process.stderr.write(\r\n `pretense requires Node.js 18 or newer (you have v${process.versions.node}).\\n`,\r\n );\r\n process.stderr.write(`Upgrade via nvm: nvm install 20 && nvm use 20\\n`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\nimport { Command } from \"commander\";\r\nimport chalk from \"chalk\";\r\nimport {\r\n readFileSync,\r\n existsSync,\r\n readdirSync,\r\n statSync,\r\n openSync,\r\n readSync,\r\n closeSync,\r\n Dirent,\r\n} from \"fs\";\r\nimport { readFile, stat as fsStat, open as fsOpen } from \"fs/promises\";\r\nimport { resolve, extname, join, basename } from \"path\";\r\nimport os from \"node:os\";\r\nimport { scan, detectLanguage } from \"./scanner.js\";\r\nimport { mutate } from \"./mutator.js\";\r\nimport { reverse } from \"./reverser.js\";\r\nimport { scan as scanSecrets, applyRedactionsTracked } from \"./secrets.js\";\r\nimport { buildSaltedSeed } from \"./salt.js\";\r\nimport { MutationStore } from \"./store.js\";\r\nimport { initConfig, loadConfig, getConfigDir } from \"./config.js\";\r\nimport { readAuditLog, formatAudit } from \"./audit.js\";\r\nimport { startProxy } from \"./proxy.js\";\r\nimport { printTokenFooter } from \"./token-footer.js\";\r\nimport { printBanner } from \"./banner.js\";\r\nimport { runStatus } from \"./commands/status.js\";\r\nimport { runUpgrade } from \"./commands/upgrade.js\";\r\nimport { runCredits } from \"./commands/credits.js\";\r\nimport { ensureDashboardKeyForStart, logDashboardCredentialHint, runLogin } from \"./commands/login.js\";\r\nimport { runLogout } from \"./commands/logout.js\";\r\nimport { getCliSemver } from \"./version.js\";\r\n\r\nconst VERSION = getCliSemver();\r\n\r\n// ─── Scan defaults (P0 hang fix) ─────────────────────────────────────────────\r\n// Files larger than the --max-file-size value (default: 10mb) are skipped.\r\n// Real-world source files are almost always < 1 MB; anything larger is\r\n// typically generated/minified/vendored data that wedges the regex scanner\r\n// with no useful signal.\r\n//\r\n// Concurrency cap for parallel file scanning (1 worker per logical CPU,\r\n// minimum 2 to keep things moving on single-core CI).\r\nconst SCAN_CONCURRENCY = Math.max(2, os.cpus().length);\r\n// Throttle for streaming progress updates so we don't flood stderr.\r\nconst PROGRESS_INTERVAL_MS = 500;\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────────────\r\n\r\nconst SUPPORTED_LANGUAGES = [\"typescript\", \"javascript\", \"python\", \"go\", \"java\", \"csharp\", \"ruby\", \"rust\"];\r\n\r\nconst SUPPORTED_EXTENSIONS = new Set([\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".py\", \".go\", \".java\", \".cs\", \".rb\", \".rs\"]);\r\n\r\n// Additional config/data file types scanned for secrets (not for identifier mutation).\r\nconst SUPPORTED_CONFIG_EXTENSIONS = new Set([\r\n \".json\", \".yaml\", \".yml\", \".toml\", \".env\", \".cfg\", \".ini\",\r\n \".tf\", \".tfstate\", \".tfvars\", \".hcl\",\r\n \".properties\", \".conf\", \".xml\", \".plist\",\r\n \".pem\", \".key\", \".crt\", \".pub\", \".pfx\", \".p12\", \".htpasswd\",\r\n]);\r\n\r\nconst SUPPORTED_FILENAMES = new Set([\r\n \".env\",\r\n \".env.local\",\r\n \".env.production\",\r\n \".env.development\",\r\n \".env.staging\",\r\n \".env.test\",\r\n \".npmrc\",\r\n \".netrc\",\r\n \".pypirc\",\r\n \"Dockerfile\",\r\n \"docker-compose.yml\",\r\n \"docker-compose.yaml\",\r\n]);\r\n\r\nfunction isScannableFile(filePath: string): boolean {\r\n const ext = extname(filePath).toLowerCase();\r\n return (\r\n SUPPORTED_EXTENSIONS.has(ext) ||\r\n SUPPORTED_CONFIG_EXTENSIONS.has(ext) ||\r\n SUPPORTED_FILENAMES.has(basename(filePath))\r\n );\r\n}\r\n\r\nfunction isSourceCodeFile(filePath: string): boolean {\r\n return SUPPORTED_EXTENSIONS.has(extname(filePath).toLowerCase());\r\n}\r\n\r\nfunction langFromExt(filePath: string): string {\r\n const ext = extname(filePath).toLowerCase();\r\n const map: Record<string, string> = {\r\n \".ts\": \"typescript\",\r\n \".tsx\": \"typescript\",\r\n \".js\": \"javascript\",\r\n \".jsx\": \"javascript\",\r\n \".mjs\": \"javascript\",\r\n \".cjs\": \"javascript\",\r\n \".py\": \"python\",\r\n \".go\": \"go\",\r\n \".java\": \"java\",\r\n \".cs\": \"csharp\",\r\n \".rb\": \"ruby\",\r\n \".rs\": \"rust\",\r\n };\r\n return map[ext] ?? \"typescript\";\r\n}\r\n\r\n/**\r\n * Validate a port number string. Returns the parsed integer or null if invalid.\r\n */\r\nfunction validatePort(value: string): number | null {\r\n const port = parseInt(value, 10);\r\n if (isNaN(port) || port.toString() !== value.trim()) return null;\r\n if (port < 1 || port > 65535) return null;\r\n return port;\r\n}\r\n\r\n/**\r\n * Detect if a file is likely binary by checking for null bytes\r\n * in the first 8KB. Only reads the bytes needed, not the whole file.\r\n */\r\nfunction isBinaryFile(filePath: string): boolean {\r\n let fd: number | undefined;\r\n try {\r\n fd = openSync(filePath, \"r\");\r\n const buf = Buffer.alloc(8192);\r\n const bytesRead = readSync(fd, buf, 0, 8192, 0);\r\n for (let i = 0; i < bytesRead; i++) {\r\n if (buf[i] === 0) return true;\r\n }\r\n return false;\r\n } catch {\r\n return false;\r\n } finally {\r\n if (fd !== undefined) closeSync(fd);\r\n }\r\n}\r\n\r\n/**\r\n * Async binary-file probe — reads only the first 8KB.\r\n * Used by the concurrent scanner so we never block the event loop.\r\n */\r\nasync function isBinaryFileAsync(filePath: string): Promise<boolean> {\r\n let handle: import(\"fs/promises\").FileHandle | undefined;\r\n try {\r\n handle = await fsOpen(filePath, \"r\");\r\n const buf = Buffer.alloc(8192);\r\n const { bytesRead } = await handle.read(buf, 0, 8192, 0);\r\n for (let i = 0; i < bytesRead; i++) {\r\n if (buf[i] === 0) return true;\r\n }\r\n return false;\r\n } catch {\r\n return false;\r\n } finally {\r\n if (handle) await handle.close().catch(() => {});\r\n }\r\n}\r\n\r\n/**\r\n * Validate that a language string is supported. Returns the normalized\r\n * language or null if unsupported.\r\n */\r\nfunction validateLanguage(lang: string): string | null {\r\n const normalized = lang.toLowerCase();\r\n const aliases: Record<string, string> = {\r\n ts: \"typescript\", tsx: \"typescript\",\r\n js: \"javascript\", jsx: \"javascript\",\r\n py: \"python\",\r\n cs: \"csharp\",\r\n rb: \"ruby\",\r\n rs: \"rust\",\r\n };\r\n const resolved = aliases[normalized] ?? normalized;\r\n return SUPPORTED_LANGUAGES.includes(resolved) ? resolved : null;\r\n}\r\n\r\nfunction collectFiles(target: string): string[] {\r\n const abs = resolve(target);\r\n if (!existsSync(abs)) {\r\n return [];\r\n }\r\n const stat = statSync(abs);\r\n if (stat.isFile()) return [abs];\r\n\r\n const files: string[] = [];\r\n\r\n function walk(dir: string): void {\r\n let entries: Dirent[];\r\n try {\r\n entries = readdirSync(dir, { withFileTypes: true });\r\n } catch {\r\n // EPERM on ~/.Trash and similar protected dirs (macOS); ENOENT races; skip.\r\n return;\r\n }\r\n const skipDirs = new Set([\r\n \"node_modules\",\r\n \".git\",\r\n \"dist\",\r\n \"build\",\r\n \".pretense\",\r\n \".next\",\r\n \"__pycache__\",\r\n \".Trash\",\r\n ]);\r\n for (const entry of entries) {\r\n const fullPath = join(dir, entry.name);\r\n if (entry.isDirectory()) {\r\n if (skipDirs.has(entry.name)) continue;\r\n walk(fullPath);\r\n } else if (entry.isFile() && isScannableFile(entry.name)) {\r\n files.push(fullPath);\r\n }\r\n }\r\n }\r\n\r\n walk(abs);\r\n return files;\r\n}\r\n\r\n// ─── CLI ─────────────────────────────────────────────────────────────────────\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name(\"pretense\")\r\n .description(\"AI firewall CLI — mutates proprietary code before LLM API calls\")\r\n .version(VERSION)\r\n .hook(\"preAction\", () => {\r\n printBanner();\r\n });\r\n\r\n// ── init ──────────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"init\")\r\n .description(\"Initialize .pretense/ config in current directory\")\r\n .option(\"-d, --dir <path>\", \"Target directory\", process.cwd())\r\n .action((opts: { dir: string }) => {\r\n const dir = resolve(opts.dir);\r\n console.log(chalk.cyan(\"Initializing Pretense in\"), chalk.bold(dir));\r\n\r\n const configDir = initConfig(dir);\r\n\r\n // Scan for source files\r\n const files = collectFiles(dir);\r\n const langCounts: Record<string, number> = {};\r\n for (const f of files) {\r\n const lang = langFromExt(f);\r\n langCounts[lang] = (langCounts[lang] ?? 0) + 1;\r\n }\r\n\r\n console.log(chalk.green(\"\\n .pretense/ created at\"), chalk.bold(configDir));\r\n console.log(chalk.gray(`\\n Scanned ${files.length} source files:`));\r\n for (const [lang, count] of Object.entries(langCounts)) {\r\n console.log(chalk.gray(` ${lang}: ${count} files`));\r\n }\r\n console.log(chalk.cyan(\"\\n Next: run\"), chalk.bold(\"pretense start\"), chalk.cyan(\"to launch the proxy\"));\r\n console.log();\r\n });\r\n\r\n// ── start ─────────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"start\")\r\n .description(\"Start the Pretense proxy server\")\r\n .option(\"-p, --port <number>\", \"Port number\", \"9339\")\r\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\r\n .action(async (opts: { port: string; verbose: boolean }) => {\r\n const config = loadConfig();\r\n const port = validatePort(opts.port);\r\n if (port === null) {\r\n console.error(chalk.red(\"Error: Invalid port number:\"), chalk.bold(opts.port));\r\n console.error(chalk.gray(\"Port must be an integer between 1 and 65535.\"));\r\n process.exit(1);\r\n }\r\n await ensureDashboardKeyForStart();\r\n logDashboardCredentialHint();\r\n startProxy({ config, port, verbose: opts.verbose });\r\n });\r\n\r\n// ── scan ──────────────────────────────────────────────────────────────────────\r\n\r\ninterface ScanRowResult {\r\n file: string;\r\n identifiers: number;\r\n secrets: number;\r\n secretTypes: string[];\r\n skipped?: \"too-large\" | \"binary\" | \"read-error\";\r\n sizeBytes?: number;\r\n}\r\n\r\n/**\r\n * Scan a single file. Pure async, fully bounded (file-size + binary checks\r\n * happen before reading). Returns null on unrecoverable read errors so the\r\n * caller can keep going on the next file.\r\n */\r\nasync function scanOneFile(\r\n file: string,\r\n opts: { secretsOnly: boolean; maxFileSize: number },\r\n): Promise<ScanRowResult | null> {\r\n let size = 0;\r\n try {\r\n const st = await fsStat(file);\r\n size = st.size;\r\n if (st.size > opts.maxFileSize) {\r\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"too-large\", sizeBytes: size };\r\n }\r\n } catch {\r\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"read-error\" };\r\n }\r\n\r\n // Cheap binary probe for unknown source extensions to avoid wedging\r\n // the regex engine on minified bundles, fixtures, or vendored blobs.\r\n if (!isSourceCodeFile(file)) {\r\n try {\r\n if (await isBinaryFileAsync(file)) {\r\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"binary\", sizeBytes: size };\r\n }\r\n } catch {\r\n /* fall through and try to read */\r\n }\r\n }\r\n\r\n let code: string;\r\n try {\r\n code = await readFile(file, \"utf-8\");\r\n } catch {\r\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"read-error\", sizeBytes: size };\r\n }\r\n\r\n const lang = langFromExt(file);\r\n let identifiers = 0;\r\n if (!opts.secretsOnly && isSourceCodeFile(file)) {\r\n try {\r\n const scanResult = scan(code, lang);\r\n identifiers = scanResult.tokens.length;\r\n } catch {\r\n /* identifier scan failures are non-fatal */\r\n }\r\n }\r\n\r\n let blocked: Array<{ type: string }> = [];\r\n try {\r\n const secretResult = scanSecrets(code);\r\n blocked = secretResult.matches.filter((m) => m.action === \"block\" || m.action === \"redact\");\r\n } catch {\r\n /* secret scan failures are non-fatal */\r\n }\r\n\r\n return {\r\n file,\r\n identifiers,\r\n secrets: blocked.length,\r\n secretTypes: blocked.map((m) => m.type),\r\n sizeBytes: size,\r\n };\r\n}\r\n\r\n/**\r\n * Process `files` with bounded concurrency, streaming progress to stderr\r\n * and listening for SIGINT/SIGTERM so partial results can be flushed.\r\n */\r\nasync function scanFilesParallel(\r\n files: string[],\r\n opts: { secretsOnly: boolean; maxFileSize: number; quiet: boolean; concurrency: number },\r\n): Promise<{ results: ScanRowResult[]; interrupted: boolean }> {\r\n const results: ScanRowResult[] = [];\r\n let cursor = 0;\r\n let done = 0;\r\n let lastPrint = 0;\r\n let interrupted = false;\r\n\r\n const stopHandler = (): void => { interrupted = true; };\r\n process.on(\"SIGINT\", stopHandler);\r\n process.on(\"SIGTERM\", stopHandler);\r\n\r\n const isTTY = process.stderr.isTTY === true;\r\n const printProgress = (force = false): void => {\r\n if (opts.quiet) return;\r\n const now = Date.now();\r\n if (!force && now - lastPrint < PROGRESS_INTERVAL_MS) return;\r\n lastPrint = now;\r\n const found = results.reduce((acc, r) => acc + r.secrets, 0);\r\n const msg = `Scanning ${done}/${files.length} files (${found} secrets so far)...`;\r\n if (isTTY) {\r\n process.stderr.write(`\\r\\x1b[K${msg}`);\r\n } else {\r\n process.stderr.write(`${msg}\\n`);\r\n }\r\n };\r\n\r\n async function worker(): Promise<void> {\r\n while (!interrupted) {\r\n const i = cursor++;\r\n if (i >= files.length) return;\r\n const file = files[i]!;\r\n const row = await scanOneFile(file, { secretsOnly: opts.secretsOnly, maxFileSize: opts.maxFileSize });\r\n if (row) results.push(row);\r\n done++;\r\n printProgress();\r\n }\r\n }\r\n\r\n printProgress(true);\r\n const workers = Array.from({ length: Math.min(opts.concurrency, files.length || 1) }, () => worker());\r\n await Promise.all(workers);\r\n\r\n process.removeListener(\"SIGINT\", stopHandler);\r\n process.removeListener(\"SIGTERM\", stopHandler);\r\n\r\n if (!opts.quiet && isTTY) {\r\n process.stderr.write(`\\r\\x1b[K`);\r\n }\r\n return { results, interrupted };\r\n}\r\n\r\nfunction parseSizeOption(value: string): number | null {\r\n // Accept plain bytes, or \"10m\" / \"10mb\" / \"500k\" / \"500kb\"\r\n const trimmed = value.trim().toLowerCase();\r\n const m = /^(\\d+(?:\\.\\d+)?)\\s*(b|k|kb|m|mb|g|gb)?$/.exec(trimmed);\r\n if (!m) return null;\r\n const n = parseFloat(m[1]!);\r\n if (!isFinite(n) || n <= 0) return null;\r\n const unit = m[2] ?? \"b\";\r\n const mult = unit.startsWith(\"g\") ? 1024 ** 3 : unit.startsWith(\"m\") ? 1024 ** 2 : unit.startsWith(\"k\") ? 1024 : 1;\r\n return Math.floor(n * mult);\r\n}\r\n\r\nprogram\r\n .command(\"scan <target>\")\r\n .description(\"Scan file or directory for identifiers and secrets (no mutation)\")\r\n .option(\"--secrets-only\", \"Only scan for secrets/credentials\", false)\r\n .option(\"--json\", \"Output as JSON\", false)\r\n .option(\"--max-file-size <size>\", \"Skip files larger than this (e.g. 10mb, 500k)\", \"10mb\")\r\n .option(\"--concurrency <n>\", \"Max files scanned in parallel\", String(SCAN_CONCURRENCY))\r\n .option(\"--quiet\", \"Suppress progress output\", false)\r\n .action(async (\r\n target: string,\r\n opts: { secretsOnly: boolean; json: boolean; maxFileSize: string; concurrency: string; quiet: boolean },\r\n ) => {\r\n const absTarget = resolve(target);\r\n if (!existsSync(absTarget)) {\r\n console.error(chalk.red(\"Error: Path not found:\"), chalk.bold(absTarget));\r\n process.exit(1);\r\n }\r\n\r\n const maxFileSize = parseSizeOption(opts.maxFileSize);\r\n if (maxFileSize === null) {\r\n console.error(chalk.red(\"Error: Invalid --max-file-size value:\"), chalk.bold(opts.maxFileSize));\r\n console.error(chalk.gray(\"Use bytes or a unit suffix, e.g. 10mb, 500k, 1048576\"));\r\n process.exit(1);\r\n }\r\n const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || SCAN_CONCURRENCY);\r\n\r\n if (!opts.quiet && !opts.json) {\r\n process.stderr.write(chalk.gray(`Discovering files in ${absTarget}...\\n`));\r\n }\r\n const files = collectFiles(target);\r\n if (files.length === 0) {\r\n console.error(chalk.red(\"Error: No source files found at\"), chalk.bold(absTarget));\r\n console.error(chalk.gray(\"Supported extensions: \" + [...SUPPORTED_EXTENSIONS].join(\", \")));\r\n process.exit(1);\r\n }\r\n if (!opts.quiet && !opts.json) {\r\n process.stderr.write(chalk.gray(`Found ${files.length} candidate files. Scanning with concurrency=${concurrency}...\\n`));\r\n }\r\n\r\n const startedAt = Date.now();\r\n const { results: allResults, interrupted } = await scanFilesParallel(files, {\r\n secretsOnly: opts.secretsOnly,\r\n maxFileSize,\r\n quiet: opts.quiet || opts.json,\r\n concurrency,\r\n });\r\n const elapsedMs = Date.now() - startedAt;\r\n\r\n const totalIdentifiers = allResults.reduce((acc, r) => acc + r.identifiers, 0);\r\n const totalSecrets = allResults.reduce((acc, r) => acc + r.secrets, 0);\r\n const skippedLarge = allResults.filter((r) => r.skipped === \"too-large\").length;\r\n const skippedBinary = allResults.filter((r) => r.skipped === \"binary\").length;\r\n\r\n if (opts.json) {\r\n console.log(JSON.stringify({\r\n files: allResults,\r\n totalIdentifiers,\r\n totalSecrets,\r\n skippedLarge,\r\n skippedBinary,\r\n elapsedMs,\r\n interrupted,\r\n }, null, 2));\r\n } else {\r\n console.log(chalk.cyan(\"\\nPretense Scan Results\\n\"));\r\n for (const r of allResults) {\r\n if (r.skipped) {\r\n if (r.skipped === \"too-large\") {\r\n const mb = ((r.sizeBytes ?? 0) / 1024 / 1024).toFixed(1);\r\n console.log(chalk.gray(` ${r.file} — skipped (${mb} MB > limit)`));\r\n }\r\n continue;\r\n }\r\n const secretBadge = r.secrets > 0\r\n ? chalk.red(` [${r.secrets} SECRET${r.secrets > 1 ? \"S\" : \"\"}]`)\r\n : \"\";\r\n const showRow = r.secrets > 0 || (!opts.secretsOnly && r.identifiers > 0);\r\n if (!showRow) continue;\r\n console.log(\r\n chalk.gray(\" \") + chalk.white(r.file) + chalk.gray(` — ${r.identifiers} identifiers`) + secretBadge,\r\n );\r\n if (r.secrets > 0) {\r\n for (const t of r.secretTypes) {\r\n console.log(chalk.red(` ! ${t}`));\r\n }\r\n }\r\n }\r\n const skipNote = skippedLarge + skippedBinary > 0\r\n ? chalk.gray(` (skipped ${skippedLarge} large, ${skippedBinary} binary)`)\r\n : \"\";\r\n console.log(\r\n chalk.gray(`\\n Total: ${allResults.length} files in ${(elapsedMs / 1000).toFixed(2)}s, ${totalIdentifiers} identifiers, `) +\r\n (totalSecrets > 0 ? chalk.red(`${totalSecrets} secrets found`) : chalk.green(\"0 secrets\")) +\r\n skipNote,\r\n );\r\n if (interrupted) {\r\n console.log(chalk.yellow(\"\\n Interrupted — partial results shown above.\"));\r\n }\r\n console.log();\r\n }\r\n\r\n if (!opts.json) {\r\n printTokenFooter(allResults.length, totalIdentifiers);\r\n }\r\n\r\n if (interrupted) {\r\n // Flushed partial results; signal interruption with non-zero exit.\r\n process.exit(130);\r\n }\r\n // Exit code 2 if secrets found\r\n if (totalSecrets > 0) {\r\n process.exit(2);\r\n }\r\n });\r\n\r\n// ── mutate ────────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"mutate <file>\")\r\n .description(\"Mutate identifiers for stdout (scanner redacts secrets/PII in the source first)\")\r\n .option(\"-s, --seed <seed>\", \"Mutation seed\", \"pretense\")\r\n .option(\"-l, --language <lang>\", \"Source language (typescript, javascript, python, go, java, csharp, ruby, rust)\")\r\n .option(\"--save\", \"Save mutation map to .pretense/\", false)\r\n .option(\"--json\", \"Output as JSON (includes map + stats)\", false)\r\n .action((file: string, opts: { seed: string; language?: string; save: boolean; json: boolean }) => {\r\n const absPath = resolve(file);\r\n if (!existsSync(absPath)) {\r\n console.error(chalk.red(\"Error: File not found:\"), chalk.bold(absPath));\r\n process.exit(1);\r\n }\r\n\r\n // Validate language option if provided\r\n if (opts.language) {\r\n const validLang = validateLanguage(opts.language);\r\n if (!validLang) {\r\n console.error(chalk.red(\"Error: Unsupported language:\"), chalk.bold(opts.language));\r\n console.error(chalk.gray(\"Supported languages: \" + SUPPORTED_LANGUAGES.join(\", \")));\r\n process.exit(1);\r\n }\r\n }\r\n\r\n // Check for binary files\r\n if (!SUPPORTED_EXTENSIONS.has(extname(absPath).toLowerCase()) && isBinaryFile(absPath)) {\r\n console.error(chalk.red(\"Error: Not a supported source file:\"), chalk.bold(absPath));\r\n console.error(chalk.gray(\"Supported extensions: \" + [...SUPPORTED_EXTENSIONS].join(\", \")));\r\n process.exit(1);\r\n }\r\n\r\n const code = readFileSync(absPath, \"utf-8\");\r\n const lang = opts.language ? validateLanguage(opts.language)! : langFromExt(absPath);\r\n const secretScan = scanSecrets(code);\r\n const effectiveSeed = opts.seed === \"pretense\" ? buildSaltedSeed(opts.seed) : opts.seed;\r\n const { redactedCode: redacted, secretsMap } = applyRedactionsTracked(code, secretScan.matches, effectiveSeed);\r\n const secretsRedacted = secretsMap.size;\r\n const result = mutate(redacted, lang, opts.seed);\r\n\r\n if (opts.save) {\r\n const configDir = getConfigDir();\r\n const store = new MutationStore(join(configDir, \"mutation-map.json\"));\r\n store.load();\r\n store.save({\r\n id: absPath,\r\n originalHash: absPath,\r\n mapEntries: MutationStore.fromMap(result.map),\r\n secretsMapEntries: [...secretsMap.entries()],\r\n timestamp: Date.now(),\r\n language: lang,\r\n });\r\n store.persist();\r\n process.stderr.write(chalk.gray(`Mutation map saved to ${configDir}/mutation-map.json\\n`));\r\n }\r\n\r\n if (opts.json) {\r\n console.log(JSON.stringify({\r\n mutatedCode: result.mutatedCode,\r\n map: Object.fromEntries(result.map),\r\n stats: result.stats,\r\n secretsRedacted,\r\n secretsMap: Object.fromEntries(secretsMap),\r\n }, null, 2));\r\n } else {\r\n process.stdout.write(result.mutatedCode);\r\n if (secretsRedacted > 0) {\r\n process.stderr.write(\r\n chalk.gray(`--- ${secretsRedacted} secret/PII span(s) redacted before identifier mutation ---\\n`),\r\n );\r\n }\r\n process.stderr.write(chalk.gray(`\\n--- ${result.stats.tokensMutated} identifiers mutated in ${result.stats.durationMs}ms ---\\n`));\r\n printTokenFooter(1, result.stats.tokensMutated);\r\n }\r\n });\r\n\r\n// ── reverse ───────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"reverse <file>\")\r\n .description(\"Reverse mutations using stored map\")\r\n .option(\"-m, --map <path>\", \"Path to mutation map JSON file\")\r\n .action((file: string, opts: { map?: string }) => {\r\n const absPath = resolve(file);\r\n if (!existsSync(absPath)) {\r\n console.error(chalk.red(\"Error: File not found:\"), chalk.bold(absPath));\r\n process.exit(1);\r\n }\r\n\r\n const mutatedCode = readFileSync(absPath, \"utf-8\");\r\n\r\n // Load map from specified path or .pretense/mutation-map.json\r\n const mapPath = opts.map\r\n ? resolve(opts.map)\r\n : join(getConfigDir(), \"mutation-map.json\");\r\n\r\n if (!existsSync(mapPath)) {\r\n console.error(chalk.red(\"Error: Mutation map not found:\"), chalk.bold(mapPath));\r\n console.error(chalk.gray(\"Run 'pretense mutate --save' first, or specify --map <path>\"));\r\n process.exit(1);\r\n }\r\n\r\n let store: MutationStore;\r\n try {\r\n store = new MutationStore(mapPath);\r\n store.load();\r\n } catch {\r\n console.error(chalk.red(\"Error: Failed to load mutation map:\"), chalk.bold(mapPath));\r\n console.error(chalk.gray(\"The file may be corrupted. Run 'pretense mutate --save' to regenerate.\"));\r\n process.exit(1);\r\n }\r\n\r\n // Try to find map by file path, or use the most recent entry\r\n const entry = store.get(absPath) ?? store.getByHash(absPath) ?? store.list(1)[0];\r\n if (!entry) {\r\n console.error(chalk.red(\"Error: No mutation map entries found.\"));\r\n console.error(chalk.gray(\"Run 'pretense mutate --save <file>' first to generate a map.\"));\r\n process.exit(1);\r\n }\r\n\r\n const map = MutationStore.toMap(entry);\r\n const secretsMap = entry.secretsMapEntries\r\n ? new Map(entry.secretsMapEntries)\r\n : undefined;\r\n const restored = reverse(mutatedCode, map, secretsMap);\r\n\r\n process.stdout.write(restored);\r\n const secretsCount = secretsMap?.size ?? 0;\r\n const secretsSuffix = secretsCount > 0 ? ` + ${secretsCount} secret(s)` : \"\";\r\n process.stderr.write(chalk.gray(`\\n--- Reversed ${map.size} mutations${secretsSuffix} ---\\n`));\r\n });\r\n\r\n// ── audit ─────────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"audit\")\r\n .description(\"View the audit log\")\r\n .option(\"--json\", \"Output as JSON\", false)\r\n .option(\"--csv\", \"Output as CSV\", false)\r\n .option(\"-l, --limit <number>\", \"Limit entries\", \"50\")\r\n .action((opts: { json: boolean; csv: boolean; limit: string }) => {\r\n const format = opts.json ? \"json\" : opts.csv ? \"csv\" : \"text\";\r\n const limit = parseInt(opts.limit) || 50;\r\n\r\n const entries = readAuditLog({ limit, format });\r\n const output = formatAudit(entries, format);\r\n console.log(output);\r\n });\r\n\r\n// ── version ───────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"version\")\r\n .description(\"Print Pretense CLI version\")\r\n .action(() => {\r\n console.log(`@pretense/cli v${VERSION}`);\r\n });\r\n\r\n// ── status / usage / tokens ─────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"status\")\r\n .description(\"Show current plan, monthly quota, seat usage\")\r\n .action(async () => {\r\n await runStatus();\r\n });\r\n\r\nprogram\r\n .command(\"usage\")\r\n .description(\"Alias for `pretense status` — show monthly quota usage\")\r\n .action(async () => {\r\n await runStatus();\r\n });\r\n\r\nprogram\r\n .command(\"tokens\")\r\n .description(\"Alias for `pretense credits` — show remaining mutation budget\")\r\n .action(async () => {\r\n await runCredits();\r\n });\r\n\r\n// ── upgrade / credits ────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"upgrade\")\r\n .description(\"Compare plans and upgrade to Pro or Enterprise\")\r\n .action(() => {\r\n runUpgrade();\r\n });\r\n\r\nprogram\r\n .command(\"credits\")\r\n .description(\"Show remaining mutation/scan budget for the current month\")\r\n .action(async () => {\r\n await runCredits();\r\n });\r\n\r\n// ── login ─────────────────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .command(\"login\")\r\n .description(\"Save a Pretense API key to ~/.pretense/config.json for future CLI runs\")\r\n .option(\"-k, --key <key>\", \"API key (prtns_live_... or pk_live_...). If omitted, read from $PRETENSE_API_KEY or stdin.\")\r\n .action((opts: { key?: string }) => {\r\n const code = runLogin({ key: opts.key });\r\n if (code !== 0) process.exit(code);\r\n });\r\n\r\nprogram\r\n .command(\"logout\")\r\n .description(\"Remove the saved Pretense dashboard API key from ~/.pretense/config.json\")\r\n .option(\"-y, --yes\", \"Skip confirmation prompt\", false)\r\n .action(async (opts: { yes: boolean }) => {\r\n const code = await runLogout({ assumeYes: opts.yes === true });\r\n if (code !== 0) process.exit(code);\r\n });\r\n\r\n// ─── Global error handler ───────────────────────────────────────────────────\r\n\r\nfunction handleFatalError(err: unknown): void {\r\n if (err instanceof Error && err.message) {\r\n console.error(chalk.red(\"Error:\"), err.message);\r\n } else {\r\n console.error(chalk.red(\"An unexpected error occurred.\"));\r\n }\r\n process.exit(1);\r\n}\r\n\r\nprocess.on(\"uncaughtException\", handleFatalError);\r\nprocess.on(\"unhandledRejection\", handleFatalError);\r\n\r\n// ─── Parse and run ───────────────────────────────────────────────────────────\r\n\r\nprogram\r\n .showSuggestionAfterError(true)\r\n .showHelpAfterError(\"(use --help for available commands)\");\r\n\r\nprogram.parse();\r\n","/**\r\n * Pretense Core — Shared Types\r\n * All domain interfaces and enums used across the mutation pipeline.\r\n */\r\n\r\n// ─── Token Types ───────────────────────────────────────────────────────────────\r\n\r\nexport enum TokenType {\r\n Variable = \"Variable\",\r\n Function = \"Function\",\r\n Class = \"Class\",\r\n String = \"String\",\r\n /** Quoted HTTP header name (e.g. \"x-api-key\", \"Authorization\") — mutated to hide provider hints */\r\n HttpHeaderString = \"HttpHeaderString\",\r\n Comment = \"Comment\",\r\n Import = \"Import\",\r\n Property = \"Property\",\r\n Method = \"Method\",\r\n}\r\n\r\nexport interface Token {\r\n type: TokenType;\r\n value: string;\r\n start: number;\r\n end: number;\r\n line: number;\r\n}\r\n\r\n// ─── Scan ──────────────────────────────────────────────────────────────────────\r\n\r\nexport interface ScanResult {\r\n tokens: Token[];\r\n language: string;\r\n}\r\n\r\n// ─── Mutation ─────────────────────────────────────────────────────────────────\r\n\r\nexport interface MutationRule {\r\n /** Token type this rule targets */\r\n tokenType: TokenType;\r\n /** Whether to strip this token type entirely (e.g. comments) */\r\n strip?: boolean;\r\n /** Custom prefix to use instead of the default per-type prefix */\r\n prefix?: string;\r\n}\r\n\r\n/**\r\n * Maps every original token value to its mutated synthetic.\r\n * Used during forward mutation and exact reversal.\r\n */\r\nexport type MutationMap = Map<string, string>;\r\n\r\nexport interface MutationStats {\r\n tokensScanned: number;\r\n tokensMutated: number;\r\n durationMs: number;\r\n language: string;\r\n}\r\n\r\nexport interface MutationResult {\r\n mutatedCode: string;\r\n map: MutationMap;\r\n stats: MutationStats;\r\n}\r\n\r\n// ─── Store ────────────────────────────────────────────────────────────────────\r\n\r\nexport interface StoreEntry {\r\n id: string;\r\n originalHash: string;\r\n /** Serialized MutationMap (array of [original, synthetic] tuples) */\r\n mapEntries: [string, string][];\r\n /** Serialized secrets map (array of [placeholder, originalValue] tuples) for reversal */\r\n secretsMapEntries?: [string, string][];\r\n timestamp: number;\r\n language: string;\r\n}\r\n\r\n// ─── Proxy ────────────────────────────────────────────────────────────────────\r\n\r\nexport interface ProxyRequest {\r\n body: string;\r\n targetUrl: string;\r\n headers: Record<string, string>;\r\n}\r\n\r\nexport interface ProxyResponse {\r\n body: string;\r\n statusCode: number;\r\n reversed: boolean;\r\n}\r\n\r\n// ─── Config ───────────────────────────────────────────────────────────────────\r\n\r\nexport interface PretenseConfig {\r\n port: number;\r\n targetApis: string[];\r\n languages: string[];\r\n mutationRules: MutationRule[];\r\n storePath: string;\r\n}\r\n\r\nexport const DEFAULT_CONFIG: PretenseConfig = {\r\n port: 9339,\r\n targetApis: [\"https://api.anthropic.com\", \"https://api.openai.com\"],\r\n languages: [\"typescript\", \"javascript\", \"python\", \"go\", \"java\", \"csharp\", \"ruby\", \"rust\"],\r\n mutationRules: [\r\n { tokenType: TokenType.Variable, prefix: \"_v\" },\r\n { tokenType: TokenType.Function, prefix: \"_fn\" },\r\n { tokenType: TokenType.Class, prefix: \"_cls\" },\r\n { tokenType: TokenType.String },\r\n { tokenType: TokenType.Comment, strip: true },\r\n { tokenType: TokenType.Import },\r\n { tokenType: TokenType.Property, prefix: \"_prop\" },\r\n { tokenType: TokenType.Method, prefix: \"_fn\" },\r\n ],\r\n storePath: `${process.env[\"HOME\"] ?? \"/tmp\"}/.pretense`,\r\n};\r\n","/**\r\n * Pretense Core — Token Scanner\r\n *\r\n * Regex-based token scanner for TypeScript/JavaScript, Python, Go, and Java.\r\n * Extracts mutable tokens (variables, functions, classes, strings, imports,\r\n * comments) with exact positions for accurate reversal.\r\n *\r\n * No tree-sitter dependency — pure regex MVP, production-ready accuracy.\r\n */\r\n\r\nimport { TokenType, type Token, type ScanResult } from \"./types.js\";\r\n\r\n// ─── Language keyword sets ─────────────────────────────────────────────────────\r\n\r\nconst TS_JS_KEYWORDS = new Set([\r\n \"abstract\", \"any\", \"as\", \"async\", \"await\", \"boolean\", \"break\", \"case\",\r\n \"catch\", \"class\", \"const\", \"constructor\", \"continue\", \"debugger\", \"declare\",\r\n \"default\", \"delete\", \"do\", \"else\", \"enum\", \"export\", \"extends\", \"false\",\r\n \"finally\", \"for\", \"from\", \"function\", \"get\", \"if\", \"implements\", \"import\",\r\n \"in\", \"instanceof\", \"interface\", \"keyof\", \"let\", \"module\", \"namespace\",\r\n \"never\", \"new\", \"null\", \"number\", \"object\", \"of\", \"package\", \"private\",\r\n \"protected\", \"public\", \"readonly\", \"require\", \"return\", \"set\", \"static\",\r\n \"string\", \"super\", \"switch\", \"symbol\", \"this\", \"throw\", \"true\", \"try\",\r\n \"type\", \"typeof\", \"undefined\", \"unknown\", \"var\", \"void\", \"while\", \"with\",\r\n \"yield\", \"satisfies\", \"using\", \"infer\", \"asserts\",\r\n]);\r\n\r\nconst PYTHON_KEYWORDS = new Set([\r\n \"False\", \"None\", \"True\", \"and\", \"as\", \"assert\", \"async\", \"await\",\r\n \"break\", \"class\", \"continue\", \"def\", \"del\", \"elif\", \"else\", \"except\",\r\n \"finally\", \"for\", \"from\", \"global\", \"if\", \"import\", \"in\", \"is\",\r\n \"lambda\", \"nonlocal\", \"not\", \"or\", \"pass\", \"raise\", \"return\", \"try\",\r\n \"while\", \"with\", \"yield\", \"self\", \"cls\",\r\n]);\r\n\r\nconst GO_KEYWORDS = new Set([\r\n \"break\", \"case\", \"chan\", \"const\", \"continue\", \"default\", \"defer\", \"else\",\r\n \"fallthrough\", \"for\", \"func\", \"go\", \"goto\", \"if\", \"import\", \"interface\",\r\n \"map\", \"package\", \"range\", \"return\", \"select\", \"struct\", \"switch\", \"type\",\r\n \"var\", \"nil\", \"true\", \"false\", \"error\", \"string\", \"int\", \"int8\", \"int16\",\r\n \"int32\", \"int64\", \"uint\", \"uint8\", \"uint16\", \"uint32\", \"uint64\", \"float32\",\r\n \"float64\", \"complex64\", \"complex128\", \"bool\", \"byte\", \"rune\", \"uintptr\",\r\n \"make\", \"new\", \"len\", \"cap\", \"append\", \"copy\", \"close\", \"delete\", \"panic\",\r\n \"recover\", \"print\", \"println\",\r\n]);\r\n\r\nconst JAVA_KEYWORDS = new Set([\r\n \"abstract\", \"assert\", \"boolean\", \"break\", \"byte\", \"case\", \"catch\", \"char\",\r\n \"class\", \"const\", \"continue\", \"default\", \"do\", \"double\", \"else\", \"enum\",\r\n \"extends\", \"final\", \"finally\", \"float\", \"for\", \"goto\", \"if\", \"implements\",\r\n \"import\", \"instanceof\", \"int\", \"interface\", \"long\", \"native\", \"new\",\r\n \"package\", \"private\", \"protected\", \"public\", \"return\", \"short\", \"static\",\r\n \"strictfp\", \"super\", \"switch\", \"synchronized\", \"this\", \"throw\", \"throws\",\r\n \"transient\", \"try\", \"void\", \"volatile\", \"while\", \"true\", \"false\", \"null\",\r\n \"var\", \"record\", \"sealed\", \"permits\", \"yield\",\r\n]);\r\n\r\nconst CSHARP_KEYWORDS = new Set([\r\n \"class\", \"interface\", \"namespace\", \"public\", \"private\", \"protected\",\r\n \"internal\", \"static\", \"void\", \"return\", \"new\", \"using\", \"override\", \"sealed\",\r\n \"abstract\", \"virtual\", \"readonly\", \"const\", \"var\", \"int\", \"string\", \"bool\",\r\n \"double\", \"float\", \"object\", \"null\", \"true\", \"false\", \"if\", \"else\", \"for\",\r\n \"foreach\", \"while\", \"do\", \"switch\", \"case\", \"break\", \"continue\", \"try\",\r\n \"catch\", \"finally\", \"throw\", \"async\", \"await\", \"get\", \"set\", \"partial\",\r\n \"enum\", \"struct\", \"delegate\", \"event\",\r\n]);\r\n\r\nconst RUBY_KEYWORDS = new Set([\r\n \"def\", \"class\", \"module\", \"end\", \"do\", \"if\", \"else\", \"elsif\", \"unless\",\r\n \"while\", \"until\", \"for\", \"begin\", \"rescue\", \"ensure\", \"raise\", \"return\",\r\n \"yield\", \"self\", \"super\", \"true\", \"false\", \"nil\", \"and\", \"or\", \"not\", \"in\",\r\n \"then\", \"case\", \"when\", \"puts\", \"print\", \"require\", \"require_relative\",\r\n \"include\", \"extend\", \"attr_accessor\", \"attr_reader\", \"attr_writer\",\r\n \"initialize\", \"new\", \"public\", \"private\", \"protected\",\r\n]);\r\n\r\nconst RUST_KEYWORDS = new Set([\r\n \"fn\", \"struct\", \"enum\", \"trait\", \"impl\", \"mod\", \"pub\", \"let\", \"mut\",\r\n \"const\", \"type\", \"use\", \"crate\", \"self\", \"super\", \"move\", \"ref\", \"match\",\r\n \"if\", \"else\", \"loop\", \"while\", \"for\", \"return\", \"break\", \"continue\",\r\n \"where\", \"as\", \"in\", \"true\", \"false\", \"unsafe\", \"extern\", \"dyn\", \"box\",\r\n \"static\", \"async\", \"await\", \"Box\", \"String\", \"Vec\", \"Option\", \"Result\",\r\n \"Ok\", \"Err\", \"Some\", \"None\",\r\n]);\r\n\r\n// ─── Language detection ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Detect the programming language from code heuristics.\r\n *\r\n * @example\r\n * detectLanguage(\"const x: number = 1;\") // => \"typescript\"\r\n * detectLanguage(\"def foo(x):\\n return x\") // => \"python\"\r\n */\r\nexport function detectLanguage(code: string): string {\r\n if (/:[\\s]*\\w+[\\s]*[;,{)]/.test(code) || /import.*from\\s+['\"]/.test(code) || /interface\\s+\\w+/.test(code)) return \"typescript\";\r\n if (/\\bdef\\s+\\w+\\s*\\(/.test(code) || /\\bimport\\s+\\w+/.test(code) && /:$/.test(code)) return \"python\";\r\n if (/\\bfunc\\s+\\w+\\s*\\(/.test(code) || /\\bpackage\\s+\\w+/.test(code)) return \"go\";\r\n if (/\\bpublic\\s+class\\s+\\w+/.test(code) || /\\bimport\\s+java\\./.test(code)) return \"java\";\r\n if (/\\bnamespace\\s+\\w+/.test(code) || /\\busing\\s+System/.test(code)) return \"csharp\";\r\n if (/\\bfn\\s+\\w+\\s*\\(/.test(code) || /\\blet\\s+mut\\s+\\w+/.test(code)) return \"rust\";\r\n if (/\\bdef\\s+\\w+/.test(code) && /\\bend\\b/.test(code)) return \"ruby\";\r\n if (/\\bconst\\s+\\w+\\s*=/.test(code) || /\\bfunction\\s+\\w+\\s*\\(/.test(code)) return \"javascript\";\r\n return \"typescript\"; // default\r\n}\r\n\r\n// ─── Line-number helper ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Build a sorted array of newline byte offsets so we can convert any\r\n * index → 1-based line number in O(log lines) via binary search.\r\n *\r\n * Replaces the old per-call O(N) lineAt() walk. On a 400 KB file with\r\n * 7K tokens, the old impl was ~3 billion char comparisons (O(tokens × file))\r\n * which made the scanner appear to hang on real-world repos.\r\n */\r\nfunction buildLineIndex(code: string): number[] {\r\n const offsets: number[] = [];\r\n for (let i = 0; i < code.length; i++) {\r\n if (code.charCodeAt(i) === 10 /* \\n */) offsets.push(i);\r\n }\r\n return offsets;\r\n}\r\n\r\nfunction lineFromIndex(lineOffsets: number[], index: number): number {\r\n // Binary search for first newline >= index. Lines are 1-based.\r\n let lo = 0;\r\n let hi = lineOffsets.length;\r\n while (lo < hi) {\r\n const mid = (lo + hi) >> 1;\r\n if (lineOffsets[mid]! < index) lo = mid + 1;\r\n else hi = mid;\r\n }\r\n return lo + 1;\r\n}\r\n\r\n// ─── Per-language scanners ─────────────────────────────────────────────────────\r\n\r\nfunction scanTypeScript(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n // Single-line comment\r\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\r\n // Multi-line comment\r\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\r\n // Quoted HTTP header names (fetch/axios headers objects) — mutated, not vendor-identifying literals\r\n { re: /\"(?:x-[a-z0-9][a-z0-9-]*|authorization|api-key)\"/gi, type: TokenType.HttpHeaderString },\r\n { re: /'(?:x-[a-z0-9][a-z0-9-]*|authorization|api-key)'/gi, type: TokenType.HttpHeaderString },\r\n // Unquoted `Authorization` key — value must start with a string/template (skips interface/type shapes)\r\n {\r\n re: /(?:\\{|\\,)\\s*(Authorization)\\s*:\\s*(?=[`'\"])/g,\r\n type: TokenType.HttpHeaderString,\r\n groupIndex: 1,\r\n },\r\n // Import source (the module path string)\r\n { re: /\\bimport\\b[^'\"]*['\"]([^'\"]+)['\"]/g, type: TokenType.Import, groupIndex: 1 },\r\n // Class name\r\n { re: /\\bclass\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Function/method name (function keyword)\r\n { re: /\\bfunction\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Function, groupIndex: 1 },\r\n // Arrow function assigned to const/let/var\r\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*[-.][A-Za-z0-9_$])\\s*=\\s*(?:async\\s*)?\\(/g, type: TokenType.Function, groupIndex: 1 },\r\n // Method: identifier followed by (\r\n { re: /\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\r\n // Env-style binding names with hyphens or dots (e.g. AWS-SECRET-KEY, AWS.SECRET.KEY) — not valid JS identifiers but common in pasted config\r\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*(?:(?:-|\\.)(?:[A-Za-z0-9_$]+))+)(?=\\s*=)/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Variable declarations (exclude names continued with -/. so AWS-SECRET-KEY is captured only by the rule above)\r\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*[-.][A-Za-z0-9_$])/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Member receiver: matches in matches.push, row in row.patientId, def in def.name\r\n { re: /\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*(?:\\.|\\?\\.)[^0-9]/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Property after . or ?. when not immediately followed by ( — method calls use Method rule\r\n { re: /\\.([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\r\n { re: /\\?\\.([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\r\n // Template literals (preserve backtick wrapper)\r\n { re: /`[^`]*`/g, type: TokenType.String },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n // Single-quoted strings\r\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n // Skip language keywords for identifier tokens\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Function ||\r\n type === TokenType.Class ||\r\n type === TokenType.Method ||\r\n type === TokenType.Property\r\n ) {\r\n if (TS_JS_KEYWORDS.has(captureValue)) continue;\r\n // Skip console/process/Object etc.\r\n if (/^(console|process|Object|Array|Math|JSON|Promise|Error|Map|Set|Date|RegExp|Symbol|Proxy|Reflect|global|globalThis|window|document|module|exports|require|__dirname|__filename|Intl|WebAssembly)$/.test(captureValue)) continue;\r\n // Skip single-character identifiers (loop vars, etc.)\r\n if (captureValue.length <= 1) continue;\r\n }\r\n\r\n // import.meta must stay verbatim for valid ESM\r\n if (\r\n type === TokenType.Property &&\r\n captureValue === \"meta\" &&\r\n code.slice(Math.max(0, captureStart - 7), captureStart) === \"import.\"\r\n ) {\r\n continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n const commentSpans = tokens.filter((t) => t.type === TokenType.Comment);\r\n const stringLikeSpans = tokens.filter(\r\n (t) => t.type === TokenType.String || t.type === TokenType.HttpHeaderString,\r\n );\r\n const dropsSpanOverlap = (t: Token) => {\r\n if (\r\n t.type === TokenType.Variable ||\r\n t.type === TokenType.Function ||\r\n t.type === TokenType.Class ||\r\n t.type === TokenType.Method ||\r\n t.type === TokenType.Property\r\n ) {\r\n if (commentSpans.some((c) => t.start < c.end && t.end > c.start)) return false;\r\n if (stringLikeSpans.some((s) => t.start < s.end && t.end > s.start)) return false;\r\n }\r\n return true;\r\n };\r\n\r\n return deduplicate(tokens.filter(dropsSpanOverlap));\r\n}\r\n\r\nfunction scanPython(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n // Triple-quoted docstrings\r\n { re: /\"\"\"[\\s\\S]*?\"\"\"|'''[\\s\\S]*?'''/g, type: TokenType.Comment },\r\n // Line comments\r\n { re: /#[^\\n]*/g, type: TokenType.Comment },\r\n // Import module name\r\n { re: /\\bimport\\s+([A-Za-z_][A-Za-z0-9_.]*)/g, type: TokenType.Import, groupIndex: 1 },\r\n { re: /\\bfrom\\s+([A-Za-z_.][A-Za-z0-9_.]*)\\s+import/g, type: TokenType.Import, groupIndex: 1 },\r\n // Class name\r\n { re: /\\bclass\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Function/method def\r\n { re: /\\bdef\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Function, groupIndex: 1 },\r\n // Call site: method name in obj.method(\r\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\r\n // obj.attr receiver and attribute (matches.push-style)\r\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*\\.\\s*(?=[a-zA-Z_])/g, type: TokenType.Variable, groupIndex: 1 },\r\n { re: /\\.([A-Za-z_][A-Za-z0-9_]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\r\n // Variable assignment (simple name = ...)\r\n { re: /^([A-Za-z_][A-Za-z0-9_]*)\\s*=/gm, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n // Single-quoted strings\r\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Function ||\r\n type === TokenType.Class ||\r\n type === TokenType.Method ||\r\n type === TokenType.Property\r\n ) {\r\n if (PYTHON_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n // Skip dunder methods/vars\r\n if (captureValue.startsWith(\"__\") && captureValue.endsWith(\"__\")) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n const pyCommentSpans = tokens.filter((t) => t.type === TokenType.Comment);\r\n const pyStringSpans = tokens.filter((t) => t.type === TokenType.String);\r\n const dropsPyOverlap = (t: Token) => {\r\n if (\r\n t.type === TokenType.Variable ||\r\n t.type === TokenType.Function ||\r\n t.type === TokenType.Class ||\r\n t.type === TokenType.Method ||\r\n t.type === TokenType.Property\r\n ) {\r\n if (pyCommentSpans.some((c) => t.start < c.end && t.end > c.start)) return false;\r\n if (pyStringSpans.some((s) => t.start < s.end && t.end > s.start)) return false;\r\n }\r\n return true;\r\n };\r\n\r\n return deduplicate(tokens.filter(dropsPyOverlap));\r\n}\r\n\r\nfunction scanGo(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\r\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\r\n // Import path\r\n { re: /import\\s*\\(\\s*([\\s\\S]*?)\\s*\\)/g, type: TokenType.Import },\r\n { re: /import\\s+\"([^\"]+)\"/g, type: TokenType.Import, groupIndex: 1 },\r\n // Type declaration\r\n { re: /\\btype\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+(?:struct|interface)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Func name\r\n { re: /\\bfunc\\s+(?:\\([^)]*\\)\\s*)?([A-Za-z_][A-Za-z0-9_]*)\\s*\\(/g, type: TokenType.Function, groupIndex: 1 },\r\n // Var/const declaration\r\n { re: /\\b(?:var|const)\\s+([A-Za-z_][A-Za-z0-9_]*)\\b/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Short variable declaration\r\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*:=/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n // Backtick raw strings\r\n { re: /`[^`]*`/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Function ||\r\n type === TokenType.Class\r\n ) {\r\n if (GO_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n return deduplicate(tokens);\r\n}\r\n\r\nfunction scanJava(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\r\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\r\n // Import statement\r\n { re: /\\bimport\\s+([\\w.]+);/g, type: TokenType.Import, groupIndex: 1 },\r\n // Class/interface/enum\r\n { re: /\\b(?:class|interface|enum|record)\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Method declaration\r\n { re: /\\b(?:public|private|protected|static|final|abstract|synchronized|native|default)[\\w\\s<>\\[\\],]*\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\r\n // Variable declaration\r\n { re: /\\b(?:int|long|double|float|boolean|char|byte|short|String|Object|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\s*[=;,)]/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Method ||\r\n type === TokenType.Class\r\n ) {\r\n if (JAVA_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n // Skip common stdlib class names\r\n if (/^(String|Object|Integer|Long|Double|Boolean|List|Map|Set|Array|Exception|Error|System|Math|Thread|Class|Enum)$/.test(captureValue)) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n return deduplicate(tokens);\r\n}\r\n\r\nfunction scanCSharp(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\r\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\r\n // Namespace/using import\r\n { re: /\\busing\\s+([\\w.]+);/g, type: TokenType.Import, groupIndex: 1 },\r\n // Class/interface/struct/enum names\r\n { re: /\\b(?:class|interface|struct|enum)\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Method/property declaration\r\n { re: /\\b(?:public|private|protected|internal|static|virtual|override|async)\\s+(?:\\w+\\s+)+([a-zA-Z_]\\w*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\r\n // Local variable declarations\r\n { re: /\\b(?:var|int|string|bool|double|float|object)\\s+([a-zA-Z_]\\w*)\\b/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n // Verbatim strings\r\n { re: /@\"(?:[^\"]|\"\")*\"/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Method ||\r\n type === TokenType.Class\r\n ) {\r\n if (CSHARP_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n if (/^(String|Object|Integer|Boolean|Double|Float|List|Dictionary|Array|Exception|Task|Console|Math|Enum|Delegate)$/.test(captureValue)) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n return deduplicate(tokens);\r\n}\r\n\r\nfunction scanRuby(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n // Single-line comment\r\n { re: /#[^\\n]*/g, type: TokenType.Comment },\r\n // Method names\r\n { re: /\\bdef\\s+([a-zA-Z_]\\w*[!?]?)/g, type: TokenType.Function, groupIndex: 1 },\r\n // Class and module names\r\n { re: /\\b(?:class|module)\\s+([A-Z][a-zA-Z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Instance variables\r\n { re: /@([a-zA-Z_]\\w*)/g, type: TokenType.Property, groupIndex: 1 },\r\n // All-caps constants (3+ chars to avoid single-letter constants)\r\n { re: /\\b([A-Z][A-Z0-9_]{2,})\\b/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n // Single-quoted strings\r\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Function ||\r\n type === TokenType.Class ||\r\n type === TokenType.Property\r\n ) {\r\n if (RUBY_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n return deduplicate(tokens);\r\n}\r\n\r\nfunction scanRust(code: string): Token[] {\r\n const tokens: Token[] = [];\r\n if (!code.trim()) return tokens;\r\n const lineOffsets = buildLineIndex(code);\r\n\r\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\r\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\r\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\r\n // Use declarations\r\n { re: /\\buse\\s+([\\w:]+)/g, type: TokenType.Import, groupIndex: 1 },\r\n // Named type declarations (struct, enum, trait)\r\n { re: /\\b(?:struct|enum|trait)\\s+([A-Z][a-zA-Z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\r\n // Function names\r\n { re: /\\bfn\\s+([a-zA-Z_]\\w*)/g, type: TokenType.Function, groupIndex: 1 },\r\n // Constants (ALL_CAPS)\r\n { re: /\\bconst\\s+([A-Z_][A-Z0-9_]*)\\s*:/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Variable bindings\r\n { re: /\\blet\\s+(?:mut\\s+)?([a-zA-Z_]\\w*)/g, type: TokenType.Variable, groupIndex: 1 },\r\n // Double-quoted strings\r\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\r\n ];\r\n\r\n for (const { re, type, groupIndex } of patterns) {\r\n re.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(code)) !== null) {\r\n const fullMatch = m[0];\r\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\r\n const captureStart = groupIndex !== undefined\r\n ? m.index + fullMatch.indexOf(captureValue)\r\n : m.index;\r\n\r\n if (!captureValue || captureValue.trim() === \"\") continue;\r\n\r\n if (\r\n type === TokenType.Variable ||\r\n type === TokenType.Function ||\r\n type === TokenType.Class\r\n ) {\r\n if (RUST_KEYWORDS.has(captureValue)) continue;\r\n if (captureValue.length <= 1) continue;\r\n }\r\n\r\n tokens.push({\r\n type,\r\n value: captureValue,\r\n start: captureStart,\r\n end: captureStart + captureValue.length,\r\n line: lineFromIndex(lineOffsets, captureStart),\r\n });\r\n }\r\n }\r\n\r\n return deduplicate(tokens);\r\n}\r\n\r\n// ─── Deduplication ────────────────────────────────────────────────────────────\r\n\r\nfunction deduplicate(tokens: Token[]): Token[] {\r\n tokens.sort((a, b) => a.start - b.start);\r\n const seen = new Set<string>();\r\n const result: Token[] = [];\r\n for (const token of tokens) {\r\n const key = `${token.start}:${token.end}`;\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n result.push(token);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n// ─── Public API ───────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Scan source code and extract mutable tokens with their positions.\r\n *\r\n * @example\r\n * const result = scan(\"const greeting = 'hello';\", \"typescript\");\r\n * result.tokens.map(t => t.value) // => [\"greeting\", \"'hello'\"]\r\n */\r\nexport function scan(code: string, language: string): ScanResult {\r\n if (!code || !code.trim()) {\r\n return { tokens: [], language };\r\n }\r\n\r\n const lang = language.toLowerCase();\r\n let tokens: Token[];\r\n\r\n switch (lang) {\r\n case \"typescript\":\r\n case \"javascript\":\r\n case \"ts\":\r\n case \"js\":\r\n case \"tsx\":\r\n case \"jsx\":\r\n tokens = scanTypeScript(code);\r\n break;\r\n case \"python\":\r\n case \"py\":\r\n tokens = scanPython(code);\r\n break;\r\n case \"go\":\r\n tokens = scanGo(code);\r\n break;\r\n case \"java\":\r\n tokens = scanJava(code);\r\n break;\r\n case \"csharp\":\r\n case \"cs\":\r\n tokens = scanCSharp(code);\r\n break;\r\n case \"ruby\":\r\n case \"rb\":\r\n tokens = scanRuby(code);\r\n break;\r\n case \"rust\":\r\n case \"rs\":\r\n tokens = scanRust(code);\r\n break;\r\n default:\r\n tokens = scanTypeScript(code);\r\n }\r\n\r\n return { tokens, language: lang };\r\n}\r\n","/**\r\n * Pretense — Mutation Salt Manager\r\n *\r\n * Per-installation random salt for mutation hashing.\r\n * Stored at ~/.pretense/mutation.salt, never transmitted.\r\n *\r\n * Security: Without a salt, mutation hashes like _v1a2b can be reversed via\r\n * dictionary attack (65536 possibilities for 4 hex chars). With a 256-bit\r\n * per-installation salt, pre-image recovery is computationally infeasible.\r\n */\r\n\r\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from \"fs\";\r\nimport { join } from \"path\";\r\nimport { homedir } from \"os\";\r\nimport { randomBytes } from \"crypto\";\r\n\r\nconst SALT_BYTES = 32;\r\n\r\n// Paths are computed lazily so that tests can override HOME before calling getMutationSalt()\r\nfunction getSaltPath(): { dir: string; path: string } {\r\n const dir = join(homedir(), \".pretense\");\r\n return { dir, path: join(dir, \"mutation.salt\") };\r\n}\r\n\r\nlet _cachedSalt: string | null = null;\r\n\r\nexport function getMutationSalt(): string {\r\n if (_cachedSalt) return _cachedSalt;\r\n\r\n const { dir, path } = getSaltPath();\r\n\r\n if (existsSync(path)) {\r\n try {\r\n const raw = readFileSync(path, \"utf-8\").trim();\r\n if (/^[0-9a-f]{64}$/i.test(raw)) {\r\n _cachedSalt = raw.toLowerCase();\r\n return _cachedSalt;\r\n }\r\n } catch {\r\n // fall through\r\n }\r\n }\r\n\r\n const salt = randomBytes(SALT_BYTES).toString(\"hex\");\r\n try {\r\n mkdirSync(dir, { recursive: true });\r\n writeFileSync(path, salt, { mode: 0o600 });\r\n } catch {\r\n // in-memory only if FS is read-only\r\n }\r\n\r\n _cachedSalt = salt;\r\n return salt;\r\n}\r\n\r\nexport function buildSaltedSeed(baseSeed: string): string {\r\n return `${baseSeed}:${getMutationSalt()}`;\r\n}\r\n\r\n/** @internal */\r\nexport function _resetSaltCache(): void {\r\n _cachedSalt = null;\r\n}\r\n","/**\r\n * Deterministic synthetic identifiers — shared by identifier mutation\r\n * and secret-span placeholders (same hash + seed semantics).\r\n */\r\n\r\nfunction hash32(str: string): number {\r\n let h = 5381;\r\n for (let i = 0; i < str.length; i++) {\r\n h = ((h << 5) + h) ^ str.charCodeAt(i);\r\n }\r\n return h >>> 0;\r\n}\r\n\r\nfunction toAlphaNum(n: number, len: number): string {\r\n const CHARS = \"abcdefghijklmnopqrstuvwxyz0123456789\";\r\n let result = \"\";\r\n let v = n;\r\n for (let i = 0; i < len; i++) {\r\n result = CHARS[v % CHARS.length]! + result;\r\n v = Math.floor(v / CHARS.length);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * @example deterministicSyntheticId(\"getUserById\", seed, \"_fn\") // => \"_fnx3k7\"\r\n */\r\nexport function deterministicSyntheticId(original: string, seed: string, prefix: string, len = 4): string {\r\n const combined = `${seed}:${prefix}:${original}`;\r\n const h = hash32(combined);\r\n return prefix + toAlphaNum(h, len);\r\n}\r\n","/**\r\n * Pretense Core — Deterministic Mutation Engine\r\n *\r\n * Replaces identifiers, strings, and comments with synthetic tokens.\r\n * Same input + same seed always produces the same output (seeded PRNG).\r\n * Tracks every substitution in a MutationMap for exact reversal.\r\n */\r\n\r\nimport { TokenType, type MutationMap, type MutationResult, type MutationStats } from \"./types.js\";\r\nimport { scan, detectLanguage } from \"./scanner.js\";\r\nimport { buildSaltedSeed } from \"./salt.js\";\r\nimport { deterministicSyntheticId } from \"./deterministic-id.js\";\r\n\r\n// ─── Mutation logic ────────────────────────────────────────────────────────────\r\n\r\nfunction prefixForType(type: TokenType): string {\r\n switch (type) {\r\n case TokenType.Class: return \"_cls\";\r\n case TokenType.Function:\r\n case TokenType.Method: return \"_fn\";\r\n case TokenType.Variable: return \"_v\";\r\n case TokenType.Property: return \"_prop\";\r\n case TokenType.HttpHeaderString: return \"_hk\";\r\n default: return \"_tok\";\r\n }\r\n}\r\n\r\n/**\r\n * Mutate source code deterministically. Returns mutated code and the\r\n * MutationMap needed to reverse it.\r\n *\r\n * @param code - Source code string\r\n * @param language - Language identifier (\"typescript\", \"python\", \"go\", \"java\")\r\n * @param seed - Optional seed for determinism (default: \"pretense\")\r\n *\r\n * @example\r\n * const { mutatedCode, map } = mutate(\"const apiKey = 'secret';\", \"typescript\");\r\n * mutatedCode // => \"const _va1b2 = '_strc3d4';\"\r\n */\r\nexport function mutate(code: string, language?: string, seed = \"pretense\"): MutationResult {\r\n const startMs = performance.now();\r\n const lang = language ?? detectLanguage(code);\r\n\r\n if (!code || !code.trim()) {\r\n const emptyMap: MutationMap = new Map();\r\n return {\r\n mutatedCode: code,\r\n map: emptyMap,\r\n stats: { tokensScanned: 0, tokensMutated: 0, durationMs: 0, language: lang },\r\n };\r\n }\r\n\r\n // Mix in per-installation salt when using the default seed (production path).\r\n // This prevents dictionary brute-force reversal of mutation hashes.\r\n const effectiveSeed = seed === \"pretense\" ? buildSaltedSeed(seed) : seed;\r\n\r\n const { tokens } = scan(code, lang);\r\n const map: MutationMap = new Map<string, string>();\r\n\r\n // Build mutation map — one synthetic per unique original value\r\n for (const token of tokens) {\r\n if (map.has(token.value)) continue; // already mapped\r\n\r\n if (token.type === TokenType.Comment) {\r\n // Comments preserved verbatim — stripping breaks round-trip\r\n continue;\r\n }\r\n\r\n if (token.type === TokenType.String) {\r\n // Strings preserved verbatim — mutations break round-trip for multi-line strings\r\n continue;\r\n }\r\n\r\n if (token.type === TokenType.HttpHeaderString) {\r\n const qm = /^(\"|')(.+)\\1$/.exec(token.value);\r\n if (qm) {\r\n const inner = qm[2]!;\r\n const q = qm[1]!;\r\n const syntheticInner = deterministicSyntheticId(inner, effectiveSeed, prefixForType(TokenType.HttpHeaderString));\r\n map.set(token.value, `${q}${syntheticInner}${q}`);\r\n } else {\r\n // Bare property name (e.g. Authorization: `Bearer …`)\r\n const syntheticInner = deterministicSyntheticId(token.value, effectiveSeed, prefixForType(TokenType.HttpHeaderString));\r\n map.set(token.value, syntheticInner);\r\n }\r\n continue;\r\n }\r\n\r\n if (token.type === TokenType.Import) {\r\n // Keep import paths intact — they refer to packages, not IP\r\n continue;\r\n }\r\n\r\n const prefix = prefixForType(token.type);\r\n const synthetic = deterministicSyntheticId(token.value, effectiveSeed, prefix);\r\n map.set(token.value, synthetic);\r\n }\r\n\r\n // Apply substitutions — longest-first to avoid partial match issues\r\n const entries = [...map.entries()].sort((a, b) => b[0].length - a[0].length);\r\n\r\n let mutatedCode = code;\r\n for (const [original, synthetic] of entries) {\r\n if (!synthetic) continue;\r\n // Use word-boundary aware replacement for identifiers\r\n const escaped = original.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n if (original.match(/^[A-Za-z_$][A-Za-z0-9_$]*$/)) {\r\n // Identifier: use word boundaries\r\n mutatedCode = mutatedCode.replace(new RegExp(`\\\\b${escaped}\\\\b`, \"g\"), synthetic);\r\n } else {\r\n // String literals or other: exact replacement\r\n mutatedCode = mutatedCode.split(original).join(synthetic);\r\n }\r\n }\r\n\r\n const durationMs = Math.round((performance.now() - startMs) * 100) / 100;\r\n\r\n return {\r\n mutatedCode,\r\n map,\r\n stats: {\r\n tokensScanned: tokens.length,\r\n tokensMutated: map.size,\r\n durationMs,\r\n language: lang,\r\n },\r\n };\r\n}\r\n","/**\r\n * Pretense Core — Exact Reverser\r\n *\r\n * Uses the MutationMap produced by mutate() to restore original code.\r\n * Applies replacements longest-first to prevent partial-match bugs.\r\n * After reversal, output must equal the original input byte-for-byte.\r\n */\r\n\r\nimport type { MutationMap } from \"./types.js\";\r\n\r\n/**\r\n * Reverse a previously mutated string back to the original.\r\n * Throws if the map contains entries whose synthetic values are not\r\n * present in the mutated code (indicates map/code mismatch).\r\n *\r\n * @param mutatedCode - Code that was produced by mutate()\r\n * @param map - The MutationMap returned by the same mutate() call\r\n * @param secretsMap - Optional map of synthetic secret placeholders (`_sl…`) → original values\r\n *\r\n * @example\r\n * const { mutatedCode, map } = mutate(\"const apiKey = 'secret';\", \"typescript\");\r\n * reverse(mutatedCode, map) // => \"const apiKey = 'secret';\"\r\n */\r\nexport function reverse(mutatedCode: string, map: MutationMap, secretsMap?: Map<string, string>): string {\r\n if (!mutatedCode) return mutatedCode;\r\n\r\n let result = mutatedCode;\r\n\r\n // 1. Restore identifiers from the mutation map\r\n if (map.size > 0) {\r\n const reverseMap = new Map<string, string>();\r\n for (const [original, synthetic] of map.entries()) {\r\n if (synthetic === \"\" || !synthetic) continue;\r\n reverseMap.set(synthetic, original);\r\n }\r\n\r\n if (reverseMap.size > 0) {\r\n const sortedEntries = [...reverseMap.entries()].sort((a, b) => b[0].length - a[0].length);\r\n\r\n for (const [synthetic, original] of sortedEntries) {\r\n const escaped = synthetic.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n if (synthetic.match(/^[A-Za-z_$][A-Za-z0-9_$]*$/) || synthetic.match(/^_[a-z]+[a-z0-9]{4,}$/)) {\r\n result = result.replace(new RegExp(`\\\\b${escaped}\\\\b`, \"g\"), original);\r\n } else {\r\n result = result.split(synthetic).join(original);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 2. Restore secret values from the secrets map\r\n if (secretsMap && secretsMap.size > 0) {\r\n const sortedSecrets = [...secretsMap.entries()].sort((a, b) => b[0].length - a[0].length);\r\n for (const [placeholder, original] of sortedSecrets) {\r\n result = result.split(placeholder).join(original);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n","/**\r\n * Pretense Core — Secret Detection Engine\r\n *\r\n * 40+ regex patterns for API keys, tokens, credentials, and PII.\r\n * Sub-5ms per scan. Zero dependencies beyond regex.\r\n * Includes Shannon entropy check for high-entropy strings.\r\n */\r\n\r\nimport { buildSaltedSeed } from \"./salt.js\";\r\nimport { deterministicSyntheticId } from \"./deterministic-id.js\";\r\n\r\nexport type ScanCategory = \"secret\" | \"pii\" | \"credential\" | \"proprietary\";\r\nexport type ScanAction = \"block\" | \"redact\" | \"mutate\" | \"warn\" | \"pass\";\r\nexport type ScanSeverity = \"critical\" | \"high\" | \"medium\" | \"low\";\r\n\r\nexport interface ScanMatch {\r\n id: string;\r\n category: ScanCategory;\r\n type: string;\r\n value: string;\r\n masked: string;\r\n start: number;\r\n end: number;\r\n severity: ScanSeverity;\r\n action: ScanAction;\r\n}\r\n\r\nexport interface SecretScanResult {\r\n clean: boolean;\r\n matches: ScanMatch[];\r\n scannedAt: number;\r\n durationMs: number;\r\n}\r\n\r\ninterface PatternDef {\r\n name: string;\r\n category: ScanCategory;\r\n severity: ScanSeverity;\r\n defaultAction: ScanAction;\r\n /** Must include flag `d` so `exec` returns `indices` for this group. */\r\n pattern: RegExp;\r\n validate?: (match: string) => boolean;\r\n /**\r\n * When set, only this capture group's span is redacted and stored as `value`\r\n * (avoids eating `TOKEN =` / quotes into the placeholder and secretsMap).\r\n */\r\n valueGroup?: number;\r\n}\r\n\r\nconst SECRET_PATTERNS: PatternDef[] = [\r\n { name: \"anthropic-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sk-ant-api\\d{2}-[A-Za-z0-9_-]{40,}/g },\r\n /** Legacy `sk-…` and modern `sk-proj-…` (hyphenated body); aligned with @pretense/scanner */\r\n { name: \"openai-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g },\r\n { name: \"aws-access-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /AKIA[0-9A-Z]{16}/g },\r\n /** `AWS_SECRET = '…40 chars…'` (not `AWS_SECRET_ACCESS_KEY`, which is covered below). */\r\n { name: \"aws-secret-assignment\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bAWS_SECRET\\s*=\\s*['\"]([A-Za-z0-9/+=]{40})['\"]/gd, valueGroup: 1 },\r\n /**\r\n * Env-style labels with `-` or `.` (e.g. `AWS-SECRET-KEY`, `AWS.SECRET.KEY`, long `ACCESS` forms).\r\n * Case-insensitive `AWS` / `SECRET` / `KEY`. Value: 40-char secret; quotes optional (matches aws-secret-key).\r\n */\r\n {\r\n name: \"aws-secret-key-delimited\",\r\n category: \"secret\",\r\n severity: \"critical\",\r\n defaultAction: \"block\",\r\n pattern: /\\bAWS[-.]SECRET(?:[-.]ACCESS)?[-.]KEY\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gdi,\r\n valueGroup: 1,\r\n },\r\n { name: \"aws-secret-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gd, valueGroup: 1 },\r\n { name: \"github-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /gh[ps]_[A-Za-z0-9_]{36,}/g },\r\n { name: \"github-fine-grained\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /github_pat_[A-Za-z0-9_]{22,}/g },\r\n { name: \"stripe-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:sk|pk|rk)_(?:test|live)_[A-Za-z0-9]{20,}/g },\r\n { name: \"private-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g },\r\n /** Three base64url JWT segments; payload segment is not required to start with `eyJ` (Supabase and many issuers use compact payloads). */\r\n { name: \"jwt-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{4,}/g },\r\n { name: \"database-url\", category: \"credential\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:postgres|mysql|mongodb|redis|amqp):\\/\\/[^\\s'\"\\\\)]+:[^\\s'\"\\\\)]+@[^\\s'\"\\\\)]+/g },\r\n {\r\n name: \"generic-password\",\r\n category: \"credential\",\r\n severity: \"high\",\r\n defaultAction: \"redact\",\r\n // Do not match `token` / `secret` inside identifiers (e.g. GITHUB_TOKEN, AWS_SECRET): require no word/underscore before keyword.\r\n pattern: /(?<![A-Za-z0-9_])(?:password|passwd|pwd|secret|token|api_key|apikey|api-key)\\s*[=:]\\s*['\"]([^\\s'\"]{8,})['\"]/gid,\r\n valueGroup: 1,\r\n },\r\n { name: \"slack-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /xox[bpors]-[A-Za-z0-9-]{10,}/g },\r\n { name: \"google-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /AIza[A-Za-z0-9_-]{35}/g },\r\n { name: \"npm-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /npm_[A-Za-z0-9]{36}/g },\r\n { name: \"sendgrid-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}/g },\r\n { name: \"twilio-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /SK[a-f0-9]{32}/g },\r\n // ─── Additional patterns (v0.3) ──────────────────────────────────────────────\r\n { name: \"azure-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:AccountKey|SharedAccessKey)=[A-Za-z0-9+/=]{40,}/g },\r\n { name: \"mailgun-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /key-[a-f0-9]{32}/g },\r\n { name: \"twilio-sid\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /AC[a-f0-9]{32}/g },\r\n { name: \"heroku-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /[hH]eroku.*[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g },\r\n { name: \"shopify-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /shpat_[a-fA-F0-9]{32}/g },\r\n { name: \"datadog-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /dd[a-z]{1,2}_[a-zA-Z0-9]{32,}/g },\r\n { name: \"vercel-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /vc_[a-zA-Z0-9]{24,}/g },\r\n { name: \"supabase-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sbp_[a-f0-9]{40}/g },\r\n { name: \"linear-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /lin_api_[A-Za-z0-9]{40}/g },\r\n { name: \"cloudflare-api-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /v1\\.0-[a-f0-9]{24}-[a-f0-9]{146}/g },\r\n { name: \"discord-bot-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /[MN][A-Za-z\\d]{23,}\\.[\\w-]{6}\\.[\\w-]{27}/g },\r\n { name: \"grafana-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /eyJrIjoi[A-Za-z0-9_-]{40,}/g },\r\n { name: \"confluent-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /CONFLUENT[A-Z_]*\\s*[=:]\\s*['\"]?[A-Za-z0-9/+=]{16,}['\"]?/g },\r\n { name: \"digitalocean-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /dop_v1_[a-f0-9]{64}/g },\r\n { name: \"doppler-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /dp\\.st\\.[a-z0-9_-]{2,}\\.[A-Za-z0-9]{40,}/g },\r\n { name: \"planetscale-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /pscale_tkn_[A-Za-z0-9_-]{32,}/g },\r\n { name: \"hashicorp-vault-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /hvs\\.[A-Za-z0-9_-]{24,}/g },\r\n { name: \"fastly-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /fastly_[A-Za-z0-9]{32}/g },\r\n { name: \"algolia-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /[a-f0-9]{32}/g, validate: (m) => /ALGOLIA|algolia/.test(m) },\r\n { name: \"pulumi-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /pul-[a-f0-9]{40}/g },\r\n // ─── Extended patterns (v0.6 unit 8) ─────────────────────────────────────────\r\n { name: \"google-oauth-refresh\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bGOCSPX-[A-Za-z0-9_-]{20,}\\b/g },\r\n { name: \"slack-webhook-url\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /https:\\/\\/hooks\\.slack\\.com\\/services\\/T[A-Z0-9]+\\/B[A-Z0-9]+\\/[A-Za-z0-9]{20,}/g },\r\n { name: \"sentry-dsn\", category: \"secret\", severity: \"high\", defaultAction: \"redact\", pattern: /https:\\/\\/[a-f0-9]{32}@o\\d+\\.ingest\\.sentry\\.io\\/\\d+/g },\r\n { name: \"x509-certificate\", category: \"secret\", severity: \"high\", defaultAction: \"redact\", pattern: /-----BEGIN CERTIFICATE-----/g },\r\n { name: \"launchdarkly-sdk-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bsdk-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g },\r\n { name: \"launchdarkly-mobile-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /\\bmob-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g },\r\n /** Stripe signing secrets are often 32+ chars; allow shorter synthetic/test tails so redaction still applies. */\r\n { name: \"stripe-webhook-secret\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bwhsec_[A-Za-z0-9]{16,}\\b/g },\r\n /** Stripe Price / product IDs (`price_…`) — identifiers, not card data, but leak billing context. */\r\n { name: \"stripe-price-id\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /\\bprice_[A-Za-z0-9_]{14,}\\b/g },\r\n /** `FOO_PASSWORD = '…'` / `NEXT_PUBLIC_*_PASSWORD` — generic-password skips when `password` is preceded by `_`. */\r\n {\r\n name: \"env-password-assignment\",\r\n category: \"credential\",\r\n severity: \"high\",\r\n defaultAction: \"block\",\r\n pattern: /\\b[A-Z][A-Z0-9_]*PASSWORD\\s*=\\s*['\"]([^'\"]{6,})['\"]/gd,\r\n valueGroup: 1,\r\n },\r\n /** Quoted common DB dialect names — stack hints when mutating env-style config. */\r\n {\r\n name: \"quoted-db-dialect\",\r\n category: \"credential\",\r\n severity: \"medium\",\r\n defaultAction: \"block\",\r\n pattern: /(['\"])(postgres|mysql|redis)\\1/gd,\r\n valueGroup: 2,\r\n },\r\n];\r\n\r\nconst PII_PATTERNS: PatternDef[] = [\r\n { name: \"ssn\", category: \"pii\", severity: \"critical\", defaultAction: \"redact\", pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g },\r\n { name: \"credit-card\", category: \"pii\", severity: \"critical\", defaultAction: \"redact\", pattern: /\\b(?:\\d[ -]*?){13,19}\\b/g, validate: luhnCheck },\r\n { name: \"email\", category: \"pii\", severity: \"medium\", defaultAction: \"warn\", pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g },\r\n { name: \"phone-us\", category: \"pii\", severity: \"medium\", defaultAction: \"warn\", pattern: /\\b(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b/g },\r\n { name: \"ip-address\", category: \"pii\", severity: \"low\", defaultAction: \"warn\", pattern: /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g, validate: (ip) => !ip.startsWith(\"127.\") && !ip.startsWith(\"0.\") && ip !== \"255.255.255.255\" },\r\n];\r\n\r\nconst ENV_PATTERNS: PatternDef[] = [\r\n { name: \"env-secret\", category: \"credential\", severity: \"high\", defaultAction: \"block\", pattern: /(?:process\\.env\\.|os\\.environ\\[|ENV\\[|getenv\\()['\"]?((?:SECRET|TOKEN|PASSWORD|API_KEY|PRIVATE|AUTH)[A-Z_0-9]*)['\"]?\\]?\\)?/gi },\r\n];\r\n\r\nfunction luhnCheck(num: string): boolean {\r\n const digits = num.replace(/\\D/g, \"\");\r\n if (digits.length < 13 || digits.length > 19) return false;\r\n let sum = 0;\r\n let alternate = false;\r\n for (let i = digits.length - 1; i >= 0; i--) {\r\n let n = parseInt(digits[i]!, 10);\r\n if (alternate) { n *= 2; if (n > 9) n -= 9; }\r\n sum += n;\r\n alternate = !alternate;\r\n }\r\n return sum % 10 === 0;\r\n}\r\n\r\n// ─── Shannon entropy check ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Calculate Shannon entropy of a string. Higher values indicate more randomness.\r\n * Useful for detecting high-entropy strings that may be secrets/tokens.\r\n */\r\nexport function shannonEntropy(str: string): number {\r\n if (str.length === 0) return 0;\r\n const freq = new Map<string, number>();\r\n for (const ch of str) {\r\n freq.set(ch, (freq.get(ch) ?? 0) + 1);\r\n }\r\n let entropy = 0;\r\n const len = str.length;\r\n for (const count of freq.values()) {\r\n const p = count / len;\r\n if (p > 0) entropy -= p * Math.log2(p);\r\n }\r\n return entropy;\r\n}\r\n\r\n/**\r\n * Check if a string is likely a high-entropy secret.\r\n * Returns true if the string is > 20 chars and has entropy > 4.5.\r\n */\r\nexport function isHighEntropy(str: string, minLength = 20, threshold = 4.5): boolean {\r\n if (str.length <= minLength) return false;\r\n return shannonEntropy(str) > threshold;\r\n}\r\n\r\nfunction maskValue(value: string, type: string): string {\r\n if (type.includes(\"key\") || type.includes(\"token\") || type.includes(\"secret\")) return value.slice(0, 6) + \"...\" + value.slice(-4);\r\n if (type === \"ssn\") return \"***-**-\" + value.slice(-4);\r\n if (type === \"credit-card\") return \"****-****-****-\" + value.replace(/\\D/g, \"\").slice(-4);\r\n if (type === \"email\") { const [local, domain] = value.split(\"@\"); return (local?.[0] ?? \"*\") + \"***@\" + (domain ?? \"\"); }\r\n if (value.length > 12) return value.slice(0, 4) + \"...\" + value.slice(-4);\r\n return \"***\";\r\n}\r\n\r\nlet matchCounter = 0;\r\n\r\n// Files larger than this byte budget skip the expensive entropy sweep.\r\n// Big generated/minified files trigger millions of high-entropy candidates\r\n// and produce no useful signal — the regex-pattern pass still runs.\r\nconst ENTROPY_SCAN_MAX_BYTES = 512 * 1024; // 512 KB\r\n\r\nexport function scan(text: string, actionOverrides?: Partial<Record<string, ScanAction>>): SecretScanResult {\r\n const start = performance.now();\r\n const matches: ScanMatch[] = [];\r\n const allPatterns = [...SECRET_PATTERNS, ...PII_PATTERNS, ...ENV_PATTERNS];\r\n\r\n for (const def of allPatterns) {\r\n def.pattern.lastIndex = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = def.pattern.exec(text)) !== null) {\r\n let value = m[0];\r\n let start = m.index;\r\n let end = start + value.length;\r\n\r\n if (def.valueGroup !== undefined) {\r\n const span = m.indices?.[def.valueGroup];\r\n if (!span) continue;\r\n const [gs, ge] = span;\r\n value = text.slice(gs, ge);\r\n start = gs;\r\n end = ge;\r\n }\r\n\r\n if (def.validate && !def.validate(value)) continue;\r\n const action = actionOverrides?.[def.name] ?? def.defaultAction;\r\n matchCounter++;\r\n matches.push({\r\n id: `scan_${matchCounter}`,\r\n category: def.category,\r\n type: def.name,\r\n value,\r\n masked: maskValue(value, def.name),\r\n start,\r\n end,\r\n severity: def.severity,\r\n action,\r\n });\r\n }\r\n }\r\n\r\n // Shannon entropy check for unquoted high-entropy strings.\r\n // Skipped for very large inputs to avoid pathological O(N) regex sweeps\r\n // and the O(N) covered-range check below.\r\n if (text.length <= ENTROPY_SCAN_MAX_BYTES) {\r\n // Pre-sort regex matches by start index so we can skip already-covered\r\n // regions in O(log N) instead of O(N) per entropy candidate. Without this\r\n // the entropy pass becomes catastrophic on large files.\r\n const sortedByStart = [...matches].sort((a, b) => a.start - b.start);\r\n const coveredEnd = (idx: number): number => {\r\n // Returns the largest end-index of any match whose start <= idx.\r\n let lo = 0;\r\n let hi = sortedByStart.length - 1;\r\n let best = -1;\r\n while (lo <= hi) {\r\n const mid = (lo + hi) >> 1;\r\n if (sortedByStart[mid]!.start <= idx) {\r\n best = mid;\r\n lo = mid + 1;\r\n } else {\r\n hi = mid - 1;\r\n }\r\n }\r\n return best >= 0 ? sortedByStart[best]!.end : -1;\r\n };\r\n\r\n const highEntropyPattern = /\\b[A-Za-z0-9_\\-/.+=$]{21,}\\b/g;\r\n highEntropyPattern.lastIndex = 0;\r\n let hem: RegExpExecArray | null;\r\n while ((hem = highEntropyPattern.exec(text)) !== null) {\r\n const value = hem[0];\r\n const end = hem.index + value.length;\r\n // Skip if already matched by a pattern (covered-region check via binary search)\r\n if (coveredEnd(hem.index) >= end) continue;\r\n if (isHighEntropy(value)) {\r\n matchCounter++;\r\n matches.push({\r\n id: `scan_${matchCounter}`,\r\n category: \"secret\",\r\n type: \"high-entropy-string\",\r\n value,\r\n masked: value.slice(0, 6) + \"...\" + value.slice(-4),\r\n start: hem.index,\r\n end,\r\n severity: \"medium\",\r\n action: actionOverrides?.[\"high-entropy-string\"] ?? \"warn\",\r\n });\r\n }\r\n }\r\n }\r\n\r\n const severityRank: Record<ScanSeverity, number> = { critical: 4, high: 3, medium: 2, low: 1 };\r\n matches.sort((a, b) => a.start - b.start || severityRank[b.severity] - severityRank[a.severity]);\r\n\r\n const deduped: ScanMatch[] = [];\r\n let lastEnd = -1;\r\n for (const match of matches) {\r\n if (match.start >= lastEnd) {\r\n deduped.push(match);\r\n lastEnd = match.end;\r\n }\r\n }\r\n\r\n return {\r\n clean: deduped.filter((m) => m.action === \"block\" || m.action === \"redact\").length === 0,\r\n matches: deduped,\r\n scannedAt: Date.now(),\r\n durationMs: Math.round((performance.now() - start) * 100) / 100,\r\n };\r\n}\r\n\r\nexport function applyRedactions(text: string, matches: ScanMatch[]): string {\r\n return applyRedactionsTracked(text, matches).redactedCode;\r\n}\r\n\r\nexport interface RedactionResult {\r\n redactedCode: string;\r\n /** Maps each synthetic placeholder token (e.g. `_slx3k7`) to its original value. */\r\n secretsMap: Map<string, string>;\r\n}\r\n\r\n/** Prefix for secret-span placeholders — matches mutator-style `_v` / `_fn` tokens (not vendor-specific). */\r\nconst SECRET_LITERAL_PREFIX = \"_sl\";\r\n\r\n/**\r\n * Replace secret/PII values with deterministic synthetic tokens and return a\r\n * map for exact reversal. Placeholders use the same seeded hash scheme as\r\n * identifier mutation (`_sl` + 4 alphanumeric chars) so nothing leaks vendor or pattern names.\r\n */\r\nexport function applyRedactionsTracked(\r\n text: string,\r\n matches: ScanMatch[],\r\n mutationSeed: string = buildSaltedSeed(\"pretense\"),\r\n): RedactionResult {\r\n const actionable = matches.filter((m) => m.action === \"block\" || m.action === \"redact\");\r\n const sorted = [...actionable].sort((a, b) => b.start - a.start);\r\n\r\n const secretsMap = new Map<string, string>();\r\n\r\n const placeholders = new Map<string, string>();\r\n const forward = [...actionable].sort((a, b) => a.start - b.start);\r\n for (const match of forward) {\r\n const tag = deterministicSyntheticId(`${match.id}:${match.start}`, mutationSeed, SECRET_LITERAL_PREFIX);\r\n placeholders.set(match.id, tag);\r\n secretsMap.set(tag, match.value);\r\n }\r\n\r\n // Second pass (reverse order) to splice placeholders into the text\r\n let result = text;\r\n for (const match of sorted) {\r\n const tag = placeholders.get(match.id)!;\r\n result = result.slice(0, match.start) + tag + result.slice(match.end);\r\n }\r\n\r\n return { redactedCode: result, secretsMap };\r\n}\r\n\r\nexport function getPatternCount(): number {\r\n return SECRET_PATTERNS.length + PII_PATTERNS.length + ENV_PATTERNS.length;\r\n}\r\n","/**\r\n * Pretense Core — Mutation Store\r\n *\r\n * In-memory store with JSON file persistence for MutationMap entries.\r\n * SQLite replaces this in v0.2. For now: simple, zero-dependency, works.\r\n *\r\n * File: ~/.pretense/store.json (configurable)\r\n */\r\n\r\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from \"fs\";\r\nimport { dirname } from \"path\";\r\nimport type { StoreEntry, MutationMap } from \"./types.js\";\r\n\r\nexport class MutationStore {\r\n private entries: Map<string, StoreEntry> = new Map();\r\n private readonly filePath: string;\r\n\r\n constructor(filePath: string) {\r\n this.filePath = filePath;\r\n }\r\n\r\n /**\r\n * Persist a mutation map with associated metadata.\r\n *\r\n * @example\r\n * store.save({ id: \"req-1\", originalHash: \"abc\", mapEntries: [...], timestamp: Date.now(), language: \"typescript\" });\r\n */\r\n save(entry: StoreEntry): void {\r\n this.entries.set(entry.id, { ...entry });\r\n }\r\n\r\n /**\r\n * Retrieve a stored entry by request ID.\r\n *\r\n * @example\r\n * const entry = store.get(\"req-1\");\r\n */\r\n get(id: string): StoreEntry | null {\r\n return this.entries.get(id) ?? null;\r\n }\r\n\r\n /**\r\n * Find the most recent entry whose originalHash matches.\r\n *\r\n * @example\r\n * const entry = store.getByHash(\"sha256-abc123\");\r\n */\r\n getByHash(hash: string): StoreEntry | null {\r\n for (const entry of [...this.entries.values()].reverse()) {\r\n if (entry.originalHash === hash) return entry;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Return all stored entries, newest first, up to `limit`.\r\n *\r\n * @example\r\n * store.list(10) // last 10 entries\r\n */\r\n list(limit = 50): StoreEntry[] {\r\n const all = [...this.entries.values()].reverse();\r\n return all.slice(0, limit);\r\n }\r\n\r\n /**\r\n * Delete an entry by ID. Returns true if it existed.\r\n */\r\n delete(id: string): boolean {\r\n return this.entries.delete(id);\r\n }\r\n\r\n /**\r\n * Remove all entries from memory.\r\n */\r\n clear(): void {\r\n this.entries.clear();\r\n }\r\n\r\n /**\r\n * Write current in-memory state to the JSON file.\r\n */\r\n persist(): void {\r\n const dir = dirname(this.filePath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n const data = JSON.stringify([...this.entries.values()], null, 2);\r\n writeFileSync(this.filePath, data, \"utf-8\");\r\n }\r\n\r\n /**\r\n * Load entries from the JSON file into memory.\r\n * No-ops if the file doesn't exist.\r\n */\r\n load(): void {\r\n if (!existsSync(this.filePath)) return;\r\n try {\r\n const raw = readFileSync(this.filePath, \"utf-8\");\r\n const parsed = JSON.parse(raw) as StoreEntry[];\r\n this.entries.clear();\r\n for (const entry of parsed) {\r\n this.entries.set(entry.id, entry);\r\n }\r\n } catch {\r\n // Corrupted or empty file — start fresh\r\n this.entries.clear();\r\n }\r\n }\r\n\r\n /** Total entries in memory */\r\n get size(): number {\r\n return this.entries.size;\r\n }\r\n\r\n /**\r\n * Reconstruct a MutationMap from a stored entry.\r\n *\r\n * @example\r\n * const map = store.toMap(entry);\r\n * reverse(mutatedCode, map);\r\n */\r\n static toMap(entry: StoreEntry): MutationMap {\r\n return new Map(entry.mapEntries);\r\n }\r\n\r\n /**\r\n * Serialize a MutationMap to the format stored in StoreEntry.\r\n */\r\n static fromMap(map: MutationMap): [string, string][] {\r\n return [...map.entries()];\r\n }\r\n}\r\n","/**\r\n * Pretense CLI — Configuration Manager\r\n *\r\n * Reads/writes the .pretense/ directory for project-level config,\r\n * mutation maps, and audit logs.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\r\nimport { join, resolve } from \"path\";\r\nimport { createHmac } from \"node:crypto\";\r\nimport type { PretenseConfig } from \"./types.js\";\r\nimport { DEFAULT_CONFIG } from \"./types.js\";\r\n\r\nconst CONFIG_DIR_NAME = \".pretense\";\r\nconst CONFIG_FILE = \"config.json\";\r\nconst MUTATION_MAP_FILE = \"mutation-map.json\";\r\nconst AUDIT_LOG_FILE = \"audit.log\";\r\nconst USAGE_FILE = \"usage.json\";\r\n\r\n/**\r\n * Get the .pretense/ config directory path for a given base directory.\r\n */\r\nexport function getConfigDir(baseDir?: string): string {\r\n const base = baseDir ?? process.cwd();\r\n return resolve(base, CONFIG_DIR_NAME);\r\n}\r\n\r\n/**\r\n * Initialize the .pretense/ directory with default config files.\r\n * Creates config.json, empty mutation-map.json, and empty audit.log.\r\n *\r\n * @returns The path to the created .pretense/ directory\r\n */\r\nexport function initConfig(dir?: string): string {\r\n const configDir = getConfigDir(dir);\r\n\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n\r\n // config.json\r\n const configPath = join(configDir, CONFIG_FILE);\r\n if (!existsSync(configPath)) {\r\n const config: PretenseConfig = {\r\n ...DEFAULT_CONFIG,\r\n storePath: configDir,\r\n };\r\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\r\n }\r\n\r\n // mutation-map.json\r\n const mapPath = join(configDir, MUTATION_MAP_FILE);\r\n if (!existsSync(mapPath)) {\r\n writeFileSync(mapPath, \"[]\", \"utf-8\");\r\n }\r\n\r\n // audit.log\r\n const auditPath = join(configDir, AUDIT_LOG_FILE);\r\n if (!existsSync(auditPath)) {\r\n writeFileSync(auditPath, \"\", \"utf-8\");\r\n }\r\n\r\n // usage.json\r\n const usagePath = join(configDir, USAGE_FILE);\r\n if (!existsSync(usagePath)) {\r\n const today = new Date().toISOString().slice(0, 10);\r\n const month = today.slice(0, 7);\r\n const usageData: UsageData = { month, mutations: 0, firstUseDate: today };\r\n writeFileSync(\r\n usagePath,\r\n JSON.stringify({ ...usageData, date: today, checksum: computeUsageChecksum(usageData) }, null, 2),\r\n \"utf-8\",\r\n );\r\n }\r\n\r\n return configDir;\r\n}\r\n\r\n/**\r\n * Load config from .pretense/config.json.\r\n * Returns DEFAULT_CONFIG if the file doesn't exist or is corrupted.\r\n */\r\nexport function loadConfig(dir?: string): PretenseConfig {\r\n const configDir = getConfigDir(dir);\r\n const configPath = join(configDir, CONFIG_FILE);\r\n\r\n if (!existsSync(configPath)) {\r\n return { ...DEFAULT_CONFIG };\r\n }\r\n\r\n try {\r\n const raw = readFileSync(configPath, \"utf-8\");\r\n const parsed = JSON.parse(raw) as Partial<PretenseConfig>;\r\n return { ...DEFAULT_CONFIG, ...parsed };\r\n } catch {\r\n return { ...DEFAULT_CONFIG };\r\n }\r\n}\r\n\r\n/**\r\n * Save config to .pretense/config.json.\r\n */\r\nexport function saveConfig(config: PretenseConfig, dir?: string): void {\r\n const configDir = getConfigDir(dir);\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n const configPath = join(configDir, CONFIG_FILE);\r\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\r\n}\r\n\r\n// ─── Usage integrity ─────────────────────────────────────────────────────────\r\n\r\n/** App-level secret used for usage.json HMAC when no external secret is set */\r\nconst USAGE_HMAC_SECRET = \"pretense_usage_integrity_v1\";\r\n\r\nfunction getUsageSecret(): string {\r\n return process.env[\"PRETENSE_USAGE_SECRET\"] ?? USAGE_HMAC_SECRET;\r\n}\r\n\r\nfunction computeUsageChecksum(data: { month: string; mutations: number; firstUseDate: string }): string {\r\n const payload = JSON.stringify({ month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate });\r\n return createHmac(\"sha256\", getUsageSecret()).update(payload).digest(\"hex\");\r\n}\r\n\r\nfunction verifyUsageChecksum(data: { month: string; mutations: number; firstUseDate: string; checksum?: string }): boolean {\r\n if (!data.checksum) return false;\r\n return data.checksum === computeUsageChecksum(data);\r\n}\r\n\r\n// ─── Usage tracking ──────────────────────────────────────────────────────────\r\n\r\nexport interface UsageData {\r\n month: string;\r\n mutations: number;\r\n firstUseDate: string;\r\n}\r\n\r\nexport function loadUsage(dir?: string): UsageData {\r\n const configDir = getConfigDir(dir);\r\n const usagePath = join(configDir, USAGE_FILE);\r\n\r\n const today = new Date().toISOString().slice(0, 10);\r\n const currentMonth = today.slice(0, 7); // YYYY-MM\r\n\r\n if (!existsSync(usagePath)) {\r\n return { month: currentMonth, mutations: 0, firstUseDate: today };\r\n }\r\n\r\n try {\r\n const raw = readFileSync(usagePath, \"utf-8\");\r\n const data = JSON.parse(raw) as UsageData & { checksum?: string; date?: string };\r\n\r\n // Migrate legacy daily format: if 'date' field exists but not 'month'\r\n if (data.date && !data.month) {\r\n const legacyDate = data.date as string;\r\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? legacyDate };\r\n }\r\n\r\n // Verify integrity checksum\r\n if (!verifyUsageChecksum({ month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate, checksum: data.checksum })) {\r\n process.stderr.write(\"[PRETENSE] Warning: usage.json integrity check failed. Resetting usage counter.\\n\");\r\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? today };\r\n }\r\n\r\n // Reset counter if it's a new month\r\n if (data.month !== currentMonth) {\r\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? today };\r\n }\r\n return { month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate };\r\n } catch {\r\n return { month: currentMonth, mutations: 0, firstUseDate: today };\r\n }\r\n}\r\n\r\nexport function saveUsage(usage: UsageData, dir?: string): void {\r\n const configDir = getConfigDir(dir);\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n const usagePath = join(configDir, USAGE_FILE);\r\n const checksum = computeUsageChecksum(usage);\r\n writeFileSync(usagePath, JSON.stringify({ ...usage, checksum }, null, 2), \"utf-8\");\r\n}\r\n\r\n// ─── License tier detection ───────────────────────────────────────────────────\r\n\r\nexport type LicenseTier = \"free\" | \"pro\" | \"enterprise\";\r\n\r\n/** Minimum key length: 8-char prefix + 32-char alphanumeric payload */\r\nconst MIN_LICENSE_KEY_LENGTH = 40;\r\nconst LICENSE_PAYLOAD_REGEX = /^[a-zA-Z0-9]+$/;\r\n\r\n/**\r\n * Validate license key format:\r\n * 1. Must be at least MIN_LICENSE_KEY_LENGTH chars\r\n * 2. Payload (after prefix) must be alphanumeric\r\n * 3. If PRETENSE_LICENSE_SECRET is set, validate HMAC:\r\n * key format = `pre_pro_<payload>_<hmac>` where hmac = HMAC-SHA256(payload, secret) truncated to 16 hex chars\r\n */\r\nfunction isValidLicenseKey(key: string, prefix: string): boolean {\r\n if (key.length < MIN_LICENSE_KEY_LENGTH) return false;\r\n\r\n const afterPrefix = key.slice(prefix.length);\r\n\r\n const hmacSecret = process.env[\"PRETENSE_LICENSE_SECRET\"];\r\n if (hmacSecret) {\r\n // HMAC mode: expect format `<payload>_<hmac16hex>`\r\n const lastUnderscore = afterPrefix.lastIndexOf(\"_\");\r\n if (lastUnderscore === -1) return false;\r\n const payload = afterPrefix.slice(0, lastUnderscore);\r\n const providedHmac = afterPrefix.slice(lastUnderscore + 1);\r\n if (!payload || !providedHmac) return false;\r\n if (!LICENSE_PAYLOAD_REGEX.test(payload)) return false;\r\n const expectedHmac = createHmac(\"sha256\", hmacSecret).update(payload).digest(\"hex\").slice(0, 16);\r\n return providedHmac === expectedHmac;\r\n }\r\n\r\n // Offline mode: length + alphanumeric validation only\r\n return LICENSE_PAYLOAD_REGEX.test(afterPrefix);\r\n}\r\n\r\nexport function detectTier(): LicenseTier {\r\n const key = process.env[\"PRETENSE_LICENSE_KEY\"] ?? \"\";\r\n if (key.startsWith(\"pre_ent_\") && isValidLicenseKey(key, \"pre_ent_\")) return \"enterprise\";\r\n if (key.startsWith(\"pre_pro_\") && isValidLicenseKey(key, \"pre_pro_\")) return \"pro\";\r\n return \"free\";\r\n}\r\n\r\n/** Map dashboard `/auth/validate` plan to local tier for limits/UI. API keys (`prtns_live_*`) do not set `PRETENSE_LICENSE_KEY`, so paid users must use this when validation is cached. */\r\nexport function tierFromDashboardPlan(\r\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\" | undefined,\r\n fallback: LicenseTier,\r\n): LicenseTier {\r\n if (plan === \"ENTERPRISE\") return \"enterprise\";\r\n if (plan === \"PRO\") return \"pro\";\r\n return fallback;\r\n}\r\n\r\nexport function getTierLimits(tier: LicenseTier): { monthlyMutations: number; auditRetentionDays: number } {\r\n switch (tier) {\r\n case \"enterprise\":\r\n return { monthlyMutations: Infinity, auditRetentionDays: Infinity };\r\n case \"pro\":\r\n return { monthlyMutations: Infinity, auditRetentionDays: 90 };\r\n case \"free\":\r\n default:\r\n return { monthlyMutations: 1000, auditRetentionDays: 30 };\r\n }\r\n}\r\n","/**\r\n * Pretense CLI — Audit Logger\r\n *\r\n * Writes JSON lines to .pretense/audit.log for compliance and debugging.\r\n * Supports JSON and CSV output formats. Tier-gated retention.\r\n */\r\n\r\nimport { appendFileSync, existsSync, readFileSync, mkdirSync } from \"fs\";\r\nimport { join, dirname } from \"path\";\r\nimport { getConfigDir, detectTier, getTierLimits } from \"./config.js\";\r\n\r\n// ─── Types ───────────────────────────────────────────────────────────────────\r\n\r\nexport interface AuditEntry {\r\n timestamp: string;\r\n sessionId: string;\r\n file: string;\r\n identifiersMutated: number;\r\n secretsBlocked: number;\r\n llmProvider: string;\r\n latencyMs: number;\r\n}\r\n\r\nexport interface AuditReadOptions {\r\n limit?: number;\r\n format?: \"json\" | \"csv\" | \"text\";\r\n dir?: string;\r\n}\r\n\r\n// ─── Write ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Append an audit entry as a JSON line to .pretense/audit.log.\r\n */\r\nexport function writeAuditEntry(entry: AuditEntry, dir?: string): void {\r\n const configDir = getConfigDir(dir);\r\n const auditPath = join(configDir, \"audit.log\");\r\n\r\n const logDir = dirname(auditPath);\r\n if (!existsSync(logDir)) {\r\n mkdirSync(logDir, { recursive: true });\r\n }\r\n\r\n const line = JSON.stringify(entry) + \"\\n\";\r\n appendFileSync(auditPath, line, \"utf-8\");\r\n}\r\n\r\n/**\r\n * Create a new audit entry with current timestamp.\r\n */\r\nexport function createAuditEntry(\r\n sessionId: string,\r\n file: string,\r\n identifiersMutated: number,\r\n secretsBlocked: number,\r\n llmProvider: string,\r\n latencyMs: number,\r\n): AuditEntry {\r\n return {\r\n timestamp: new Date().toISOString(),\r\n sessionId,\r\n file,\r\n identifiersMutated,\r\n secretsBlocked,\r\n llmProvider,\r\n latencyMs,\r\n };\r\n}\r\n\r\n// ─── Read ────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Read and parse the audit log. Applies tier-based retention filtering.\r\n */\r\nexport function readAuditLog(options: AuditReadOptions = {}): AuditEntry[] {\r\n const { limit, dir } = options;\r\n const configDir = getConfigDir(dir);\r\n const auditPath = join(configDir, \"audit.log\");\r\n\r\n if (!existsSync(auditPath)) {\r\n return [];\r\n }\r\n\r\n const raw = readFileSync(auditPath, \"utf-8\");\r\n const lines = raw.trim().split(\"\\n\").filter(Boolean);\r\n\r\n let entries: AuditEntry[] = [];\r\n for (const line of lines) {\r\n try {\r\n entries.push(JSON.parse(line) as AuditEntry);\r\n } catch {\r\n // Skip malformed lines\r\n }\r\n }\r\n\r\n // Apply tier-based retention filter\r\n const tier = detectTier();\r\n const { auditRetentionDays } = getTierLimits(tier);\r\n\r\n if (auditRetentionDays !== Infinity) {\r\n const cutoff = Date.now() - auditRetentionDays * 24 * 60 * 60 * 1000;\r\n entries = entries.filter((e) => new Date(e.timestamp).getTime() >= cutoff);\r\n }\r\n\r\n // Sort newest first\r\n entries.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\r\n\r\n // Apply limit\r\n if (limit && limit > 0) {\r\n entries = entries.slice(0, limit);\r\n }\r\n\r\n return entries;\r\n}\r\n\r\n// ─── Formatters ──────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Format audit entries as JSON string.\r\n */\r\nexport function formatJson(entries: AuditEntry[]): string {\r\n return JSON.stringify(entries, null, 2);\r\n}\r\n\r\n/**\r\n * Format audit entries as CSV string.\r\n */\r\nexport function formatCsv(entries: AuditEntry[]): string {\r\n const headers = \"timestamp,sessionId,file,identifiersMutated,secretsBlocked,llmProvider,latencyMs\";\r\n const rows = entries.map((e) =>\r\n [\r\n e.timestamp,\r\n e.sessionId,\r\n `\"${e.file.replace(/\"/g, '\"\"')}\"`,\r\n e.identifiersMutated,\r\n e.secretsBlocked,\r\n e.llmProvider,\r\n e.latencyMs,\r\n ].join(\",\"),\r\n );\r\n return [headers, ...rows].join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Format audit entries as human-readable text.\r\n */\r\nexport function formatText(entries: AuditEntry[]): string {\r\n if (entries.length === 0) return \"No audit entries found.\";\r\n\r\n const lines = entries.map((e) => {\r\n const date = new Date(e.timestamp).toLocaleString();\r\n return `[${date}] ${e.file} | ${e.identifiersMutated} mutated | ${e.secretsBlocked} secrets blocked | ${e.llmProvider} | ${e.latencyMs}ms`;\r\n });\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Format entries using the specified format.\r\n */\r\nexport function formatAudit(entries: AuditEntry[], format: \"json\" | \"csv\" | \"text\" = \"text\"): string {\r\n switch (format) {\r\n case \"json\":\r\n return formatJson(entries);\r\n case \"csv\":\r\n return formatCsv(entries);\r\n case \"text\":\r\n default:\r\n return formatText(entries);\r\n }\r\n}\r\n","/**\r\n * Pretense CLI — Proxy Server\r\n *\r\n * Hono HTTP proxy that intercepts LLM API calls, scans + mutates\r\n * proprietary code, forwards to the real provider, then reverse-mutates\r\n * the response. Supports Anthropic, OpenAI, and Google Gemini.\r\n *\r\n * Includes free-tier enforcement, usage tracking, and upgrade nudges.\r\n * Drop-in replacement: set *_BASE_URL=http://localhost:9339 and done.\r\n */\r\n\r\nimport { Hono } from \"hono\";\r\nimport { serve } from \"@hono/node-server\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { createServer } from \"node:net\";\r\nimport { existsSync, watch } from \"node:fs\";\r\nimport { mutate } from \"./mutator.js\";\r\nimport { reverse } from \"./reverser.js\";\r\nimport { detectLanguage } from \"./scanner.js\";\r\nimport { MutationStore } from \"./store.js\";\r\nimport { scan as scanSecrets, applyRedactions } from \"./secrets.js\";\r\nimport { writeAuditEntry, createAuditEntry } from \"./audit.js\";\r\nimport {\r\n loadUsage,\r\n saveUsage,\r\n detectTier,\r\n getTierLimits,\r\n getConfigDir,\r\n tierFromDashboardPlan,\r\n type LicenseTier,\r\n} from \"./config.js\";\r\nimport type { StoreEntry, PretenseConfig } from \"./types.js\";\r\nimport { DEFAULT_CONFIG } from \"./types.js\";\r\nimport { requireApiKey } from \"./auth.js\";\r\nimport { getSession, sessionCount } from \"./session-store.js\";\r\nimport { uploadLog } from \"./log-uploader.js\";\r\nimport {\r\n validateKey,\r\n getCachedValidation,\r\n isWithinLimits,\r\n getPretenseApiKey,\r\n bumpCachedUsageAfterLog,\r\n clearValidationCache,\r\n} from \"./backend-client.js\";\r\nimport {\r\n installDashboardKeyForCurrentProcess,\r\n promptDashboardApiKeyAfterFailure,\r\n isValidKeyShape,\r\n loadApiKey,\r\n getUserDashboardConfigDir,\r\n} from \"./commands/login.js\";\r\nimport { printStartClientInstructions } from \"./start-client-instructions.js\";\r\nimport { getCliSemver } from \"./version.js\";\r\n\r\n/**\r\n * When `pretense logout` clears ~/.pretense/config.json while this proxy runs,\r\n * we flip this flag (via fs.watch) so POST mutation stops without restarting.\r\n * Only active when the process did not start with $PRETENSE_API_KEY set (env overrides file).\r\n */\r\nlet dashboardSavedCredentialsRevoked = false;\r\n\r\nfunction attachDashboardLogoutWatcher(enabled: boolean): void {\r\n if (!enabled) return;\r\n\r\n const dir = getUserDashboardConfigDir();\r\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n const applyFilesystemCredentialState = (): void => {\r\n const fk = loadApiKey();\r\n if (!fk) {\r\n if (dashboardSavedCredentialsRevoked) return;\r\n dashboardSavedCredentialsRevoked = true;\r\n delete process.env[\"PRETENSE_API_KEY\"];\r\n clearValidationCache();\r\n try {\r\n process.stderr.write(\r\n `\\x1b[33m[PRETENSE] Saved dashboard API key removed (~/.pretense/config.json, e.g. pretense logout). ` +\r\n `LLM proxy POST requests are disabled until you run pretense login and restart pretense start.\\x1b[0m\\n`,\r\n );\r\n } catch {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n if (dashboardSavedCredentialsRevoked) {\r\n dashboardSavedCredentialsRevoked = false;\r\n clearValidationCache();\r\n }\r\n };\r\n\r\n const schedule = (): void => {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(applyFilesystemCredentialState, 120);\r\n };\r\n\r\n try {\r\n if (!existsSync(dir)) return;\r\n watch(dir, () => {\r\n schedule();\r\n });\r\n } catch {\r\n /* fs.watch unavailable */\r\n }\r\n}\r\n\r\n// ─── Provider detection ───────────────────────────────────────────────────────\r\n\r\nfunction anthropicUpstream(): string { return process.env[\"ANTHROPIC_UPSTREAM_URL\"] ?? \"https://api.anthropic.com\"; }\r\nfunction openaiUpstream(): string { return process.env[\"OPENAI_UPSTREAM_URL\"] ?? \"https://api.openai.com\"; }\r\nfunction geminiUpstream(): string { return process.env[\"GEMINI_UPSTREAM_URL\"] ?? \"https://generativelanguage.googleapis.com\"; }\r\nfunction ollamaUpstream(): string { return process.env[\"OLLAMA_UPSTREAM_URL\"] ?? \"http://localhost:11434\"; }\r\n\r\nfunction detectUpstream(path: string): string {\r\n // Anthropic — Claude Code / Anthropic SDK\r\n if (path.startsWith(\"/v1/messages\")) return anthropicUpstream();\r\n // OpenAI — Chat Completions, Completions, Responses (Codex CLI)\r\n if (\r\n path.startsWith(\"/v1/chat/completions\") ||\r\n path.startsWith(\"/v1/completions\") ||\r\n path.startsWith(\"/v1/responses\")\r\n ) {\r\n return openaiUpstream();\r\n }\r\n // Google Gemini\r\n if (path.startsWith(\"/v1beta/\") || path.startsWith(\"/v1/models\")) return geminiUpstream();\r\n // Ollama (local LLM) — chat + generate endpoints\r\n if (path.startsWith(\"/api/chat\") || path.startsWith(\"/api/generate\")) return ollamaUpstream();\r\n // Default to Anthropic (Claude Code is the most common consumer)\r\n return anthropicUpstream();\r\n}\r\n\r\nfunction detectProvider(path: string): string {\r\n if (path.startsWith(\"/v1/messages\")) return \"anthropic\";\r\n if (\r\n path.startsWith(\"/v1/chat/completions\") ||\r\n path.startsWith(\"/v1/completions\") ||\r\n path.startsWith(\"/v1/responses\")\r\n ) {\r\n return \"openai\";\r\n }\r\n if (path.startsWith(\"/v1beta/\") || path.startsWith(\"/v1/models\")) return \"google\";\r\n if (path.startsWith(\"/api/chat\") || path.startsWith(\"/api/generate\")) return \"ollama\";\r\n return \"anthropic\";\r\n}\r\n\r\n/** Strip Pretense-only headers before forwarding; they must never reach the LLM vendor. */\r\nfunction stripPretenseOnlyForwardingHeaders(headers: Record<string, string>): void {\r\n const drop = new Set([\"x-pretense-api-key\", \"x-pretense-key\"]);\r\n for (const k of [...Object.keys(headers)]) {\r\n if (drop.has(k.toLowerCase())) delete headers[k];\r\n }\r\n}\r\n\r\n// ─── Message text extraction ──────────────────────────────────────────────────\r\n\r\nfunction extractText(body: Record<string, unknown>): string {\r\n const parts: string[] = [];\r\n if (typeof body[\"system\"] === \"string\") parts.push(body[\"system\"]);\r\n if (Array.isArray(body[\"messages\"])) {\r\n for (const msg of body[\"messages\"] as Record<string, unknown>[]) {\r\n if (typeof msg[\"content\"] === \"string\") parts.push(msg[\"content\"]);\r\n else if (Array.isArray(msg[\"content\"])) {\r\n for (const block of msg[\"content\"] as Record<string, unknown>[]) {\r\n if (block[\"type\"] === \"text\" && typeof block[\"text\"] === \"string\") parts.push(block[\"text\"]);\r\n }\r\n }\r\n }\r\n }\r\n return parts.join(\"\\n\");\r\n}\r\n\r\n// ─── Code block extraction (inline — no external dep) ────────────────────────\r\n\r\ninterface CodeBlock {\r\n code: string;\r\n language: string;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nfunction extractCodeBlocks(text: string): CodeBlock[] {\r\n const blocks: CodeBlock[] = [];\r\n const re = /```(\\w*)\\n([\\s\\S]*?)```/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(text)) !== null) {\r\n blocks.push({\r\n code: m[2] ?? \"\",\r\n language: m[1] ?? \"typescript\",\r\n start: m.index,\r\n end: m.index + m[0].length,\r\n });\r\n }\r\n return blocks;\r\n}\r\n\r\nfunction replaceCodeBlocks(text: string, blocks: CodeBlock[], replacements: string[]): string {\r\n let result = text;\r\n // Replace in reverse order to preserve indices\r\n for (let i = blocks.length - 1; i >= 0; i--) {\r\n const block = blocks[i]!;\r\n const replacement = replacements[i] ?? block.code;\r\n const lang = block.language ?? \"typescript\";\r\n result = result.slice(0, block.start) + \"```\" + lang + \"\\n\" + replacement + \"```\" + result.slice(block.end);\r\n }\r\n return result;\r\n}\r\n\r\n// ─── Apply text mutations to message body ────────────────────────────────────\r\n\r\nfunction applyToBody(\r\n body: Record<string, unknown>,\r\n transform: (text: string) => string,\r\n): Record<string, unknown> {\r\n const mutateField = (val: unknown): unknown => {\r\n if (typeof val === \"string\") return transform(val);\r\n if (Array.isArray(val)) return val.map(mutateField);\r\n if (val && typeof val === \"object\") {\r\n const obj = val as Record<string, unknown>;\r\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, mutateField(v)]));\r\n }\r\n return val;\r\n };\r\n\r\n return mutateField(body) as Record<string, unknown>;\r\n}\r\n\r\n// ─── Stats tracking ───────────────────────────────────────────────────────────\r\n\r\ninterface ProxyStats {\r\n requestsProcessed: number;\r\n totalTokensMutated: number;\r\n totalSecretsBlocked: number;\r\n startedAt: number;\r\n}\r\n\r\nconst stats: ProxyStats = {\r\n requestsProcessed: 0,\r\n totalTokensMutated: 0,\r\n totalSecretsBlocked: 0,\r\n startedAt: Date.now(),\r\n};\r\n\r\n// ─── Upgrade nudge helpers ───────────────────────────────────────────────────\r\n\r\nfunction daysSinceFirstUse(): number {\r\n const usage = loadUsage();\r\n if (!usage.firstUseDate) return 0;\r\n const first = new Date(usage.firstUseDate).getTime();\r\n return Math.floor((Date.now() - first) / (24 * 60 * 60 * 1000));\r\n}\r\n\r\nfunction printUpgradeNudge(reason: string): void {\r\n process.stdout.write(\r\n `\\n\\x1b[33m[PRETENSE] ${reason}\\x1b[0m\\n` +\r\n `\\x1b[33m[PRETENSE] Upgrade to Pro: https://pretense.ai/pricing\\x1b[0m\\n\\n`,\r\n );\r\n}\r\n\r\n// ─── Proxy factory ────────────────────────────────────────────────────────────\r\n\r\nexport interface ProxyOptions {\r\n config?: Partial<PretenseConfig>;\r\n store?: MutationStore;\r\n verbose?: boolean;\r\n}\r\n\r\ntype ProxyEnv = { Variables: { sessionHash: string } };\r\n\r\nexport function createProxy(opts: ProxyOptions = {}): Hono<ProxyEnv> {\r\n const config: PretenseConfig = { ...DEFAULT_CONFIG, ...opts.config };\r\n const store = opts.store ?? new MutationStore(`${config.storePath}/proxy-store.json`);\r\n const verbose = opts.verbose ?? false;\r\n\r\n const app = new Hono<ProxyEnv>();\r\n\r\n // ── Auth middleware ────────────────────────────────────────────────────────\r\n // Short-circuits public paths (/, /health, /stats, /audit, /tokens) and\r\n // rejects everything else lacking an API key with HTTP 401.\r\n app.use(\"*\", requireApiKey);\r\n\r\n // ── Root welcome ───────────────────────────────────────────────────────────\r\n app.get(\"/\", (c) =>\r\n c.json({\r\n name: \"pretense\",\r\n version: getCliSemver(),\r\n status: \"running\",\r\n routes: {\r\n \"GET /\": \"This welcome page\",\r\n \"GET /health\": \"Health check with uptime\",\r\n \"GET /stats\": \"Mutation statistics\",\r\n \"GET /audit\": \"Audit log (?limit=50)\",\r\n \"POST /*\": \"Proxy to upstream LLM API (Anthropic, OpenAI, Google auto-detected)\",\r\n },\r\n languages: [\"TypeScript\", \"JavaScript\", \"Python\", \"Go\", \"Java\", \"C#\", \"Ruby\", \"Rust\"],\r\n docs: \"https://pretense.ai/docs\",\r\n }),\r\n );\r\n\r\n // ── Health ─────────────────────────────────────────────────────────────────\r\n app.get(\"/health\", (c) =>\r\n c.json({\r\n status: \"ok\",\r\n version: getCliSemver(),\r\n uptime: Math.floor((Date.now() - stats.startedAt) / 1000),\r\n stats: {\r\n requestsProcessed: stats.requestsProcessed,\r\n totalTokensMutated: stats.totalTokensMutated,\r\n },\r\n }),\r\n );\r\n\r\n // ── Stats ──────────────────────────────────────────────────────────────────\r\n app.get(\"/stats\", (c) =>\r\n c.json({\r\n ...stats,\r\n storeSize: store.size,\r\n activeSessions: sessionCount(),\r\n }),\r\n );\r\n\r\n // ── Audit ──────────────────────────────────────────────────────────────────\r\n app.get(\"/audit\", (c) => {\r\n const limit = parseInt(c.req.query(\"limit\") ?? \"50\");\r\n return c.json(store.list(limit));\r\n });\r\n\r\n // ── Main proxy handler ─────────────────────────────────────────────────────\r\n app.all(\"/*\", async (c) => {\r\n if (c.req.method !== \"POST\") {\r\n // Pass-through non-POST (GET model lists, etc.)\r\n const upstream = c.req.header(\"x-pretense-upstream\") ?? detectUpstream(c.req.path);\r\n const url = upstream + c.req.path;\r\n const headers: Record<string, string> = {};\r\n c.req.raw.headers.forEach((v, k) => { headers[k] = v; });\r\n delete headers[\"host\"];\r\n headers[\"host\"] = new URL(upstream).host;\r\n stripPretenseOnlyForwardingHeaders(headers);\r\n const resp = await fetch(url, { method: c.req.method, headers });\r\n return new Response(resp.body, { status: resp.status, headers: Object.fromEntries(resp.headers.entries()) });\r\n }\r\n\r\n const requestStart = performance.now();\r\n\r\n // ── Parse body ────────────────────────────────────────────────────────\r\n let body: Record<string, unknown>;\r\n try {\r\n body = await c.req.json<Record<string, unknown>>();\r\n } catch {\r\n return c.json({ error: { type: \"invalid_request\", message: \"Invalid JSON body\" } }, 400);\r\n }\r\n\r\n if (!body || Object.keys(body).length === 0) {\r\n return c.json({ error: { type: \"invalid_request\", message: \"Empty request body\" } }, 400);\r\n }\r\n\r\n const requestId = nanoid(12);\r\n const upstream = c.req.header(\"x-pretense-upstream\") ?? detectUpstream(c.req.path);\r\n const provider = detectProvider(c.req.path);\r\n\r\n if (dashboardSavedCredentialsRevoked) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_session_logged_out\",\r\n message:\r\n \"Saved Pretense dashboard credentials were removed (for example pretense logout). Run pretense login, then restart pretense start. If you started the proxy with PRETENSE_API_KEY in this shell, stop it (Ctrl+C) and start again after logout.\",\r\n },\r\n },\r\n 401,\r\n );\r\n }\r\n\r\n const pretenseDashboardKey = getPretenseApiKey();\r\n if (!pretenseDashboardKey) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_dashboard_key_required\",\r\n message:\r\n \"Configure your Pretense dashboard API key: run `pretense login --key prtns_live_...` or set PRETENSE_API_KEY.\",\r\n },\r\n },\r\n 401,\r\n );\r\n }\r\n\r\n try {\r\n await validateKey({ verbose, force: false, enforceReachability: true });\r\n } catch (err) {\r\n const code = (err as Error & { code?: string }).code ?? \"\";\r\n const msg = (err as Error).message;\r\n const knownAuthCodes = new Set([\r\n \"KEY_REVOKED\",\r\n \"KEY_EXPIRED\",\r\n \"INVALID_API_KEY\",\r\n \"MISSING_API_KEY\",\r\n ]);\r\n if (knownAuthCodes.has(code)) {\r\n return c.json(\r\n { error: { type: \"pretense_auth_error\", code, message: msg } },\r\n 401,\r\n );\r\n }\r\n if (code === \"BACKEND_UNAVAILABLE\" || code === \"AUTH_BACKEND_REJECTED\") {\r\n return c.json(\r\n { error: { type: \"pretense_auth_backend_error\", code, message: msg } },\r\n 503,\r\n );\r\n }\r\n if (code === \"ORG_INACTIVE\") {\r\n return c.json(\r\n { error: { type: \"pretense_org_inactive\", code, message: msg } },\r\n 403,\r\n );\r\n }\r\n return c.json(\r\n { error: { type: \"pretense_auth_error\", message: msg } },\r\n 401,\r\n );\r\n }\r\n\r\n // ── Session isolation ─────────────────────────────────────────────────\r\n // Two different API keys MUST NOT share mutation map state. The\r\n // requireApiKey middleware already validated the key and stashed\r\n // sha256(key) under \"sessionHash\"; if we get here it's set.\r\n const sessHash = c.get(\"sessionHash\");\r\n const session = getSession(sessHash);\r\n\r\n // ── Free tier enforcement ─────────────────────────────────────────────\r\n // `detectTier()` only sees `PRETENSE_LICENSE_KEY` (pre_pro_*). Dashboard\r\n // keys (prtns_live_*) get PRO/ENTERPRISE from validate — use cached plan.\r\n const tier: LicenseTier = tierFromDashboardPlan(\r\n getCachedValidation()?.plan,\r\n detectTier(),\r\n );\r\n const { monthlyMutations } = getTierLimits(tier);\r\n const usage = loadUsage();\r\n\r\n if (tier === \"free\" && usage.mutations >= monthlyMutations) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_rate_limit\",\r\n message: `Monthly mutation limit reached (${monthlyMutations}/month). Upgrade to Pro for unlimited: https://pretense.ai/pricing`,\r\n },\r\n },\r\n 429,\r\n );\r\n }\r\n\r\n // ── Backend limit enforcement (authoritative when reachable) ──────\r\n const backendLimits = await isWithinLimits();\r\n if (!backendLimits.allowed) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_rate_limit\",\r\n message: backendLimits.reason ?? \"Mutation limit exceeded.\",\r\n },\r\n },\r\n 429,\r\n );\r\n }\r\n\r\n // ── Dashboard key permission: read-only cannot run the mutating proxy ──\r\n const cliAuth = getCachedValidation();\r\n if (cliAuth?.permission === \"read_only\") {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_forbidden\",\r\n message:\r\n \"This API key is read-only. Create a read_write key in the dashboard to use the Pretense proxy.\",\r\n },\r\n },\r\n 403,\r\n );\r\n }\r\n\r\n // ── Secret scan ───────────────────────────────────────────────────────\r\n const fullText = extractText(body);\r\n const secretScan = scanSecrets(fullText);\r\n const blockedSecrets = secretScan.matches.filter((m) => m.action === \"block\");\r\n\r\n if (blockedSecrets.length > 0) {\r\n stats.totalSecretsBlocked += blockedSecrets.length;\r\n\r\n // Pro alert suggestion for secrets\r\n if (tier === \"free\") {\r\n printUpgradeNudge(`${blockedSecrets.length} secret(s) blocked. Pro tier includes real-time secret alerts via Slack/PagerDuty.`);\r\n }\r\n\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_blocked\",\r\n message: `Request blocked: ${blockedSecrets.length} secret(s) detected. Types: ${[...new Set(blockedSecrets.map((m) => m.type))].join(\", \")}`,\r\n },\r\n },\r\n 400,\r\n );\r\n }\r\n\r\n // Apply redactions (PII, warnings)\r\n const processedBody = applyToBody(body, (text) => applyRedactions(text, secretScan.matches));\r\n\r\n // ── Code mutation ─────────────────────────────────────────────────────\r\n // The mutation map is scoped to the session (per-API-key) so two\r\n // different callers never see each other's tokens. We still track a\r\n // per-request local map for logging + the audit StoreEntry below.\r\n const mutationMap = new Map<string, string>();\r\n let tokensMutated = 0;\r\n\r\n const mutatedBody = applyToBody(processedBody, (text) => {\r\n const blocks = extractCodeBlocks(text);\r\n // No markdown fences — still mutate (raw paste is the common case).\r\n if (blocks.length === 0) {\r\n const lang = detectLanguage(text);\r\n const result = mutate(text, lang);\r\n for (const [k, v] of result.map) {\r\n mutationMap.set(k, v);\r\n session.mutationMap.set(k, v);\r\n session.reverseMap.set(v, k);\r\n }\r\n tokensMutated += result.stats.tokensMutated;\r\n return result.mutatedCode;\r\n }\r\n\r\n const mutatedBlocks: string[] = [];\r\n for (const block of blocks) {\r\n const result = mutate(block.code, block.language);\r\n for (const [k, v] of result.map) {\r\n mutationMap.set(k, v);\r\n session.mutationMap.set(k, v);\r\n session.reverseMap.set(v, k);\r\n }\r\n tokensMutated += result.stats.tokensMutated;\r\n mutatedBlocks.push(result.mutatedCode);\r\n }\r\n\r\n return replaceCodeBlocks(text, blocks, mutatedBlocks);\r\n });\r\n\r\n // Update usage tracking\r\n usage.mutations += tokensMutated;\r\n saveUsage(usage);\r\n\r\n // ── Server-side attribution (fire-and-forget) ─────────────────────────\r\n // Upload this event to /api/cli/log with git context. Runs in the\r\n // background so we never add latency to the LLM proxy path. Opt out\r\n // with PRETENSE_DISABLE_REMOTE_LOG=1.\r\n const remoteLogDisabled = process.env[\"PRETENSE_DISABLE_REMOTE_LOG\"] === \"1\";\r\n if (pretenseDashboardKey && !remoteLogDisabled) {\r\n void uploadLog(\r\n {\r\n file_count: 0,\r\n identifiers_mutated: tokensMutated,\r\n secrets_blocked: blockedSecrets.length,\r\n llm_provider: provider,\r\n cli_version: getCliSemver(),\r\n },\r\n { apiKey: pretenseDashboardKey, verbose },\r\n );\r\n bumpCachedUsageAfterLog(tokensMutated);\r\n }\r\n\r\n // Warning at 80% of monthly limit (free tier)\r\n const warningThreshold = Math.floor(monthlyMutations * 0.8);\r\n if (tier === \"free\" && usage.mutations >= warningThreshold && usage.mutations - tokensMutated < warningThreshold) {\r\n printUpgradeNudge(`${usage.mutations}/${monthlyMutations} monthly mutations used. Running low!`);\r\n }\r\n\r\n // 7-day upgrade nudge\r\n if (tier === \"free\" && daysSinceFirstUse() >= 7) {\r\n printUpgradeNudge(\"You've been using Pretense for 7+ days. Unlock Pro features: unlimited mutations, 90-day audit, Slack alerts.\");\r\n }\r\n\r\n // Store mutation map for response reversal\r\n const entry: StoreEntry = {\r\n id: requestId,\r\n originalHash: requestId,\r\n mapEntries: [...mutationMap.entries()],\r\n timestamp: Date.now(),\r\n language: \"mixed\",\r\n };\r\n store.save(entry);\r\n stats.requestsProcessed++;\r\n stats.totalTokensMutated += tokensMutated;\r\n\r\n // Write audit entry\r\n const latencyMs = Math.round((performance.now() - requestStart) * 100) / 100;\r\n writeAuditEntry(\r\n createAuditEntry(requestId, \"proxy-request\", tokensMutated, blockedSecrets.length, provider, latencyMs),\r\n );\r\n\r\n if (verbose && tokensMutated > 0) {\r\n process.stdout.write(`[PRETENSE] ${tokensMutated} tokens mutated for request ${requestId}\\n`);\r\n }\r\n\r\n // ── Forward to upstream ───────────────────────────────────────────────\r\n const headers: Record<string, string> = {};\r\n c.req.raw.headers.forEach((v, k) => { headers[k] = v; });\r\n delete headers[\"host\"];\r\n delete headers[\"content-length\"];\r\n headers[\"host\"] = new URL(upstream).host;\r\n headers[\"x-pretense-request-id\"] = requestId;\r\n stripPretenseOnlyForwardingHeaders(headers);\r\n\r\n const forwardBody = JSON.stringify(mutatedBody);\r\n\r\n let upstreamResp: Response;\r\n try {\r\n upstreamResp = await fetch(upstream + c.req.path, {\r\n method: \"POST\",\r\n headers: { ...headers, \"content-type\": \"application/json\", \"content-length\": String(Buffer.byteLength(forwardBody)) },\r\n body: forwardBody,\r\n });\r\n } catch {\r\n return c.json({ error: { type: \"pretense_upstream_error\", message: \"Failed to reach upstream provider\" } }, 502);\r\n }\r\n\r\n // ── Streaming with reverse-mutation ────────────────────────────────────\r\n if (body[\"stream\"] === true) {\r\n const streamReverseMap = new Map(mutationMap);\r\n const upstream = upstreamResp.body;\r\n if (!upstream || tokensMutated === 0) {\r\n // No mutations to reverse -- pass through as-is.\r\n return new Response(upstream, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"content-type\": upstreamResp.headers.get(\"content-type\") ?? \"text/event-stream\",\r\n \"cache-control\": \"no-cache\",\r\n \"x-pretense-request-id\": requestId,\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n },\r\n });\r\n }\r\n\r\n // Build a TransformStream that reverse-mutates each SSE data line.\r\n const decoder = new TextDecoder();\r\n const encoder = new TextEncoder();\r\n let buffer = \"\";\r\n\r\n const transform = new TransformStream<Uint8Array, Uint8Array>({\r\n transform(chunk, controller) {\r\n buffer += decoder.decode(chunk, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n // Keep the last partial line in the buffer\r\n buffer = lines.pop() ?? \"\";\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(\"data: \") && line !== \"data: [DONE]\") {\r\n try {\r\n const json = JSON.parse(line.slice(6)) as Record<string, unknown>;\r\n // Reverse-mutate text content in the SSE payload\r\n const reversed = applyToBody(json, (text) => reverse(text, streamReverseMap));\r\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(reversed)}\\n`));\r\n } catch {\r\n // If JSON parsing fails, pass line through unchanged.\r\n controller.enqueue(encoder.encode(line + \"\\n\"));\r\n }\r\n } else {\r\n controller.enqueue(encoder.encode(line + \"\\n\"));\r\n }\r\n }\r\n },\r\n flush(controller) {\r\n if (buffer.length > 0) {\r\n controller.enqueue(encoder.encode(buffer));\r\n }\r\n },\r\n });\r\n\r\n const reversedStream = upstream.pipeThrough(transform);\r\n return new Response(reversedStream, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"content-type\": upstreamResp.headers.get(\"content-type\") ?? \"text/event-stream\",\r\n \"cache-control\": \"no-cache\",\r\n \"x-pretense-request-id\": requestId,\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n \"x-pretense-stream-reversal\": \"active\",\r\n },\r\n });\r\n }\r\n\r\n // ── Reverse-mutate response ──────────────────────────────────────────\r\n const reverseMap = new Map(mutationMap);\r\n let respBody: Record<string, unknown>;\r\n try {\r\n respBody = (await upstreamResp.json()) as Record<string, unknown>;\r\n } catch {\r\n return new Response(null, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n },\r\n });\r\n }\r\n\r\n const reversedBody = applyToBody(respBody, (text) => {\r\n const blocks = extractCodeBlocks(text);\r\n if (blocks.length === 0) return reverse(text, reverseMap);\r\n const reversedBlocks = blocks.map((b) => reverse(b.code, reverseMap));\r\n return replaceCodeBlocks(text, blocks, reversedBlocks);\r\n });\r\n\r\n c.header(\"x-pretense-request-id\", requestId);\r\n c.header(\"x-pretense-protected\", \"true\");\r\n c.header(\"x-pretense-mutations\", String(tokensMutated));\r\n return c.json(reversedBody, upstreamResp.status as 200);\r\n });\r\n\r\n return app;\r\n}\r\n\r\n// ─── Port helpers ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether a port is currently free on 127.0.0.1.\r\n */\r\nfunction isPortAvailable(port: number): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const tester = createServer()\r\n .once(\"error\", () => resolve(false))\r\n .once(\"listening\", () => {\r\n tester.once(\"close\", () => resolve(true)).close();\r\n })\r\n .listen(port, \"127.0.0.1\");\r\n });\r\n}\r\n\r\n/**\r\n * Try the requested port; if it is busy, walk forward up to `maxAttempts`\r\n * times until a free port is found. Returns the chosen port number.\r\n */\r\nexport async function findAvailablePort(startPort: number, maxAttempts = 10): Promise<number> {\r\n for (let i = 0; i < maxAttempts; i++) {\r\n const candidate = startPort + i;\r\n if (candidate < 1 || candidate > 65535) break;\r\n // eslint-disable-next-line no-await-in-loop\r\n if (await isPortAvailable(candidate)) return candidate;\r\n }\r\n throw new Error(\r\n `No available port found in range ${startPort}-${startPort + maxAttempts - 1}. ` +\r\n `Free a port or pass --port <number>.`,\r\n );\r\n}\r\n\r\n// ─── Start server ─────────────────────────────────────────────────────────────\r\n\r\nexport function startProxy(opts: ProxyOptions & { port?: number } = {}): void {\r\n const requestedPort = opts.port ?? opts.config?.port ?? DEFAULT_CONFIG.port;\r\n const app = createProxy(opts);\r\n\r\n void (async () => {\r\n const pretenseDashboardKeyFromEnvAtLaunch = !!(process.env[\"PRETENSE_API_KEY\"]?.trim());\r\n\r\n const dashboardKey = getPretenseApiKey();\r\n\r\n if (!dashboardKey || !isValidKeyShape(dashboardKey)) {\r\n process.stderr.write(\r\n `\\x1b[31m[PRETENSE] API key required or invalid shape. Run \\`pretense login --key prtns_live_...\\`\\x1b[0m\\n` +\r\n `\\x1b[31m[PRETENSE] or set PRETENSE_API_KEY. Get a key at https://pretense.ai/dashboard/settings/api-keys\\x1b[0m\\n`,\r\n );\r\n process.exit(1);\r\n }\r\n\r\n const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\r\n\r\n // ── Backend key validation on startup ────────────────────────────────\r\n for (;;) {\r\n try {\r\n const validation = await validateKey({\r\n force: true,\r\n verbose: opts.verbose,\r\n enforceReachability: true,\r\n });\r\n if (!validation) {\r\n process.stderr.write(\r\n `\\x1b[31m[PRETENSE] Startup validation failed (no API key or unreachable backend). Cannot start proxy.\\x1b[0m\\n`,\r\n );\r\n process.exit(1);\r\n }\r\n const plan = validation.plan ?? \"FREE\";\r\n const remaining =\r\n validation.mutationsRemaining === -1 ? \"unlimited\" : String(validation.mutationsRemaining);\r\n process.stdout.write(\r\n `\\x1b[32m[PRETENSE] Key validated: ${plan} plan` +\r\n (validation.organizationName ? ` (${validation.organizationName})` : \"\") +\r\n ` — ${remaining} mutations remaining\\x1b[0m\\n`,\r\n );\r\n break;\r\n } catch (err) {\r\n const code = (err as Error & { code?: string }).code;\r\n const msg = (err as Error).message;\r\n\r\n if (code === \"BACKEND_UNAVAILABLE\" || code === \"AUTH_BACKEND_REJECTED\") {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETENSE] Fix network or set PRETENSE_API_URL if using a custom API.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n if (code === \"ORG_INACTIVE\") {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETENSE] Your organization is inactive; contact support.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n const authRetryable =\r\n code === \"INVALID_API_KEY\" ||\r\n code === \"KEY_REVOKED\" ||\r\n code === \"KEY_EXPIRED\" ||\r\n code === \"AUTH_ERROR\" ||\r\n code === \"MISSING_API_KEY\";\r\n\r\n if (authRetryable && interactive) {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(\r\n `\\x1b[33m[PRETENSE] Enter your Pretense dashboard API key and press Enter (Ctrl+C to quit).\\x1b[0m\\n`,\r\n );\r\n let entered: string | null = null;\r\n for (;;) {\r\n entered = await promptDashboardApiKeyAfterFailure();\r\n if (!entered) {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] No key entered; exiting.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n if (isValidKeyShape(entered)) break;\r\n process.stderr.write(\r\n `\\x1b[31m[PRETENSE] That does not look like a Pretense dashboard key (expect prtns_live_… or pk_live_…).\\x1b[0m\\n`,\r\n );\r\n }\r\n const savedPath = installDashboardKeyForCurrentProcess(entered);\r\n process.stdout.write(`\\x1b[32m[PRETENSE] Saved API key to ${savedPath}\\x1b[0m\\n`);\r\n clearValidationCache();\r\n continue;\r\n }\r\n\r\n if (\r\n code === \"KEY_REVOKED\" ||\r\n code === \"KEY_EXPIRED\" ||\r\n code === \"INVALID_API_KEY\" ||\r\n code === \"AUTH_ERROR\" ||\r\n code === \"MISSING_API_KEY\"\r\n ) {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETENSE] Run 'pretense login --key <new-key>' to fix.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETENSE] Run 'pretense login --key <new-key>' or check connectivity.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n attachDashboardLogoutWatcher(!pretenseDashboardKeyFromEnvAtLaunch);\r\n\r\n const bannerTier: LicenseTier = tierFromDashboardPlan(\r\n getCachedValidation()?.plan,\r\n detectTier(),\r\n );\r\n\r\n let port: number;\r\n try {\r\n port = await findAvailablePort(requestedPort, 10);\r\n } catch (err) {\r\n process.stderr.write(`\\x1b[31m[PRETENSE] ${(err as Error).message}\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n if (port !== requestedPort) {\r\n process.stderr.write(\r\n `\\x1b[33m[PRETENSE] Port ${requestedPort} in use, falling back to ${port}.\\x1b[0m\\n`,\r\n );\r\n }\r\n\r\n printStartClientInstructions(port);\r\n\r\n serve({ fetch: app.fetch, port }, () => {\r\n const portStr = String(port);\r\n process.stdout.write(`\r\n\\x1b[36mPretense v${getCliSemver()} [${bannerTier.toUpperCase()}]\\x1b[0m\r\n Your code hits AI naked. We fix that.\r\n\r\n Proxy: http://localhost:${portStr}\r\n Health: http://localhost:${portStr}/health\r\n Stats: http://localhost:${portStr}/stats\r\n\r\n Drop-in env vars:\r\n ANTHROPIC_BASE_URL=http://localhost:${portStr}\r\n OPENAI_BASE_URL=http://localhost:${portStr}/v1\r\n GEMINI_BASE_URL=http://localhost:${portStr}/v1beta\r\n OLLAMA_HOST=http://localhost:${portStr}\r\n\r\n Routes intercepted:\r\n /v1/messages -> Anthropic (Claude Code, SDK)\r\n /v1/chat/completions -> OpenAI (ChatGPT, Cursor)\r\n /v1/responses -> OpenAI (Codex CLI)\r\n /v1beta/... -> Google Gemini\r\n /api/chat, /api/generate -> Ollama (local)\r\n`);\r\n // Periodic revalidation every 60s to catch revocation/limit changes.\r\n setInterval(() => {\r\n if (dashboardSavedCredentialsRevoked) return;\r\n if (!getPretenseApiKey()) return;\r\n void validateKey({\r\n force: true,\r\n verbose: opts.verbose,\r\n enforceReachability: true,\r\n }).catch(() => {});\r\n }, 60_000);\r\n });\r\n })();\r\n}\r\n","/**\r\n * Pretense CLI — Proxy Authentication\r\n *\r\n * Extracts API keys from incoming requests and enforces presence on all\r\n * non-public routes. The hash of each API key is used as an isolation\r\n * key for per-session mutation maps (see session-store.ts), so two\r\n * different API keys can never read or write each other's token map.\r\n */\r\n\r\nimport { createHash } from \"node:crypto\";\r\nimport type { Context, MiddlewareHandler } from \"hono\";\r\n\r\nconst AUTH_HEADERS = [\"authorization\", \"x-api-key\", \"x-goog-api-key\"] as const;\r\n\r\n/**\r\n * Public routes that do NOT require an API key. Used for health checks,\r\n * welcome page, stats/audit dashboards, and any local introspection routes.\r\n */\r\nconst PUBLIC_PATHS = new Set<string>([\r\n \"/\",\r\n \"/health\",\r\n \"/stats\",\r\n \"/audit\",\r\n \"/tokens\",\r\n]);\r\n\r\n/**\r\n * Pull the API key out of the first matching auth header.\r\n * Strips optional \"Bearer \" prefix for Authorization headers.\r\n */\r\nexport function extractApiKey(c: Context): string | null {\r\n for (const h of AUTH_HEADERS) {\r\n const v = c.req.header(h);\r\n if (v && v.length > 0) {\r\n return v.replace(/^Bearer\\s+/i, \"\").trim();\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Deterministic short hash of an API key, safe to use as a map key.\r\n * Uses sha256 truncated to 16 hex chars (64 bits) — plenty for isolation\r\n * without leaking the full key.\r\n */\r\nexport function sessionHash(apiKey: string): string {\r\n return createHash(\"sha256\").update(apiKey).digest(\"hex\").slice(0, 16);\r\n}\r\n\r\n/**\r\n * Hono middleware that:\r\n * 1. Lets public routes through untouched.\r\n * 2. Rejects protected routes missing an API key with HTTP 401 + JSON.\r\n * 3. Stores the session hash in the request context for downstream handlers.\r\n */\r\nexport const requireApiKey: MiddlewareHandler = async (c, next) => {\r\n if (PUBLIC_PATHS.has(c.req.path)) {\r\n return next();\r\n }\r\n const key = extractApiKey(c);\r\n if (!key) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"missing_api_key\",\r\n message:\r\n \"Authorization header required (Authorization, x-api-key, or x-goog-api-key)\",\r\n },\r\n },\r\n 401,\r\n );\r\n }\r\n c.set(\"sessionHash\", sessionHash(key));\r\n return next();\r\n};\r\n","/**\r\n * Pretense CLI — Per-Session Token Maps\r\n *\r\n * Keyed by sha256(API key) so two different API keys can never share\r\n * mutation map state. Each SessionState holds the forward + reverse\r\n * mutation maps used by the proxy to translate identifiers into\r\n * synthetic tokens (PretenseMut/pretense_mut markers) before the\r\n * request is forwarded upstream, and to reverse them on the response.\r\n */\r\n\r\nexport interface SessionState {\r\n /** original identifier -> transformed synthetic */\r\n mutationMap: Map<string, string>;\r\n /** transformed synthetic -> original identifier (used on response) */\r\n reverseMap: Map<string, string>;\r\n /** unix epoch ms the session was first created */\r\n createdAt: number;\r\n /** unix epoch ms of most recent activity (used for sweeping) */\r\n lastUsed: number;\r\n}\r\n\r\nconst sessions = new Map<string, SessionState>();\r\n\r\n/**\r\n * Fetch (or lazily create) the session associated with an API key hash.\r\n * Updates lastUsed on every access so idle sessions can be swept later.\r\n */\r\nexport function getSession(hash: string): SessionState {\r\n let s = sessions.get(hash);\r\n if (!s) {\r\n s = {\r\n mutationMap: new Map(),\r\n reverseMap: new Map(),\r\n createdAt: Date.now(),\r\n lastUsed: Date.now(),\r\n };\r\n sessions.set(hash, s);\r\n }\r\n s.lastUsed = Date.now();\r\n return s;\r\n}\r\n\r\n/** Number of active sessions. Exposed for /stats + tests. */\r\nexport function sessionCount(): number {\r\n return sessions.size;\r\n}\r\n\r\n/**\r\n * Clear every tracked session. Only used by tests so state does not\r\n * bleed between test cases.\r\n */\r\nexport function clearSessions(): void {\r\n sessions.clear();\r\n}\r\n\r\n/**\r\n * Remove sessions whose lastUsed is older than `maxAgeMs`. Returns the\r\n * number of sessions removed. Called on a timer by the long-lived proxy\r\n * process to bound memory growth.\r\n */\r\nexport function sweepSessions(maxAgeMs: number): number {\r\n const cutoff = Date.now() - maxAgeMs;\r\n let removed = 0;\r\n for (const [hash, s] of sessions.entries()) {\r\n if (s.lastUsed < cutoff) {\r\n sessions.delete(hash);\r\n removed++;\r\n }\r\n }\r\n return removed;\r\n}\r\n","/**\r\n * Pretense CLI — Git Context Collector\r\n *\r\n * Shells out to `git` to collect repo attribution metadata (remote URL,\r\n * branch, commit SHA) for POST to `/api/cli/log`. Every field is\r\n * optional: outside a git repo — or if `git` isn't installed — every\r\n * call returns an empty object and NEVER throws.\r\n *\r\n * The API side tolerates missing fields (see\r\n * `apps/web/src/app/api/cli/log/route.ts` — all three default to null),\r\n * so the CLI is free to skip collection without breaking logging.\r\n */\r\n\r\nimport { execFile } from \"node:child_process\";\r\nimport { promisify } from \"node:util\";\r\n\r\nconst execFileAsync = promisify(execFile);\r\n\r\n/**\r\n * Attribution metadata posted alongside every mutation log. All fields\r\n * optional — absent when the CLI is run outside a git repo or when\r\n * individual git commands fail (detached HEAD, no origin remote, etc.).\r\n */\r\nexport interface GitContext {\r\n git_remote?: string;\r\n git_branch?: string;\r\n git_commit_sha?: string;\r\n}\r\n\r\n/** Per-git-invocation timeout. Git should answer in milliseconds; 2s\r\n * is a generous upper bound that also caps worst-case hangs on\r\n * misconfigured remotes / filesystem stalls. */\r\nconst GIT_TIMEOUT_MS = 2000;\r\n\r\nasync function runGit(args: string[], cwd: string): Promise<string | undefined> {\r\n try {\r\n const { stdout } = await execFileAsync(\"git\", args, {\r\n cwd,\r\n timeout: GIT_TIMEOUT_MS,\r\n windowsHide: true,\r\n });\r\n const trimmed = stdout.trim();\r\n return trimmed.length > 0 ? trimmed : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Strip credentials from a remote URL so we never upload a PAT embedded\r\n * in `https://<token>@github.com/...`. Returns the input unchanged if it\r\n * doesn't parse as a URL — git also accepts scp-style `git@host:repo`,\r\n * which is safe to pass through verbatim.\r\n */\r\nexport function sanitizeRemote(raw: string): string {\r\n // scp-style SSH: `git@github.com:owner/repo.git`. No credentials\r\n // possible in that form.\r\n if (/^[\\w.-]+@[^:]+:/.test(raw) && !raw.includes(\"://\")) {\r\n return raw;\r\n }\r\n try {\r\n const url = new URL(raw);\r\n url.username = \"\";\r\n url.password = \"\";\r\n return url.toString();\r\n } catch {\r\n return raw;\r\n }\r\n}\r\n\r\n/**\r\n * Collect git repo metadata for attribution on `/api/cli/log`.\r\n *\r\n * Guarantees:\r\n * - Never throws. Failures return `{}` or partial context.\r\n * - Never blocks longer than ~3×GIT_TIMEOUT_MS.\r\n * - Strips credentials from HTTPS remote URLs.\r\n *\r\n * @param cwd working directory (defaults to process.cwd())\r\n */\r\nexport async function collectGitContext(cwd: string = process.cwd()): Promise<GitContext> {\r\n // Fast-fail when we're not inside a git worktree. This avoids three\r\n // stderr-spamming invocations on every proxy request in a non-repo\r\n // scratch dir.\r\n const insideRepo = await runGit([\"rev-parse\", \"--is-inside-work-tree\"], cwd);\r\n if (insideRepo !== \"true\") return {};\r\n\r\n const [remote, branch, sha] = await Promise.all([\r\n runGit([\"remote\", \"get-url\", \"origin\"], cwd),\r\n runGit([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], cwd),\r\n runGit([\"rev-parse\", \"HEAD\"], cwd),\r\n ]);\r\n\r\n const ctx: GitContext = {};\r\n if (remote) ctx.git_remote = sanitizeRemote(remote);\r\n // `rev-parse --abbrev-ref HEAD` returns `HEAD` in detached mode —\r\n // not useful, skip it.\r\n if (branch && branch !== \"HEAD\") ctx.git_branch = branch;\r\n if (sha) ctx.git_commit_sha = sha;\r\n return ctx;\r\n}\r\n\r\n// ─── Cache ───────────────────────────────────────────────────────────────────\r\n// The proxy calls uploadLog on every LLM request; shelling out to git\r\n// three times per request is wasted I/O. 30s TTL is short enough to\r\n// pick up a branch switch / new commit mid-session, long enough to\r\n// collapse a burst of requests to a single git read.\r\n\r\ninterface CacheEntry {\r\n value: GitContext;\r\n expiresAt: number;\r\n}\r\n\r\nconst CACHE_TTL_MS = 30_000;\r\nconst cache = new Map<string, CacheEntry>();\r\n\r\nexport async function collectGitContextCached(\r\n cwd: string = process.cwd(),\r\n now: number = Date.now(),\r\n): Promise<GitContext> {\r\n const hit = cache.get(cwd);\r\n if (hit && hit.expiresAt > now) return hit.value;\r\n const value = await collectGitContext(cwd);\r\n cache.set(cwd, { value, expiresAt: now + CACHE_TTL_MS });\r\n return value;\r\n}\r\n\r\n/** Test hook — clear the git-context cache. */\r\nexport function _resetGitContextCache(): void {\r\n cache.clear();\r\n}\r\n","/**\r\n * `pretense login` — store an API key in the user-level config so future\r\n * CLI runs can authenticate against pretense.ai without re-entering it.\r\n *\r\n * Inputs (in priority order):\r\n * 1. --key <plaintext> explicit flag\r\n * 2. PRETENSE_API_KEY env var one-shot use\r\n * 3. stdin (if piped) scripted use, e.g. `echo $KEY | pretense login`\r\n *\r\n * Storage: ~/.pretense/config.json with `{ api_key, saved_at }`. File is\r\n * created with mode 0o600 so other users on the host cannot read it.\r\n *\r\n * Validation: prefix must be `pk_live_` or `ptns_live_` (legacy). The\r\n * payload must be 16 chars or longer. We never call the network here —\r\n * a wrong key just fails on the next CLI run with a clear error message.\r\n */\r\n\r\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, chmodSync, readSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport readline from \"node:readline/promises\";\r\nimport chalk from \"chalk\";\r\n\r\nconst CONFIG_DIR_NAME = \".pretense\";\r\nconst CONFIG_FILE = \"config.json\";\r\n\r\ninterface LoginConfig {\r\n api_key: string;\r\n saved_at: string;\r\n}\r\n\r\nexport function getUserDashboardConfigDir(): string {\r\n return join(homedir(), CONFIG_DIR_NAME);\r\n}\r\n\r\nexport function getUserDashboardConfigPath(): string {\r\n return join(getUserDashboardConfigDir(), CONFIG_FILE);\r\n}\r\n\r\n/** Validate the visible shape of a key. Network call happens later. */\r\nexport function isValidKeyShape(key: string): boolean {\r\n const trimmed = key.trim();\r\n if (trimmed.length < 24) return false;\r\n if (!/^[A-Za-z0-9_]+$/.test(trimmed)) return false;\r\n return (\r\n trimmed.startsWith(\"pk_live_\") ||\r\n trimmed.startsWith(\"ptns_live_\") ||\r\n trimmed.startsWith(\"prtns_live_\")\r\n );\r\n}\r\n\r\n/**\r\n * Read up to 4KB of stdin synchronously. Returns \"\" if stdin is a TTY\r\n * (i.e. nothing was piped in). Used so `echo $KEY | pretense login` works.\r\n */\r\nfunction readStdinIfPiped(): string {\r\n if (process.stdin.isTTY) return \"\";\r\n try {\r\n const chunks: Buffer[] = [];\r\n const buf = Buffer.alloc(4096);\r\n let bytesRead = 0;\r\n do {\r\n try {\r\n bytesRead = readSync(0, buf, 0, buf.length, null);\r\n } catch {\r\n // EAGAIN on some platforms — bail cleanly\r\n bytesRead = 0;\r\n }\r\n if (bytesRead > 0) chunks.push(Buffer.from(buf.subarray(0, bytesRead)));\r\n } while (bytesRead === buf.length);\r\n return Buffer.concat(chunks).toString(\"utf-8\").trim();\r\n } catch {\r\n return \"\";\r\n }\r\n}\r\n\r\nfunction maskKey(key: string): string {\r\n const trimmed = key.trim();\r\n if (trimmed.length <= 12) return trimmed;\r\n return `${trimmed.slice(0, 12)}${\"•\".repeat(8)}${trimmed.slice(-4)}`;\r\n}\r\n\r\n/** Helps explain logout/env vs ~/.pretense mismatches when troubleshooting start. */\r\nexport function logDashboardCredentialHint(): void {\r\n const env = process.env[\"PRETENSE_API_KEY\"]?.trim() ?? \"\";\r\n const envOk = env.length > 0 && isValidKeyShape(env);\r\n const abs = getUserDashboardConfigPath();\r\n const fk = loadApiKey();\r\n\r\n if (envOk) {\r\n console.error(\r\n chalk.gray(\r\n `[pretense] Dashboard key source: PRETENSE_API_KEY in environment (${maskKey(env)}) — ` +\r\n `unset this variable after logout if you expect no key.`,\r\n ),\r\n );\r\n } else if (fk && isValidKeyShape(fk)) {\r\n console.error(chalk.gray(`[pretense] Dashboard key source: ${abs} (${maskKey(fk)})`));\r\n } else {\r\n console.error(chalk.gray(\"[pretense] Dashboard key source: none configured.\"));\r\n }\r\n}\r\n\r\n/**\r\n * Persist the api key. Returns the path written.\r\n */\r\nexport function saveApiKey(key: string, configDir: string = getUserDashboardConfigDir()): string {\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n const path = join(configDir, CONFIG_FILE);\r\n\r\n // Merge with any existing config so we don't clobber unrelated fields.\r\n let existing: Record<string, unknown> = {};\r\n if (existsSync(path)) {\r\n try {\r\n existing = JSON.parse(readFileSync(path, \"utf-8\")) as Record<string, unknown>;\r\n } catch {\r\n existing = {};\r\n }\r\n }\r\n const next: Record<string, unknown> = {\r\n ...existing,\r\n api_key: key.trim(),\r\n saved_at: new Date().toISOString(),\r\n };\r\n writeFileSync(path, JSON.stringify(next, null, 2), { encoding: \"utf-8\", mode: 0o600 });\r\n try {\r\n chmodSync(path, 0o600);\r\n } catch {\r\n // Windows / sandboxed filesystems may reject — non-fatal.\r\n }\r\n return path;\r\n}\r\n\r\n/** Remove `api_key` and `saved_at` from user config; preserves other JSON fields. */\r\nexport function removeSavedDashboardCredentials(configDir: string = getUserDashboardConfigDir()): {\r\n removed: boolean;\r\n path: string;\r\n} {\r\n const path = join(configDir, CONFIG_FILE);\r\n if (!existsSync(path)) return { removed: false, path };\r\n let existing: Record<string, unknown> = {};\r\n try {\r\n existing = JSON.parse(readFileSync(path, \"utf-8\")) as Record<string, unknown>;\r\n } catch {\r\n return { removed: false, path };\r\n }\r\n const ak = existing.api_key;\r\n const hadKey = typeof ak === \"string\" && ak.trim().length > 0;\r\n if (!hadKey) return { removed: false, path };\r\n\r\n delete existing.api_key;\r\n delete existing.saved_at;\r\n writeFileSync(path, JSON.stringify(existing, null, 2), { encoding: \"utf-8\", mode: 0o600 });\r\n try {\r\n chmodSync(path, 0o600);\r\n } catch {\r\n /* ignore */\r\n }\r\n return { removed: true, path };\r\n}\r\n\r\n/**\r\n * Load the saved api key, if any. Used by other CLI commands that need to\r\n * authenticate against pretense.ai.\r\n */\r\nexport function loadApiKey(configDir: string = getUserDashboardConfigDir()): string | null {\r\n const path = join(configDir, CONFIG_FILE);\r\n if (!existsSync(path)) return null;\r\n try {\r\n const raw = readFileSync(path, \"utf-8\");\r\n const parsed = JSON.parse(raw) as Partial<LoginConfig>;\r\n if (typeof parsed.api_key === \"string\") {\r\n const t = parsed.api_key.trim();\r\n if (t.length > 0) return t;\r\n }\r\n } catch {\r\n /* ignore */\r\n }\r\n return null;\r\n}\r\n\r\ninterface RunLoginOptions {\r\n key?: string;\r\n configDir?: string;\r\n}\r\n\r\n/**\r\n * Resolve a dashboard API key from `$PRETENSE_API_KEY` or `~/.pretense/config.json`.\r\n * Keys in the file that fail `isValidKeyShape` are ignored so the user can be re-prompted.\r\n */\r\nexport function resolveDashboardKeyCandidate(): {\r\n key: string | null;\r\n fromFile: boolean;\r\n /** `$PRETENSE_API_KEY` is non-empty but fails shape checks */\r\n badEnv: boolean;\r\n} {\r\n const env = (process.env[\"PRETENSE_API_KEY\"] ?? \"\").trim();\r\n if (env.length > 0) {\r\n if (!isValidKeyShape(env)) {\r\n return { key: null, fromFile: false, badEnv: true };\r\n }\r\n return { key: env, fromFile: false, badEnv: false };\r\n }\r\n const fileKey = loadApiKey();\r\n if (fileKey && isValidKeyShape(fileKey)) {\r\n return { key: fileKey.trim(), fromFile: true, badEnv: false };\r\n }\r\n return { key: null, fromFile: Boolean(fileKey), badEnv: false };\r\n}\r\n\r\n/** Save key to ~/.pretense/config.json and make this process use it (overrides stale $PRETENSE_API_KEY). */\r\nexport function installDashboardKeyForCurrentProcess(key: string): string {\r\n const trimmed = key.trim();\r\n const path = saveApiKey(trimmed);\r\n process.env[\"PRETENSE_API_KEY\"] = trimmed;\r\n return path;\r\n}\r\n\r\n/**\r\n * Prompt for dashboard API key after validation failure (TTY only).\r\n * Returns null if stdin is not interactive or the user submits an empty line.\r\n */\r\nexport async function promptDashboardApiKeyAfterFailure(): Promise<string | null> {\r\n if (!process.stdin.isTTY || !process.stdout.isTTY) return null;\r\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\r\n try {\r\n const line = (await rl.question(chalk.bold(\"Pretense dashboard API key: \"))).trim();\r\n return line.length > 0 ? line : null;\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\n/**\r\n * Before `pretense start`: ensure a dashboard API key exists (env, saved config, or TTY prompt).\r\n * Does not call the network — `startProxy` validates with the backend.\r\n */\r\nexport async function ensureDashboardKeyForStart(): Promise<void> {\r\n const { key, fromFile, badEnv } = resolveDashboardKeyCandidate();\r\n if (badEnv) {\r\n console.error(chalk.red(\"Error: PRETENSE_API_KEY is set but is not a valid Pretense dashboard API key shape.\"));\r\n console.error(\r\n chalk.gray(\"Keys look like prtns_live_… or pk_live_…. Fix the variable or unset it to use ~/.pretense/config.json.\"),\r\n );\r\n process.exit(1);\r\n }\r\n if (key) {\r\n return;\r\n }\r\n\r\n if (fromFile) {\r\n console.warn(\r\n chalk.yellow(\r\n \"Ignoring invalid `api_key` in ~/.pretense/config.json (wrong shape). Enter a new key or run `pretense login --key ...`.\",\r\n ),\r\n );\r\n }\r\n\r\n const stdinOk = process.stdin.isTTY;\r\n const stdoutOk = process.stdout.isTTY;\r\n if (!stdinOk || !stdoutOk) {\r\n console.error(chalk.red(\"Error: Pretense API key required to start the proxy.\"));\r\n console.error(\r\n chalk.gray(\r\n \"Save one with `pretense login --key prtns_live_...` or set PRETENSE_API_KEY.\",\r\n ),\r\n );\r\n process.exit(1);\r\n }\r\n\r\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\r\n try {\r\n console.log(chalk.cyan(\"No Pretense API key found in ~/.pretense/config.json or $PRETENSE_API_KEY.\"));\r\n const entered = (await rl.question(chalk.bold(\"Enter your Pretense API key: \"))).trim();\r\n if (!entered) {\r\n console.error(chalk.red(\"No key entered; exiting.\"));\r\n process.exit(1);\r\n }\r\n if (!isValidKeyShape(entered)) {\r\n console.error(chalk.red(\"That does not look like a Pretense API key (expect prtns_live_… or pk_live_…).\"));\r\n console.error(chalk.gray(\"Get one from your Pretense dashboard, then run `pretense login --key ...`.\"));\r\n process.exit(1);\r\n }\r\n const path = installDashboardKeyForCurrentProcess(entered);\r\n console.log(chalk.green(\"Saved API key to\"), chalk.bold(path));\r\n console.log(chalk.gray(` ${maskKey(entered)}`));\r\n } finally {\r\n rl.close();\r\n }\r\n\r\n const persisted = resolveDashboardKeyCandidate();\r\n if (!persisted.key || persisted.badEnv) {\r\n console.error(chalk.red(\"Error: Pretense dashboard API key could not be confirmed after login prompt.\"));\r\n process.exit(1);\r\n }\r\n}\r\n\r\nexport function runLogin(opts: RunLoginOptions = {}): number {\r\n const candidate =\r\n opts.key?.trim() ||\r\n (process.env[\"PRETENSE_API_KEY\"] ?? \"\").trim() ||\r\n readStdinIfPiped();\r\n\r\n if (!candidate) {\r\n console.error(chalk.red(\"Error: no API key provided.\"));\r\n console.error(\r\n chalk.gray(\"Try: pretense login --key pk_live_xxxxx\"),\r\n );\r\n console.error(\r\n chalk.gray(\" or: echo $PRETENSE_API_KEY | pretense login\"),\r\n );\r\n return 1;\r\n }\r\n\r\n if (!isValidKeyShape(candidate)) {\r\n console.error(chalk.red(\"Error: that does not look like a Pretense API key.\"));\r\n console.error(\r\n chalk.gray(\"Keys start with prtns_live_ (or pk_live_) and are at least 24 characters long.\"),\r\n );\r\n console.error(\r\n chalk.gray(\"Get one at https://pretense.ai/dashboard/settings/api-keys\"),\r\n );\r\n return 1;\r\n }\r\n\r\n const path = saveApiKey(candidate, opts.configDir);\r\n console.log(chalk.green(\"Saved API key to\"), chalk.bold(path));\r\n console.log(chalk.gray(` ${maskKey(candidate)}`));\r\n console.log(chalk.gray(\" File mode 600 — readable only by you.\"));\r\n return 0;\r\n}\r\n","/**\r\n * Pretense CLI — Backend API Client\r\n *\r\n * Thin HTTP client for the Pretense backend `/api/cli/*` endpoints.\r\n * Handles key validation, usage reporting, and limit checks with\r\n * caching so the hot proxy path stays fast.\r\n */\r\n\r\nimport { loadApiKey } from \"./commands/login.js\";\r\n\r\n// ─── Types mirroring backend DTOs ────────────────────────────────────────────\r\n\r\nexport interface ValidateResponse {\r\n valid: boolean;\r\n keyId: string;\r\n permission: \"read_write\" | \"read_only\";\r\n organizationId: string | null;\r\n organizationName: string | null;\r\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\";\r\n monthlyMutationLimit: number;\r\n mutationsUsed: number;\r\n mutationsRemaining: number;\r\n periodResetsAt: string;\r\n}\r\n\r\nexport interface UsageSummary {\r\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\";\r\n monthlyMutationLimit: number;\r\n mutationsUsed: number;\r\n mutationsRemaining: number;\r\n requestsThisPeriod: number;\r\n secretsBlockedThisPeriod: number;\r\n periodResetsAt: string;\r\n keyExpiresAt: string | null;\r\n keyStatus: \"active\" | \"revoked\";\r\n}\r\n\r\n/** When GET /usage/summary fails, reuse validate payload for status display. */\r\nexport function usageSummaryFromValidate(v: ValidateResponse): UsageSummary {\r\n return {\r\n plan: v.plan,\r\n monthlyMutationLimit: v.monthlyMutationLimit,\r\n mutationsUsed: v.mutationsUsed,\r\n mutationsRemaining: v.mutationsRemaining,\r\n requestsThisPeriod: 0,\r\n secretsBlockedThisPeriod: 0,\r\n periodResetsAt: v.periodResetsAt,\r\n keyExpiresAt: null,\r\n keyStatus: \"active\",\r\n };\r\n}\r\n\r\n// ─── Configuration ───────────────────────────────────────────────────────────\r\n\r\nconst DEFAULT_PRETENSE_API_URL = \"https://api.pretense.ai\";\r\nconst DEFAULT_REQUEST_TIMEOUT_MS = 15_000;\r\n\r\n/**\r\n * Resolves the API root from `PRETENSE_API_URL`.\r\n * Supports a path prefix, e.g. `https://api.example.com/staging` →\r\n * `https://api.example.com/staging/api/cli/auth/validate` (not double `/api`).\r\n *\r\n * Legacy: `https://pretense.ai` (marketing site) has no `/api/cli/*`; map host to\r\n * `https://api.pretense.ai` while keeping any path prefix.\r\n */\r\nexport function getConfiguredApiRoot(rootOverride?: string): string {\r\n const raw = (\r\n rootOverride ??\r\n process.env[\"PRETENSE_API_URL\"] ??\r\n DEFAULT_PRETENSE_API_URL\r\n ).trim();\r\n if (!raw) {\r\n return DEFAULT_PRETENSE_API_URL.replace(/\\/$/, \"\");\r\n }\r\n let normalized = raw;\r\n if (!/^https?:\\/\\//i.test(normalized)) {\r\n normalized = `https://${normalized}`;\r\n }\r\n try {\r\n const u = new URL(normalized);\r\n const origin =\r\n /^pretense\\.ai$/i.test(u.hostname)\r\n ? \"https://api.pretense.ai\"\r\n : u.origin;\r\n const path = u.pathname === \"/\" ? \"\" : u.pathname.replace(/\\/$/, \"\");\r\n return `${origin}${path}`;\r\n } catch {\r\n return DEFAULT_PRETENSE_API_URL.replace(/\\/$/, \"\");\r\n }\r\n}\r\n\r\n/**\r\n * Full URL for a Pretense CLI HTTP route (`auth/validate`, `log`, `usage/summary`).\r\n * @param pathWithinCli - segment after `/api/cli/` e.g. `auth/validate`\r\n */\r\nexport function getCliApiUrl(\r\n pathWithinCli: string,\r\n rootOverride?: string,\r\n): string {\r\n const root = getConfiguredApiRoot(rootOverride);\r\n const tail = pathWithinCli.replace(/^\\/+/, \"\");\r\n return `${root}/api/cli/${tail}`;\r\n}\r\n\r\nexport function getApiRequestTimeoutMs(): number {\r\n const raw = process.env[\"PRETENSE_API_TIMEOUT_MS\"]?.trim();\r\n if (!raw || !/^\\d+$/.test(raw)) return DEFAULT_REQUEST_TIMEOUT_MS;\r\n const n = parseInt(raw, 10);\r\n return Math.min(Math.max(n, 3_000), 120_000);\r\n}\r\n\r\nfunction getApiKey(): string | null {\r\n const fromEnv = process.env[\"PRETENSE_API_KEY\"]?.trim();\r\n if (fromEnv) return fromEnv;\r\n const fromFile = loadApiKey();\r\n if (!fromFile) return null;\r\n const t = fromFile.trim();\r\n return t.length > 0 ? t : null;\r\n}\r\n\r\n/** Pretense dashboard API key for `/api/cli/*` — NOT the upstream LLM provider key. */\r\nexport function getPretenseApiKey(): string | null {\r\n return getApiKey();\r\n}\r\n\r\n// ─── Cached validation state ─────────────────────────────────────────────────\r\n\r\nlet cachedValidation: ValidateResponse | null = null;\r\n/** Last time we successfully refreshed `cachedValidation` from `/api/cli/auth/validate`. */\r\nlet lastValidationSuccessAt = 0;\r\n\r\n/** Re-fetch plan/quota from the backend when the cache is older than this (hot path). */\r\nconst VALIDATION_CACHE_FRESH_MS = 45_000;\r\n\r\nexport function getCachedValidation(): ValidateResponse | null {\r\n return cachedValidation;\r\n}\r\n\r\nexport function clearValidationCache(): void {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n}\r\n\r\n/**\r\n * After recording usage locally, adjust cached quota so `isWithinLimits()`\r\n * stays accurate without clearing the cache or refetching every request.\r\n */\r\nexport function bumpCachedUsageAfterLog(identifiersMutated: number): void {\r\n if (!cachedValidation || identifiersMutated <= 0) return;\r\n cachedValidation.mutationsUsed += identifiersMutated;\r\n if (cachedValidation.mutationsRemaining !== -1) {\r\n cachedValidation.mutationsRemaining = Math.max(\r\n 0,\r\n cachedValidation.mutationsRemaining - identifiersMutated,\r\n );\r\n }\r\n}\r\n\r\n// ─── API calls ───────────────────────────────────────────────────────────────\r\n\r\nfunction makeBackendReachabilityError(\r\n code: \"BACKEND_UNAVAILABLE\" | \"AUTH_BACKEND_REJECTED\",\r\n message: string,\r\n): Error & { code: string } {\r\n const err = new Error(message) as Error & { code: string };\r\n err.code = code;\r\n return err;\r\n}\r\n\r\n/**\r\n * Validate the API key against the backend. Caches the result for\r\n * CACHE_TTL_MS so repeated proxy requests don't hammer the server.\r\n *\r\n * Returns null if the backend is unreachable (offline/degraded mode)\r\n * **only when** `enforceReachability` is false (e.g. `status` / `credits`).\r\n *\r\n * When `enforceReachability` is true (proxy with a configured dashboard key),\r\n * network errors and non-OK HTTP responses reject so the proxy cannot run\r\n * against an unverified or bogus key.\r\n *\r\n * Throws on auth errors (401/403, valid: false) so callers can surface\r\n * actionable messages.\r\n */\r\nexport async function validateKey(\r\n opts: {\r\n force?: boolean;\r\n verbose?: boolean;\r\n enforceReachability?: boolean;\r\n } = {},\r\n): Promise<ValidateResponse | null> {\r\n const enforceReachability = opts.enforceReachability === true;\r\n const now = Date.now();\r\n const cacheFresh =\r\n cachedValidation !== null &&\r\n now - lastValidationSuccessAt < VALIDATION_CACHE_FRESH_MS;\r\n if (!opts.force && cacheFresh) {\r\n return cachedValidation;\r\n }\r\n\r\n const validateUrl = getCliApiUrl(\"auth/validate\");\r\n const timeoutMs = getApiRequestTimeoutMs();\r\n const apiKey = getApiKey();\r\n if (!apiKey) {\r\n if (enforceReachability) {\r\n const err = new Error(\"Missing Pretense dashboard API key\") as Error & {\r\n code: string;\r\n };\r\n err.code = \"MISSING_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n return null;\r\n }\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n try {\r\n const resp = await fetch(validateUrl, {\r\n method: \"POST\",\r\n headers: {\r\n \"content-type\": \"application/json\",\r\n authorization: `Bearer ${apiKey}`,\r\n },\r\n body: \"{}\",\r\n signal: controller.signal,\r\n });\r\n\r\n if (resp.status === 401 || resp.status === 403) {\r\n const raw = (await resp.json().catch(() => ({}))) as Record<\r\n string,\r\n unknown\r\n >;\r\n const msg =\r\n typeof raw.message === \"string\"\r\n ? raw.message\r\n : \"API key rejected by server\";\r\n const err = new Error(msg) as Error & { code: string };\r\n err.code = typeof raw.code === \"string\" ? raw.code : \"INVALID_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n\r\n if (!resp.ok) {\r\n const msg = `Pretense API returned HTTP ${resp.status} from ${validateUrl}`;\r\n if (enforceReachability) {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\"AUTH_BACKEND_REJECTED\", msg);\r\n }\r\n return null;\r\n }\r\n\r\n let data: ValidateResponse;\r\n try {\r\n data = (await resp.json()) as ValidateResponse;\r\n } catch {\r\n if (enforceReachability) {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\r\n \"AUTH_BACKEND_REJECTED\",\r\n `Invalid JSON from ${validateUrl}`,\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n if (typeof data.valid === \"boolean\" && data.valid === false) {\r\n const err = new Error(\"API key is not valid\") as Error & { code: string };\r\n err.code = \"INVALID_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n\r\n cachedValidation = data;\r\n lastValidationSuccessAt = Date.now();\r\n return data;\r\n } catch (err) {\r\n if (\r\n (err as Error & { code?: string }).code === \"KEY_REVOKED\" ||\r\n (err as Error & { code?: string }).code === \"KEY_EXPIRED\" ||\r\n (err as Error & { code?: string }).code === \"INVALID_API_KEY\" ||\r\n (err as Error & { code?: string }).code === \"AUTH_ERROR\" ||\r\n (err as Error & { code?: string }).code === \"ORG_INACTIVE\" ||\r\n (err as Error & { code?: string }).code === \"MISSING_API_KEY\" ||\r\n (err as Error & { code?: string }).code === \"BACKEND_UNAVAILABLE\" ||\r\n (err as Error & { code?: string }).code === \"AUTH_BACKEND_REJECTED\"\r\n ) {\r\n throw err;\r\n }\r\n if (enforceReachability) {\r\n const msg =\r\n (err as Error).name === \"AbortError\"\r\n ? `Timed out after ${timeoutMs}ms reaching ${validateUrl} (raise PRETENSE_API_TIMEOUT_MS)`\r\n : `Cannot reach Pretense API at ${validateUrl}: ${(err as Error).message}`;\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\"BACKEND_UNAVAILABLE\", msg);\r\n }\r\n if (opts.verbose) {\r\n process.stderr.write(\r\n `[PRETENSE] Backend validation failed: ${(err as Error).message}\\n`,\r\n );\r\n }\r\n return null;\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n\r\n/**\r\n * Fetch usage summary from the backend. Returns null on network errors.\r\n */\r\nexport async function fetchUsageSummary(\r\n opts: { verbose?: boolean } = {},\r\n): Promise<UsageSummary | null> {\r\n const summaryUrl = getCliApiUrl(\"usage/summary\");\r\n const apiKey = getApiKey();\r\n if (!apiKey) return null;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), getApiRequestTimeoutMs());\r\n\r\n try {\r\n const resp = await fetch(summaryUrl, {\r\n method: \"GET\",\r\n headers: { authorization: `Bearer ${apiKey}` },\r\n signal: controller.signal,\r\n });\r\n\r\n if (!resp.ok) return null;\r\n return (await resp.json()) as UsageSummary;\r\n } catch (err) {\r\n if (opts.verbose) {\r\n process.stderr.write(\r\n `[PRETENSE] Usage summary fetch failed: ${(err as Error).message}\\n`,\r\n );\r\n }\r\n return null;\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n\r\n/**\r\n * Check whether the current key/org is within mutation limits.\r\n * When quota is unknown (no cached validation), allow — the proxy handler\r\n * only reaches this point after validateKey(strict) succeeds for paid mode.\r\n *\r\n * When the cache shows 0 remaining, re-validates against the backend before\r\n * blocking — the local cache can drift high if fire-and-forget log uploads\r\n * failed silently (bumped cache but never reached the DB).\r\n */\r\nexport async function isWithinLimits(): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n}> {\r\n const v = getCachedValidation();\r\n if (!v) return { allowed: true };\r\n\r\n if (v.mutationsRemaining !== -1 && v.mutationsRemaining <= 0) {\r\n const fresh = await validateKey({ force: true }).catch(() => null);\r\n const check = fresh ?? v;\r\n if (check.mutationsRemaining !== -1 && check.mutationsRemaining <= 0) {\r\n return {\r\n allowed: false,\r\n reason: `Monthly mutation limit reached (${check.mutationsUsed}/${check.monthlyMutationLimit}). Upgrade at https://pretense.ai/pricing`,\r\n };\r\n }\r\n return { allowed: true };\r\n }\r\n return { allowed: true };\r\n}\r\n","/**\r\n * Pretense CLI — Log Uploader\r\n *\r\n * Fire-and-forget POST of mutation events to `/api/cli/log`. Collects\r\n * git context (remote / branch / commit SHA) automatically and merges\r\n * it into the body.\r\n *\r\n * This runs AFTER the proxy has already forwarded the LLM request, so\r\n * uploader failures MUST NEVER impact the user's request path. All\r\n * errors are swallowed (optionally logged when verbose).\r\n */\r\n\r\nimport { collectGitContextCached, type GitContext } from \"./git-context.js\";\r\nimport { getApiRequestTimeoutMs, getCliApiUrl } from \"./backend-client.js\";\r\n\r\n/** Payload matching the `/api/cli/log` route contract. All optional. */\r\nexport interface LogUploadEvent {\r\n file_count?: number;\r\n identifiers_mutated?: number;\r\n secrets_blocked?: number;\r\n llm_provider?: string;\r\n scan_tokens?: number;\r\n mutation_tokens?: number;\r\n read_tokens?: number;\r\n cli_version?: string;\r\n}\r\n\r\nexport interface LogUploadOptions {\r\n /**\r\n * Base API root (same semantics as `PRETENSE_API_URL`).\r\n * Omit to use `PRETENSE_API_URL` from the environment.\r\n */\r\n apiUrl?: string;\r\n /** API key — must match a row in `api_keys`. */\r\n apiKey: string;\r\n /** Optional override for git-context (mostly for tests). */\r\n gitContext?: GitContext;\r\n /** Working directory for git lookups (defaults to process.cwd()). */\r\n cwd?: string;\r\n /** Abort the POST after this many ms (default: `PRETENSE_API_TIMEOUT_MS` or 15s). */\r\n timeoutMs?: number;\r\n /** If true, log errors to stderr instead of silently swallowing. */\r\n verbose?: boolean;\r\n}\r\n\r\n/**\r\n * POST an event to `/api/cli/log`, merging git context into the body.\r\n * Resolves once the server returns (or the request times out / errors).\r\n * NEVER rejects — callers can `void uploadLog(...)` without a try/catch.\r\n */\r\nexport async function uploadLog(\r\n event: LogUploadEvent,\r\n options: LogUploadOptions,\r\n): Promise<void> {\r\n const apiRoot = options.apiUrl?.trim() || undefined;\r\n const endpoint = getCliApiUrl(\"log\", apiRoot);\r\n const { apiKey, verbose = false, timeoutMs = getApiRequestTimeoutMs() } = options;\r\n if (!apiKey) return;\r\n\r\n const gitCtx = options.gitContext ?? (await collectGitContextCached(options.cwd));\r\n\r\n // The API route currently accepts `repo_remote_url`, `git_branch`,\r\n // `commit_sha` (see apps/web/src/app/api/cli/log/route.ts). We also\r\n // send `git_remote` / `git_commit_sha` under their git-canonical\r\n // names as a forward-compat bridge — unknown fields are ignored\r\n // server-side. When the route migrates to the canonical names we\r\n // drop the legacy aliases in a follow-up.\r\n const body = {\r\n ...event,\r\n ...gitCtx,\r\n repo_remote_url: gitCtx.git_remote,\r\n git_branch: gitCtx.git_branch,\r\n commit_sha: gitCtx.git_commit_sha,\r\n };\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n try {\r\n const resp = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: {\r\n \"content-type\": \"application/json\",\r\n authorization: `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n signal: controller.signal,\r\n });\r\n if (!resp.ok && verbose) {\r\n process.stderr.write(`[PRETENSE] log upload HTTP ${resp.status}\\n`);\r\n }\r\n } catch (err) {\r\n if (verbose) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n process.stderr.write(`[PRETENSE] log upload failed: ${msg}\\n`);\r\n }\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n","/**\r\n * Copy/paste env hints printed after the proxy key validates.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\n\r\nexport function printStartClientInstructions(port: number): void {\r\n const host = `http://localhost:${port}`;\r\n console.log();\r\n console.log(chalk.cyan.bold(\"── Client setup (environment variables) ──\"));\r\n console.log(chalk.gray(\"Point the CLI at the Pretense backend API (optional if using default):\"));\r\n console.log(\r\n chalk.white(`export PRETENSE_API_URL='https://api.pretense.ai'`),\r\n );\r\n console.log();\r\n console.log(chalk.gray(\"Log in with your Pretense dashboard API key:\"));\r\n console.log(chalk.white(\"pretense login --key your-pretense-api-key\"));\r\n console.log();\r\n console.log(\r\n chalk.gray(\"Set the LLM base URL for your provider (proxy below):\"),\r\n );\r\n console.log(chalk.white(`export ANTHROPIC_BASE_URL=\"${host}\"`));\r\n console.log(chalk.white(`export ANTHROPIC_BASE_URL=${host}`));\r\n console.log(chalk.white(`export OPENAI_BASE_URL=${host}/v1`));\r\n console.log(chalk.white(`export GEMINI_BASE_URL=${host}/v1beta`));\r\n console.log(chalk.white(`export OLLAMA_HOST=${host}`));\r\n console.log();\r\n console.log(chalk.gray(\"Set your real upstream LLM API key (unchanged):\"));\r\n console.log(chalk.white('export ANTHROPIC_API_KEY=\"sk-ant-API-KEY\"'));\r\n console.log();\r\n console.log(chalk.cyan.bold(\"── Stop & log out ──\"));\r\n console.log(\r\n chalk.gray(\r\n \"Stop the proxy: press Ctrl+C in the terminal where pretense start is running.\",\r\n ),\r\n );\r\n console.log(\r\n chalk.gray(\r\n \"Remove the saved Pretense dashboard key from ~/.pretense/config.json:\",\r\n ),\r\n );\r\n console.log(chalk.white(\"pretense logout\"));\r\n console.log(\r\n chalk.gray(\r\n \"(confirm with y / cancel with n.) Mutations stop immediately unless this proxy was started with\",\r\n ),\r\n );\r\n console.log(\r\n chalk.gray(\r\n \"PRETENSE_API_KEY set in that same terminal — then press Ctrl+C and run pretense start again.\",\r\n ),\r\n );\r\n console.log();\r\n}\r\n","/**\r\n * Single source for CLI semver — reads adjacent package.json (works from src/ and dist/).\r\n */\r\n\r\nimport { readFileSync } from \"node:fs\";\r\nimport { fileURLToPath } from \"node:url\";\r\n\r\nlet cached: string | null = null;\r\n\r\nexport function getCliSemver(): string {\r\n if (cached !== null) return cached;\r\n try {\r\n const url = new URL(\"../package.json\", import.meta.url);\r\n const raw = readFileSync(fileURLToPath(url), \"utf-8\");\r\n cached = (JSON.parse(raw) as { version?: string }).version ?? \"0.0.0\";\r\n } catch {\r\n cached = \"0.0.0\";\r\n }\r\n return cached;\r\n}\r\n","/**\r\n * Pretense CLI — Token Visibility Footer\r\n *\r\n * Prints a small footer after scan/mutate commands so users always know\r\n * (a) what plan they're on, (b) how much of their monthly quota they have\r\n * left, and (c) where to upgrade. This is the \"tokens remaining\" bar that\r\n * pre-seed CISOs expect from a paid security tool.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\nimport { detectTier, getTierLimits, loadUsage, type LicenseTier } from \"./config.js\";\r\n\r\ninterface PlanLimits {\r\n monthlyMutations: number;\r\n monthlyScans: number;\r\n seats: number;\r\n pricePerMonth: string;\r\n}\r\n\r\nconst PLAN_LIMITS: Record<LicenseTier, PlanLimits> = {\r\n free: { monthlyMutations: 1000, monthlyScans: 5000, seats: 3, pricePerMonth: \"$0/month\" },\r\n pro: { monthlyMutations: 100000, monthlyScans: 500000, seats: 25, pricePerMonth: \"$29/seat/month\" },\r\n enterprise: {\r\n monthlyMutations: Number.POSITIVE_INFINITY,\r\n monthlyScans: Number.POSITIVE_INFINITY,\r\n seats: Number.POSITIVE_INFINITY,\r\n pricePerMonth: \"$99/seat/month\",\r\n },\r\n};\r\n\r\nexport function getPlanLimits(tier: LicenseTier): PlanLimits {\r\n return PLAN_LIMITS[tier];\r\n}\r\n\r\nfunction fmt(n: number): string {\r\n if (!Number.isFinite(n)) return \"unlimited\";\r\n return n.toLocaleString(\"en-US\");\r\n}\r\n\r\n/**\r\n * Print a one-line \"tokens remaining\" footer after a CLI command completes.\r\n * Stays silent on enterprise tier (no quota to nag about).\r\n */\r\nexport function printTokenFooter(filesScanned: number, mutationsMade: number): void {\r\n const tier = detectTier();\r\n const limits = getPlanLimits(tier);\r\n const usage = loadUsage();\r\n\r\n // Enterprise users should not see upgrade nags\r\n if (tier === \"enterprise\") {\r\n process.stderr.write(\r\n chalk.gray(`\\n ${filesScanned} files, ${mutationsMade} mutations · Plan: Enterprise (unlimited)\\n\\n`),\r\n );\r\n return;\r\n }\r\n\r\n const used = usage.mutations;\r\n const cap = limits.monthlyMutations;\r\n const pct = cap > 0 ? Math.min(100, Math.round((used / cap) * 100)) : 0;\r\n\r\n // Reserve color for warning when over 80%\r\n const usageStr = pct >= 80 ? chalk.yellow(`${fmt(used)} / ${fmt(cap)}`) : chalk.gray(`${fmt(used)} / ${fmt(cap)}`);\r\n\r\n process.stderr.write(\r\n `\\n ${chalk.cyan(filesScanned + \" files\")}, ${chalk.cyan(mutationsMade + \" mutations\")} ` +\r\n `· Plan: ${chalk.bold(tier.toUpperCase())} · Mutations this month: ${usageStr} (${pct}%)\\n`,\r\n );\r\n\r\n if (tier === \"free\") {\r\n if (pct >= 80) {\r\n process.stderr.write(\r\n chalk.yellow(` ⚠ Approaching free-tier limit. Upgrade: ${chalk.bold(\"pretense upgrade\")}\\n\\n`),\r\n );\r\n } else {\r\n process.stderr.write(\r\n chalk.gray(` Run ${chalk.bold(\"pretense status\")} for details, ${chalk.bold(\"pretense upgrade\")} to remove limits.\\n\\n`),\r\n );\r\n }\r\n } else {\r\n process.stderr.write(\"\\n\");\r\n }\r\n}\r\n","/**\r\n * Pretense CLI banner.\r\n *\r\n * Printed before the commander routes a subcommand. Silent when the\r\n * terminal is a CI environment, pipeline, or non-TTY, or when the user\r\n * sets PRETENSE_NO_BANNER=1.\r\n *\r\n * Ice-blue tint (#7DD3FC) is applied via chalk.hex which needs a 256-color\r\n * terminal. We wrap the tint call in try/catch so older terminals without\r\n * truecolor support silently fall back to the plain banner. Never break\r\n * startup because a user runs Pretense on a legacy shell.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\n\r\nconst BANNER_RAW = `██████████████ pretense\r\n██ ██\r\n██ ██ Stop your code from\r\n██ ██ leaking to any LLM.\r\n██████████████\r\n██ pretense.ai\r\n██\r\n██\r\n██\r\n██`;\r\n\r\nconst ICE_BLUE = \"#7DD3FC\";\r\n\r\nfunction shouldPrint(): boolean {\r\n if (process.env.PRETENSE_NO_BANNER === \"1\") return false;\r\n if (!process.stdout.isTTY) return false;\r\n if (process.env.CI) return false;\r\n return true;\r\n}\r\n\r\nfunction tint(line: string): string {\r\n // chalk.hex is only safe on terminals that understand truecolor or 256-color.\r\n // If chalk throws or the user's terminal strips the escape codes, we print\r\n // the plain line instead of garbled output.\r\n try {\r\n return chalk.hex(ICE_BLUE)(line);\r\n } catch {\r\n return line;\r\n }\r\n}\r\n\r\nexport function printBanner(): void {\r\n if (!shouldPrint()) return;\r\n const lines = BANNER_RAW.split(\"\\n\");\r\n for (const line of lines) {\r\n process.stderr.write(tint(line) + \"\\n\");\r\n }\r\n process.stderr.write(\"\\n\");\r\n}\r\n","/**\r\n * Pretense CLI — `status` command\r\n *\r\n * Shows the current plan, monthly quota usage, seat count, and quick\r\n * upgrade hint. Fetches from the backend when reachable; falls back\r\n * to local state when offline.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\nimport { detectTier, getTierLimits, loadUsage, type LicenseTier } from \"../config.js\";\r\nimport { getPlanLimits } from \"../token-footer.js\";\r\nimport {\r\n fetchUsageSummary,\r\n usageSummaryFromValidate,\r\n validateKey,\r\n} from \"../backend-client.js\";\r\nimport { getCliSemver } from \"../version.js\";\r\n\r\nconst PLAN_LABEL: Record<LicenseTier, string> = {\r\n free: \"Free\",\r\n pro: \"Pro\",\r\n enterprise: \"Enterprise\",\r\n};\r\n\r\nfunction fmt(n: number): string {\r\n if (n === -1 || !Number.isFinite(n)) return \"unlimited\";\r\n return n.toLocaleString(\"en-US\");\r\n}\r\n\r\nexport async function runStatus(): Promise<void> {\r\n // Prefer GET /usage/summary (full request/secrets stats); fall back to POST\r\n // /auth/validate so `status` matches Postman when summary is unreachable.\r\n let remote = await fetchUsageSummary();\r\n if (!remote) {\r\n const v = await validateKey({ force: true });\r\n if (v?.valid) {\r\n remote = usageSummaryFromValidate(v);\r\n }\r\n }\r\n\r\n if (remote) {\r\n const plan = remote.plan;\r\n const tierBadge =\r\n plan === \"ENTERPRISE\"\r\n ? chalk.bgMagenta.white.bold(\" ENTERPRISE \")\r\n : plan === \"PRO\"\r\n ? chalk.bgBlue.white.bold(\" PRO \")\r\n : chalk.bgGray.white.bold(\" FREE \");\r\n\r\n const lines: string[] = [];\r\n lines.push(\"\");\r\n lines.push(`${chalk.cyan(\"Pretense\")} ${chalk.gray(`v${getCliSemver()}`)} ${tierBadge} ${chalk.green(\"(synced)\")}`);\r\n lines.push(\"\");\r\n lines.push(` Plan: ${chalk.bold(plan)}`);\r\n lines.push(` Mutations: ${fmt(remote.mutationsUsed)} / ${fmt(remote.monthlyMutationLimit)} this month`);\r\n lines.push(` Remaining: ${fmt(remote.mutationsRemaining)}`);\r\n lines.push(` Requests: ${fmt(remote.requestsThisPeriod)} this period`);\r\n lines.push(` Secrets: ${fmt(remote.secretsBlockedThisPeriod)} blocked`);\r\n lines.push(` Key status: ${remote.keyStatus === \"active\" ? chalk.green(\"active\") : chalk.red(\"revoked\")}`);\r\n lines.push(` Resets at: ${new Date(remote.periodResetsAt).toLocaleDateString()}`);\r\n if (remote.keyExpiresAt) {\r\n lines.push(` Key expires: ${new Date(remote.keyExpiresAt).toLocaleDateString()}`);\r\n }\r\n lines.push(\"\");\r\n\r\n if (plan === \"FREE\") {\r\n lines.push(` ${chalk.gray(\"Upgrade:\")} ${chalk.bold(\"pretense upgrade\")}`);\r\n lines.push(\"\");\r\n }\r\n\r\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\r\n return;\r\n }\r\n\r\n // Fallback: local-only status.\r\n const tier = detectTier();\r\n const planLimits = getPlanLimits(tier);\r\n const tierLimits = getTierLimits(tier);\r\n const usage = loadUsage();\r\n\r\n const tierBadge =\r\n tier === \"enterprise\"\r\n ? chalk.bgMagenta.white.bold(\" ENTERPRISE \")\r\n : tier === \"pro\"\r\n ? chalk.bgBlue.white.bold(\" PRO \")\r\n : chalk.bgGray.white.bold(\" FREE \");\r\n\r\n const lines: string[] = [];\r\n lines.push(\"\");\r\n lines.push(`${chalk.cyan(\"Pretense\")} ${chalk.gray(`v${getCliSemver()}`)} ${tierBadge} ${chalk.yellow(\"(offline)\")}`);\r\n lines.push(\"\");\r\n lines.push(` Plan: ${chalk.bold(PLAN_LABEL[tier])} ${chalk.gray(\"(\" + planLimits.pricePerMonth + \")\")}`);\r\n lines.push(` Mutations: ${fmt(usage.mutations)} / ${fmt(planLimits.monthlyMutations)} this month`);\r\n lines.push(` Scans: 0 / ${fmt(planLimits.monthlyScans)} this month`);\r\n lines.push(` Seats: 1 / ${fmt(planLimits.seats)}`);\r\n lines.push(` Audit log: ${Number.isFinite(tierLimits.auditRetentionDays) ? `${tierLimits.auditRetentionDays} days` : \"unlimited\"}`);\r\n lines.push(\"\");\r\n\r\n if (tier === \"free\") {\r\n lines.push(` ${chalk.gray(\"Upgrade:\")} ${chalk.bold(\"pretense upgrade\")}`);\r\n lines.push(` ${chalk.gray(\"Credits:\")} ${chalk.bold(\"pretense credits\")}`);\r\n lines.push(\"\");\r\n }\r\n\r\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\r\n}\r\n","/**\r\n * Pretense CLI — `upgrade` command\r\n *\r\n * Prints a side-by-side comparison of Free / Pro / Enterprise tiers and\r\n * a one-click URL to start checkout. Doubles as the in-CLI pricing page.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\nimport { detectTier } from \"../config.js\";\r\n\r\nconst PRICING_URL = \"https://pretense.ai/pricing\";\r\n\r\nexport function runUpgrade(): void {\r\n const tier = detectTier();\r\n\r\n const lines: string[] = [];\r\n lines.push(\"\");\r\n lines.push(chalk.cyan.bold(\" Pretense Plans\"));\r\n lines.push(\"\");\r\n lines.push(chalk.gray(\" ┌──────────────┬──────────┬──────────┬─────────────┐\"));\r\n lines.push(chalk.gray(\" │ │ Free │ Pro │ Enterprise │\"));\r\n lines.push(chalk.gray(\" ├──────────────┼──────────┼──────────┼─────────────┤\"));\r\n lines.push(` │ Price/seat │ ${chalk.bold(\"$0\")} │ ${chalk.bold(\"$29\")} │ ${chalk.bold(\"$99\")} │`);\r\n lines.push(\" │ Mutations/mo │ 1,000 │ 100,000 │ unlimited │\");\r\n lines.push(\" │ Scans/mo │ 5,000 │ 500,000 │ unlimited │\");\r\n lines.push(\" │ Seats │ 3 │ 25 │ unlimited │\");\r\n lines.push(\" │ Audit log │ 30 days │ 90 days │ unlimited │\");\r\n lines.push(\" │ SSO/SAML │ - │ - │ yes │\");\r\n lines.push(\" │ On-prem │ - │ - │ yes │\");\r\n lines.push(\" │ SLA │ - │ - │ 24/7 │\");\r\n lines.push(chalk.gray(\" └──────────────┴──────────┴──────────┴─────────────┘\"));\r\n lines.push(\"\");\r\n lines.push(` ${chalk.gray(\"Current plan:\")} ${chalk.bold(tier.toUpperCase())}`);\r\n lines.push(` ${chalk.gray(\"Upgrade at:\")} ${chalk.cyan.underline(PRICING_URL)}`);\r\n lines.push(\"\");\r\n lines.push(chalk.gray(\" After purchase, set:\"));\r\n lines.push(chalk.gray(\" export PRETENSE_LICENSE_KEY=pre_pro_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"));\r\n lines.push(\"\");\r\n\r\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\r\n}\r\n","/**\r\n * Pretense CLI — `credits` command\r\n *\r\n * Friendly summary of how much of the monthly mutation/scan quota the\r\n * user has burned through. Fetches from backend when reachable; falls\r\n * back to local state when offline.\r\n */\r\n\r\nimport chalk from \"chalk\";\r\nimport { detectTier, loadUsage, type LicenseTier } from \"../config.js\";\r\nimport { getPlanLimits } from \"../token-footer.js\";\r\nimport {\r\n fetchUsageSummary,\r\n usageSummaryFromValidate,\r\n validateKey,\r\n} from \"../backend-client.js\";\r\n\r\nconst PLAN_LABEL: Record<LicenseTier, string> = {\r\n free: \"Free\",\r\n pro: \"Pro\",\r\n enterprise: \"Enterprise\",\r\n};\r\n\r\nfunction fmt(n: number): string {\r\n if (n === -1 || !Number.isFinite(n)) return \"unlimited\";\r\n return n.toLocaleString(\"en-US\");\r\n}\r\n\r\nfunction progressBar(used: number, cap: number, width = 24): string {\r\n if (cap === -1 || !Number.isFinite(cap) || cap <= 0) return chalk.green(\"[\" + \"=\".repeat(width) + \"]\");\r\n const pct = Math.min(1, used / cap);\r\n const filled = Math.round(pct * width);\r\n const bar = \"=\".repeat(filled) + \"-\".repeat(width - filled);\r\n const colored = pct >= 0.8 ? chalk.yellow(bar) : pct >= 1 ? chalk.red(bar) : chalk.green(bar);\r\n return \"[\" + colored + \"]\";\r\n}\r\n\r\nexport async function runCredits(): Promise<void> {\r\n let remote = await fetchUsageSummary();\r\n if (!remote) {\r\n const v = await validateKey({ force: true });\r\n if (v?.valid) {\r\n remote = usageSummaryFromValidate(v);\r\n }\r\n }\r\n\r\n if (remote) {\r\n const used = remote.mutationsUsed;\r\n const cap = remote.monthlyMutationLimit;\r\n const remaining = remote.mutationsRemaining;\r\n const pct = cap > 0 && cap !== -1 ? Math.round((used / cap) * 100) : 0;\r\n\r\n const lines: string[] = [];\r\n lines.push(\"\");\r\n lines.push(chalk.cyan.bold(\" Pretense Credits\") + \" \" + chalk.green(\"(synced)\"));\r\n lines.push(\"\");\r\n lines.push(` Plan: ${chalk.bold(remote.plan)}`);\r\n lines.push(` Resets: ${new Date(remote.periodResetsAt).toLocaleDateString()}`);\r\n lines.push(\"\");\r\n lines.push(` Mutations: ${progressBar(used, cap)} ${fmt(used)} / ${fmt(cap)}`);\r\n lines.push(` Used: ${pct}%`);\r\n lines.push(` Remaining: ${fmt(remaining)}`);\r\n lines.push(\"\");\r\n\r\n if (remote.plan === \"FREE\" && cap !== -1 && used >= cap * 0.8) {\r\n lines.push(chalk.yellow(\" Warning: Approaching free-tier limit. Run 'pretense upgrade' for unlimited.\"));\r\n lines.push(\"\");\r\n } else if (remote.plan === \"FREE\") {\r\n lines.push(chalk.gray(\" Tip: Run 'pretense upgrade' to compare plans.\"));\r\n lines.push(\"\");\r\n }\r\n\r\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\r\n return;\r\n }\r\n\r\n // Fallback: local-only credits.\r\n const tier = detectTier();\r\n const limits = getPlanLimits(tier);\r\n const usage = loadUsage();\r\n\r\n const used = usage.mutations;\r\n const cap = limits.monthlyMutations;\r\n const remaining = Number.isFinite(cap) ? Math.max(0, cap - used) : Number.POSITIVE_INFINITY;\r\n const pct = Number.isFinite(cap) && cap > 0 ? Math.round((used / cap) * 100) : 0;\r\n\r\n const lines: string[] = [];\r\n lines.push(\"\");\r\n lines.push(chalk.cyan.bold(\" Pretense Credits\") + \" \" + chalk.yellow(\"(offline)\"));\r\n lines.push(\"\");\r\n lines.push(` Plan: ${chalk.bold(PLAN_LABEL[tier])}`);\r\n lines.push(` Month: ${usage.month}`);\r\n lines.push(\"\");\r\n lines.push(` Mutations: ${progressBar(used, cap)} ${fmt(used)} / ${fmt(cap)}`);\r\n lines.push(` Used: ${pct}%`);\r\n lines.push(` Remaining: ${fmt(remaining)}`);\r\n lines.push(\"\");\r\n\r\n if (tier === \"free\" && Number.isFinite(cap) && used >= cap * 0.8) {\r\n lines.push(chalk.yellow(\" Warning: Approaching free-tier limit. Run 'pretense upgrade' for unlimited.\"));\r\n lines.push(\"\");\r\n } else if (tier === \"free\") {\r\n lines.push(chalk.gray(\" Tip: Run 'pretense upgrade' to compare plans.\"));\r\n lines.push(\"\");\r\n }\r\n\r\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\r\n}\r\n","/**\r\n * `pretense logout` — remove the saved Pretense dashboard API key from\r\n * ~/.pretense/config.json after interactive confirmation.\r\n */\r\n\r\nimport readline from \"node:readline/promises\";\r\nimport chalk from \"chalk\";\r\nimport { loadApiKey, removeSavedDashboardCredentials } from \"./login.js\";\r\nimport { clearValidationCache } from \"../backend-client.js\";\r\n\r\nexport async function runLogout(opts: { assumeYes?: boolean } = {}): Promise<number> {\r\n if (!loadApiKey()) {\r\n console.log(chalk.gray(\"No saved Pretense dashboard API key in ~/.pretense/config.json.\"));\r\n console.log(chalk.gray(\"If you use PRETENSE_API_KEY in your shell, run unset PRETENSE_API_KEY.\"));\r\n return 0;\r\n }\r\n\r\n if (!opts.assumeYes) {\r\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\r\n console.error(chalk.red(\"Error: confirmation requires an interactive terminal.\"));\r\n console.error(chalk.gray(\"Run `pretense logout --yes` to skip the prompt.\"));\r\n return 1;\r\n }\r\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\r\n try {\r\n const raw = await rl.question(\r\n chalk.bold(\"Log out and remove your saved API key? Type y for yes, n for no: \"),\r\n );\r\n const answer = raw.trim().toLowerCase();\r\n if (answer !== \"y\" && answer !== \"yes\") {\r\n console.log(chalk.yellow(\"Logout cancelled.\"));\r\n return 0;\r\n }\r\n } finally {\r\n rl.close();\r\n }\r\n }\r\n\r\n const hadEnvDashboardKey = !!(process.env[\"PRETENSE_API_KEY\"]?.trim());\r\n const { removed, path } = removeSavedDashboardCredentials();\r\n clearValidationCache();\r\n delete process.env[\"PRETENSE_API_KEY\"];\r\n\r\n if (removed) {\r\n console.log(chalk.green(\"Logged out. Removed saved API key from\"), chalk.bold(path));\r\n console.log(chalk.gray(\"Other terminals: run unset PRETENSE_API_KEY if that variable is still exported (e.g. in ~/.zshrc).\"));\r\n if (hadEnvDashboardKey) {\r\n console.log(\r\n chalk.yellow(\r\n \"This shell had PRETENSE_API_KEY set; it was cleared for this process only. Restart any running pretense proxy (Ctrl+C, then pretense start).\",\r\n ),\r\n );\r\n }\r\n }\r\n return 0;\r\n}\r\n"],"mappings":";;;AAoBA,SAAS,eAAe;AACxB,OAAOA,YAAW;AAClB;AAAA,EACE,gBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAAC;AAAA,EACA;AAAA,OAEK;AACP,SAAS,UAAU,QAAQ,QAAQ,QAAQ,cAAc;AACzD,SAAS,WAAAC,UAAS,SAAS,QAAAC,OAAM,gBAAgB;AACjD,OAAO,QAAQ;;;ACoER,IAAM,iBAAiC;AAAA,EAC5C,MAAM;AAAA,EACN,YAAY,CAAC,6BAA6B,wBAAwB;AAAA,EAClE,WAAW,CAAC,cAAc,cAAc,UAAU,MAAM,QAAQ,UAAU,QAAQ,MAAM;AAAA,EACxF,eAAe;AAAA,IACb,EAAE,WAAW,2BAAoB,QAAQ,KAAK;AAAA,IAC9C,EAAE,WAAW,2BAAoB,QAAQ,MAAM;AAAA,IAC/C,EAAE,WAAW,qBAAiB,QAAQ,OAAO;AAAA,IAC7C,EAAE,WAAW,sBAAiB;AAAA,IAC9B,EAAE,WAAW,yBAAmB,OAAO,KAAK;AAAA,IAC5C,EAAE,WAAW,sBAAiB;AAAA,IAC9B,EAAE,WAAW,2BAAoB,QAAQ,QAAQ;AAAA,IACjD,EAAE,WAAW,uBAAkB,QAAQ,MAAM;AAAA,EAC/C;AAAA,EACA,WAAW,GAAG,QAAQ,IAAI,MAAM,KAAK,MAAM;AAC7C;;;ACvGA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EAAY;AAAA,EAAO;AAAA,EAAM;AAAA,EAAS;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EAC/D;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAe;AAAA,EAAY;AAAA,EAAY;AAAA,EAClE;AAAA,EAAW;AAAA,EAAU;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAW;AAAA,EAChE;AAAA,EAAW;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAO;AAAA,EAAM;AAAA,EAAc;AAAA,EACjE;AAAA,EAAM;AAAA,EAAc;AAAA,EAAa;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAC3D;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAU;AAAA,EAAM;AAAA,EAAW;AAAA,EAC7D;AAAA,EAAa;AAAA,EAAU;AAAA,EAAY;AAAA,EAAW;AAAA,EAAU;AAAA,EAAO;AAAA,EAC/D;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAChE;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAa;AAAA,EAAW;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAClE;AAAA,EAAS;AAAA,EAAa;AAAA,EAAS;AAAA,EAAS;AAC1C,CAAC;AAED,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAM;AAAA,EAAU;AAAA,EAAS;AAAA,EACzD;AAAA,EAAS;AAAA,EAAS;AAAA,EAAY;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAC5D;AAAA,EAAW;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAM;AAAA,EAAU;AAAA,EAAM;AAAA,EAC1D;AAAA,EAAU;AAAA,EAAY;AAAA,EAAO;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAC9D;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AACpC,CAAC;AAED,IAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAY;AAAA,EAAW;AAAA,EAAS;AAAA,EAClE;AAAA,EAAe;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAU;AAAA,EAC5D;AAAA,EAAO;AAAA,EAAW;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EACnE;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAU;AAAA,EAAO;AAAA,EAAQ;AAAA,EACjE;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EACjE;AAAA,EAAW;AAAA,EAAa;AAAA,EAAc;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAC9D;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAClE;AAAA,EAAW;AAAA,EAAS;AACtB,CAAC;AAED,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAAY;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EACnE;AAAA,EAAS;AAAA,EAAS;AAAA,EAAY;AAAA,EAAW;AAAA,EAAM;AAAA,EAAU;AAAA,EAAQ;AAAA,EACjE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAM;AAAA,EAC7D;AAAA,EAAU;AAAA,EAAc;AAAA,EAAO;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAU;AAAA,EAC9D;AAAA,EAAW;AAAA,EAAW;AAAA,EAAa;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAChE;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAAA,EAAgB;AAAA,EAAQ;AAAA,EAAS;AAAA,EAChE;AAAA,EAAa;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAClE;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAAW;AACxC,CAAC;AAED,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EAAS;AAAA,EAAa;AAAA,EAAa;AAAA,EAAU;AAAA,EAAW;AAAA,EACxD;AAAA,EAAY;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAO;AAAA,EAAS;AAAA,EAAY;AAAA,EACpE;AAAA,EAAY;AAAA,EAAW;AAAA,EAAY;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EACpE;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAM;AAAA,EAAQ;AAAA,EACpE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAM;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAY;AAAA,EACjE;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAC7D;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAY;AAChC,CAAC;AAED,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EAAO;AAAA,EAAM;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAS;AAAA,EAC9D;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAC/D;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EACtE;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAW;AAAA,EACpD;AAAA,EAAW;AAAA,EAAU;AAAA,EAAiB;AAAA,EAAe;AAAA,EACrD;AAAA,EAAc;AAAA,EAAO;AAAA,EAAU;AAAA,EAAW;AAC5C,CAAC;AAED,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAAM;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAC9D;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EACjE;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAS;AAAA,EACzD;AAAA,EAAS;AAAA,EAAM;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAO;AAAA,EACjE;AAAA,EAAU;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAO;AAAA,EAAU;AAAA,EAC9D;AAAA,EAAM;AAAA,EAAO;AAAA,EAAQ;AACvB,CAAC;AAWM,SAAS,eAAe,MAAsB;AACnD,MAAI,uBAAuB,KAAK,IAAI,KAAK,sBAAsB,KAAK,IAAI,KAAK,kBAAkB,KAAK,IAAI,EAAG,QAAO;AAClH,MAAI,mBAAmB,KAAK,IAAI,KAAK,iBAAiB,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,EAAG,QAAO;AAC5F,MAAI,oBAAoB,KAAK,IAAI,KAAK,kBAAkB,KAAK,IAAI,EAAG,QAAO;AAC3E,MAAI,yBAAyB,KAAK,IAAI,KAAK,oBAAoB,KAAK,IAAI,EAAG,QAAO;AAClF,MAAI,oBAAoB,KAAK,IAAI,KAAK,mBAAmB,KAAK,IAAI,EAAG,QAAO;AAC5E,MAAI,kBAAkB,KAAK,IAAI,KAAK,oBAAoB,KAAK,IAAI,EAAG,QAAO;AAC3E,MAAI,cAAc,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI,EAAG,QAAO;AAC7D,MAAI,oBAAoB,KAAK,IAAI,KAAK,wBAAwB,KAAK,IAAI,EAAG,QAAO;AACjF,SAAO;AACT;AAYA,SAAS,eAAe,MAAwB;AAC9C,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,WAAW,CAAC,MAAM,GAAa,SAAQ,KAAK,CAAC;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,cAAc,aAAuB,OAAuB;AAEnE,MAAI,KAAK;AACT,MAAI,KAAK,YAAY;AACrB,SAAO,KAAK,IAAI;AACd,UAAM,MAAO,KAAK,MAAO;AACzB,QAAI,YAAY,GAAG,IAAK,MAAO,MAAK,MAAM;AAAA,QACrC,MAAK;AAAA,EACZ;AACA,SAAO,KAAK;AACd;AAIA,SAAS,eAAe,MAAuB;AAC7C,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA;AAAA,IAE5E,EAAE,IAAI,eAAe,8BAAwB;AAAA;AAAA,IAE7C,EAAE,IAAI,qBAAqB,8BAAwB;AAAA;AAAA,IAEnD,EAAE,IAAI,sDAAsD,gDAAiC;AAAA,IAC7F,EAAE,IAAI,sDAAsD,gDAAiC;AAAA;AAAA,IAE7F;AAAA,MACE,IAAI;AAAA,MACJ;AAAA,MACA,YAAY;AAAA,IACd;AAAA;AAAA,IAEA,EAAE,IAAI,qCAAqC,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEjF,EAAE,IAAI,yCAAyC,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAEpF,EAAE,IAAI,4CAA4C,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE1F,EAAE,IAAI,qGAAqG,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEnJ,EAAE,IAAI,sCAAsC,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAElF,EAAE,IAAI,4FAA4F,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE1I,EAAE,IAAI,+EAA+E,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE7H,EAAE,IAAI,qDAAqD,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEnG,EAAE,IAAI,4CAA4C,iCAA0B,YAAY,EAAE;AAAA,IAC1F,EAAE,IAAI,8CAA8C,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE5F,EAAE,IAAI,YAAY,4BAAuB;AAAA;AAAA,IAEzC,EAAE,IAAI,sBAAsB,4BAAuB;AAAA;AAAA,IAEnD,EAAE,IAAI,sBAAsB,4BAAuB;AAAA,EACrD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAGjD,UACE,sCACA,sCACA,gCACA,kCACA,oCACA;AACA,YAAI,eAAe,IAAI,YAAY,EAAG;AAEtC,YAAI,mMAAmM,KAAK,YAAY,EAAG;AAE3N,YAAI,aAAa,UAAU,EAAG;AAAA,MAChC;AAGA,UACE,sCACA,iBAAiB,UACjB,KAAK,MAAM,KAAK,IAAI,GAAG,eAAe,CAAC,GAAG,YAAY,MAAM,WAC5D;AACA;AAAA,MACF;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,OAAO,CAAC,MAAM,EAAE,gCAA0B;AACtE,QAAM,kBAAkB,OAAO;AAAA,IAC7B,CAAC,MAAM,EAAE,kCAA6B,EAAE;AAAA,EAC1C;AACA,QAAM,mBAAmB,CAAC,MAAa;AACrC,QACE,EAAE,sCACF,EAAE,sCACF,EAAE,gCACF,EAAE,kCACF,EAAE,oCACF;AACA,UAAI,aAAa,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAG,QAAO;AACzE,UAAI,gBAAgB,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAG,QAAO;AAAA,IAC9E;AACA,WAAO;AAAA,EACT;AAEA,SAAO,YAAY,OAAO,OAAO,gBAAgB,CAAC;AACpD;AAEA,SAAS,WAAW,MAAuB;AACzC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA;AAAA,IAE5E,EAAE,IAAI,kCAAkC,8BAAwB;AAAA;AAAA,IAEhE,EAAE,IAAI,YAAY,8BAAwB;AAAA;AAAA,IAE1C,EAAE,IAAI,yCAAyC,6BAAwB,YAAY,EAAE;AAAA,IACrF,EAAE,IAAI,iDAAiD,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAE7F,EAAE,IAAI,uCAAuC,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAElF,EAAE,IAAI,qCAAqC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEnF,EAAE,IAAI,oCAAoC,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEhF,EAAE,IAAI,oDAAoD,iCAA0B,YAAY,EAAE;AAAA,IAClG,EAAE,IAAI,0CAA0C,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAExF,EAAE,IAAI,mCAAmC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEjF,EAAE,IAAI,sBAAsB,4BAAuB;AAAA;AAAA,IAEnD,EAAE,IAAI,sBAAsB,4BAAuB;AAAA,EACrD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,sCACA,gCACA,kCACA,oCACA;AACA,YAAI,gBAAgB,IAAI,YAAY,EAAG;AACvC,YAAI,aAAa,UAAU,EAAG;AAE9B,YAAI,aAAa,WAAW,IAAI,KAAK,aAAa,SAAS,IAAI,EAAG;AAAA,MACpE;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,iBAAiB,OAAO,OAAO,CAAC,MAAM,EAAE,gCAA0B;AACxE,QAAM,gBAAgB,OAAO,OAAO,CAAC,MAAM,EAAE,8BAAyB;AACtE,QAAM,iBAAiB,CAAC,MAAa;AACnC,QACE,EAAE,sCACF,EAAE,sCACF,EAAE,gCACF,EAAE,kCACF,EAAE,oCACF;AACA,UAAI,eAAe,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAG,QAAO;AAC3E,UAAI,cAAc,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAG,QAAO;AAAA,IAC5E;AACA,WAAO;AAAA,EACT;AAEA,SAAO,YAAY,OAAO,OAAO,cAAc,CAAC;AAClD;AAEA,SAAS,OAAO,MAAuB;AACrC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA,IAC5E,EAAE,IAAI,eAAe,8BAAwB;AAAA,IAC7C,EAAE,IAAI,qBAAqB,8BAAwB;AAAA;AAAA,IAEnD,EAAE,IAAI,kCAAkC,4BAAuB;AAAA,IAC/D,EAAE,IAAI,uBAAuB,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEnE,EAAE,IAAI,6DAA6D,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAExG,EAAE,IAAI,4DAA4D,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE1G,EAAE,IAAI,iDAAiD,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE/F,EAAE,IAAI,oCAAoC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAElF,EAAE,IAAI,sBAAsB,4BAAuB;AAAA;AAAA,IAEnD,EAAE,IAAI,YAAY,4BAAuB;AAAA,EAC3C;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,sCACA,8BACA;AACA,YAAI,YAAY,IAAI,YAAY,EAAG;AACnC,YAAI,aAAa,UAAU,EAAG;AAAA,MAChC;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,YAAY,MAAM;AAC3B;AAEA,SAAS,SAAS,MAAuB;AACvC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA,IAC5E,EAAE,IAAI,eAAe,8BAAwB;AAAA,IAC7C,EAAE,IAAI,qBAAqB,8BAAwB;AAAA;AAAA,IAEnD,EAAE,IAAI,yBAAyB,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAErE,EAAE,IAAI,mEAAmE,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAE9G,EAAE,IAAI,qIAAqI,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEjL,EAAE,IAAI,gHAAgH,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE9J,EAAE,IAAI,sBAAsB,4BAAuB;AAAA,EACrD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,kCACA,8BACA;AACA,YAAI,cAAc,IAAI,YAAY,EAAG;AACrC,YAAI,aAAa,UAAU,EAAG;AAE9B,YAAI,iHAAiH,KAAK,YAAY,EAAG;AAAA,MAC3I;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,YAAY,MAAM;AAC3B;AAEA,SAAS,WAAW,MAAuB;AACzC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA,IAC5E,EAAE,IAAI,eAAe,8BAAwB;AAAA,IAC7C,EAAE,IAAI,qBAAqB,8BAAwB;AAAA;AAAA,IAEnD,EAAE,IAAI,wBAAwB,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEpE,EAAE,IAAI,iEAAiE,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAE5G,EAAE,IAAI,2GAA2G,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEvJ,EAAE,IAAI,qEAAqE,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEnH,EAAE,IAAI,sBAAsB,4BAAuB;AAAA;AAAA,IAEnD,EAAE,IAAI,oBAAoB,4BAAuB;AAAA,EACnD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,kCACA,8BACA;AACA,YAAI,gBAAgB,IAAI,YAAY,EAAG;AACvC,YAAI,aAAa,UAAU,EAAG;AAC9B,YAAI,iHAAiH,KAAK,YAAY,EAAG;AAAA,MAC3I;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,YAAY,MAAM;AAC3B;AAEA,SAAS,SAAS,MAAuB;AACvC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA;AAAA,IAE5E,EAAE,IAAI,YAAY,8BAAwB;AAAA;AAAA,IAE1C,EAAE,IAAI,gCAAgC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE9E,EAAE,IAAI,8CAA8C,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAEzF,EAAE,IAAI,oBAAoB,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAElE,EAAE,IAAI,6BAA6B,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAE3E,EAAE,IAAI,sBAAsB,4BAAuB;AAAA;AAAA,IAEnD,EAAE,IAAI,sBAAsB,4BAAuB;AAAA,EACrD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,sCACA,gCACA,oCACA;AACA,YAAI,cAAc,IAAI,YAAY,EAAG;AACrC,YAAI,aAAa,UAAU,EAAG;AAAA,MAChC;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,YAAY,MAAM;AAC3B;AAEA,SAAS,SAAS,MAAuB;AACvC,QAAM,SAAkB,CAAC;AACzB,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,QAAM,cAAc,eAAe,IAAI;AAEvC,QAAM,WAAwE;AAAA,IAC5E,EAAE,IAAI,eAAe,8BAAwB;AAAA,IAC7C,EAAE,IAAI,qBAAqB,8BAAwB;AAAA;AAAA,IAEnD,EAAE,IAAI,qBAAqB,6BAAwB,YAAY,EAAE;AAAA;AAAA,IAEjE,EAAE,IAAI,mDAAmD,2BAAuB,YAAY,EAAE;AAAA;AAAA,IAE9F,EAAE,IAAI,0BAA0B,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAExE,EAAE,IAAI,qCAAqC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEnF,EAAE,IAAI,sCAAsC,iCAA0B,YAAY,EAAE;AAAA;AAAA,IAEpF,EAAE,IAAI,sBAAsB,4BAAuB;AAAA,EACrD;AAEA,aAAW,EAAE,IAAI,MAAM,WAAW,KAAK,UAAU;AAC/C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,YAAM,YAAY,EAAE,CAAC;AACrB,YAAM,eAAe,eAAe,SAAa,EAAE,UAAU,KAAK,YAAa;AAC/E,YAAM,eAAe,eAAe,SAChC,EAAE,QAAQ,UAAU,QAAQ,YAAY,IACxC,EAAE;AAEN,UAAI,CAAC,gBAAgB,aAAa,KAAK,MAAM,GAAI;AAEjD,UACE,sCACA,sCACA,8BACA;AACA,YAAI,cAAc,IAAI,YAAY,EAAG;AACrC,YAAI,aAAa,UAAU,EAAG;AAAA,MAChC;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO;AAAA,QACP,OAAO;AAAA,QACP,KAAK,eAAe,aAAa;AAAA,QACjC,MAAM,cAAc,aAAa,YAAY;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,YAAY,MAAM;AAC3B;AAIA,SAAS,YAAY,QAA0B;AAC7C,SAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACvC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAkB,CAAC;AACzB,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,GAAG,MAAM,KAAK,IAAI,MAAM,GAAG;AACvC,QAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,WAAK,IAAI,GAAG;AACZ,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,KAAK,MAAc,UAA8B;AAC/D,MAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG;AACzB,WAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,OAAO,SAAS,YAAY;AAClC,MAAI;AAEJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,eAAS,eAAe,IAAI;AAC5B;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,eAAS,WAAW,IAAI;AACxB;AAAA,IACF,KAAK;AACH,eAAS,OAAO,IAAI;AACpB;AAAA,IACF,KAAK;AACH,eAAS,SAAS,IAAI;AACtB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,eAAS,WAAW,IAAI;AACxB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,eAAS,SAAS,IAAI;AACtB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,eAAS,SAAS,IAAI;AACtB;AAAA,IACF;AACE,eAAS,eAAe,IAAI;AAAA,EAChC;AAEA,SAAO,EAAE,QAAQ,UAAU,KAAK;AAClC;;;ACtqBA,SAAS,cAAc,eAAe,WAAW,kBAAkB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAE5B,IAAM,aAAa;AAGnB,SAAS,cAA6C;AACpD,QAAM,MAAM,KAAK,QAAQ,GAAG,WAAW;AACvC,SAAO,EAAE,KAAK,MAAM,KAAK,KAAK,eAAe,EAAE;AACjD;AAEA,IAAI,cAA6B;AAE1B,SAAS,kBAA0B;AACxC,MAAI,YAAa,QAAO;AAExB,QAAM,EAAE,KAAK,KAAK,IAAI,YAAY;AAElC,MAAI,WAAW,IAAI,GAAG;AACpB,QAAI;AACF,YAAM,MAAM,aAAa,MAAM,OAAO,EAAE,KAAK;AAC7C,UAAI,kBAAkB,KAAK,GAAG,GAAG;AAC/B,sBAAc,IAAI,YAAY;AAC9B,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,OAAO,YAAY,UAAU,EAAE,SAAS,KAAK;AACnD,MAAI;AACF,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,kBAAc,MAAM,MAAM,EAAE,MAAM,IAAM,CAAC;AAAA,EAC3C,QAAQ;AAAA,EAER;AAEA,gBAAc;AACd,SAAO;AACT;AAEO,SAAS,gBAAgB,UAA0B;AACxD,SAAO,GAAG,QAAQ,IAAI,gBAAgB,CAAC;AACzC;;;ACpDA,SAAS,OAAO,KAAqB;AACnC,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,SAAM,KAAK,KAAK,IAAK,IAAI,WAAW,CAAC;AAAA,EACvC;AACA,SAAO,MAAM;AACf;AAEA,SAAS,WAAW,GAAW,KAAqB;AAClD,QAAM,QAAQ;AACd,MAAI,SAAS;AACb,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,aAAS,MAAM,IAAI,MAAM,MAAM,IAAK;AACpC,QAAI,KAAK,MAAM,IAAI,MAAM,MAAM;AAAA,EACjC;AACA,SAAO;AACT;AAKO,SAAS,yBAAyB,UAAkB,MAAc,QAAgB,MAAM,GAAW;AACxG,QAAM,WAAW,GAAG,IAAI,IAAI,MAAM,IAAI,QAAQ;AAC9C,QAAM,IAAI,OAAO,QAAQ;AACzB,SAAO,SAAS,WAAW,GAAG,GAAG;AACnC;;;AChBA,SAAS,cAAc,MAAyB;AAC9C,UAAQ,MAAM;AAAA,IACZ;AAAyB,aAAO;AAAA,IAChC;AAAA,IACA;AAAyB,aAAO;AAAA,IAChC;AAAyB,aAAO;AAAA,IAChC;AAAyB,aAAO;AAAA,IAChC;AAAiC,aAAO;AAAA,IACxC;AAAyB,aAAO;AAAA,EAClC;AACF;AAcO,SAAS,OAAO,MAAc,UAAmB,OAAO,YAA4B;AACzF,QAAM,UAAU,YAAY,IAAI;AAChC,QAAM,OAAO,YAAY,eAAe,IAAI;AAE5C,MAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,GAAG;AACzB,UAAM,WAAwB,oBAAI,IAAI;AACtC,WAAO;AAAA,MACL,aAAa;AAAA,MACb,KAAK;AAAA,MACL,OAAO,EAAE,eAAe,GAAG,eAAe,GAAG,YAAY,GAAG,UAAU,KAAK;AAAA,IAC7E;AAAA,EACF;AAIA,QAAM,gBAAgB,SAAS,aAAa,gBAAgB,IAAI,IAAI;AAEpE,QAAM,EAAE,OAAO,IAAI,KAAK,MAAM,IAAI;AAClC,QAAM,MAAmB,oBAAI,IAAoB;AAGjD,aAAW,SAAS,QAAQ;AAC1B,QAAI,IAAI,IAAI,MAAM,KAAK,EAAG;AAE1B,QAAI,MAAM,kCAA4B;AAEpC;AAAA,IACF;AAEA,QAAI,MAAM,gCAA2B;AAEnC;AAAA,IACF;AAEA,QAAI,MAAM,oDAAqC;AAC7C,YAAM,KAAK,gBAAgB,KAAK,MAAM,KAAK;AAC3C,UAAI,IAAI;AACN,cAAM,QAAQ,GAAG,CAAC;AAClB,cAAM,IAAI,GAAG,CAAC;AACd,cAAM,iBAAiB,yBAAyB,OAAO,eAAe,uDAAwC,CAAC;AAC/G,YAAI,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG,cAAc,GAAG,CAAC,EAAE;AAAA,MAClD,OAAO;AAEL,cAAM,iBAAiB,yBAAyB,MAAM,OAAO,eAAe,uDAAwC,CAAC;AACrH,YAAI,IAAI,MAAM,OAAO,cAAc;AAAA,MACrC;AACA;AAAA,IACF;AAEA,QAAI,MAAM,gCAA2B;AAEnC;AAAA,IACF;AAEA,UAAM,SAAS,cAAc,MAAM,IAAI;AACvC,UAAM,YAAY,yBAAyB,MAAM,OAAO,eAAe,MAAM;AAC7E,QAAI,IAAI,MAAM,OAAO,SAAS;AAAA,EAChC;AAGA,QAAM,UAAU,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM;AAE3E,MAAI,cAAc;AAClB,aAAW,CAAC,UAAU,SAAS,KAAK,SAAS;AAC3C,QAAI,CAAC,UAAW;AAEhB,UAAM,UAAU,SAAS,QAAQ,uBAAuB,MAAM;AAC9D,QAAI,SAAS,MAAM,4BAA4B,GAAG;AAEhD,oBAAc,YAAY,QAAQ,IAAI,OAAO,MAAM,OAAO,OAAO,GAAG,GAAG,SAAS;AAAA,IAClF,OAAO;AAEL,oBAAc,YAAY,MAAM,QAAQ,EAAE,KAAK,SAAS;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,aAAa,KAAK,OAAO,YAAY,IAAI,IAAI,WAAW,GAAG,IAAI;AAErE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,eAAe,OAAO;AAAA,MACtB,eAAe,IAAI;AAAA,MACnB;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,EACF;AACF;;;ACxGO,SAAS,QAAQ,aAAqB,KAAkB,YAA0C;AACvG,MAAI,CAAC,YAAa,QAAO;AAEzB,MAAI,SAAS;AAGb,MAAI,IAAI,OAAO,GAAG;AAChB,UAAM,aAAa,oBAAI,IAAoB;AAC3C,eAAW,CAAC,UAAU,SAAS,KAAK,IAAI,QAAQ,GAAG;AACjD,UAAI,cAAc,MAAM,CAAC,UAAW;AACpC,iBAAW,IAAI,WAAW,QAAQ;AAAA,IACpC;AAEA,QAAI,WAAW,OAAO,GAAG;AACvB,YAAM,gBAAgB,CAAC,GAAG,WAAW,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM;AAExF,iBAAW,CAAC,WAAW,QAAQ,KAAK,eAAe;AACjD,cAAM,UAAU,UAAU,QAAQ,uBAAuB,MAAM;AAC/D,YAAI,UAAU,MAAM,4BAA4B,KAAK,UAAU,MAAM,uBAAuB,GAAG;AAC7F,mBAAS,OAAO,QAAQ,IAAI,OAAO,MAAM,OAAO,OAAO,GAAG,GAAG,QAAQ;AAAA,QACvE,OAAO;AACL,mBAAS,OAAO,MAAM,SAAS,EAAE,KAAK,QAAQ;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,WAAW,OAAO,GAAG;AACrC,UAAM,gBAAgB,CAAC,GAAG,WAAW,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM;AACxF,eAAW,CAAC,aAAa,QAAQ,KAAK,eAAe;AACnD,eAAS,OAAO,MAAM,WAAW,EAAE,KAAK,QAAQ;AAAA,IAClD;AAAA,EACF;AAEA,SAAO;AACT;;;ACVA,IAAM,kBAAgC;AAAA,EACpC,EAAE,MAAM,qBAAqB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,sCAAsC;AAAA;AAAA,EAE9I,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,mCAAmC;AAAA,EACxI,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,oBAAoB;AAAA;AAAA,EAEzH,EAAE,MAAM,yBAAyB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,qDAAqD,YAAY,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/K;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,6FAA6F,YAAY,EAAE;AAAA,EAChN,EAAE,MAAM,gBAAgB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,4BAA4B;AAAA,EAC/H,EAAE,MAAM,uBAAuB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,gCAAgC;AAAA,EAC1I,EAAE,MAAM,cAAc,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,+CAA+C;AAAA,EAChJ,EAAE,MAAM,eAAe,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,sHAAsH;AAAA;AAAA,EAExN,EAAE,MAAM,aAAa,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,gEAAgE;AAAA,EAC5J,EAAE,MAAM,gBAAgB,UAAU,cAAc,UAAU,YAAY,eAAe,SAAS,SAAS,iFAAiF;AAAA,EACxL;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA;AAAA,IAEf,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA,EAAE,MAAM,eAAe,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,gCAAgC;AAAA,EAClI,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,yBAAyB;AAAA,EAC1H,EAAE,MAAM,aAAa,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,uBAAuB;AAAA,EACvH,EAAE,MAAM,gBAAgB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,4CAA4C;AAAA,EAC/I,EAAE,MAAM,cAAc,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,kBAAkB;AAAA;AAAA,EAEnH,EAAE,MAAM,aAAa,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,sDAAsD;AAAA,EACtJ,EAAE,MAAM,eAAe,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,oBAAoB;AAAA,EACtH,EAAE,MAAM,cAAc,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,kBAAkB;AAAA,EAC/G,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,0FAA0F;AAAA,EAC/L,EAAE,MAAM,iBAAiB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,yBAAyB;AAAA,EAC7H,EAAE,MAAM,eAAe,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,iCAAiC;AAAA,EAC/H,EAAE,MAAM,gBAAgB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,uBAAuB;AAAA,EACtH,EAAE,MAAM,gBAAgB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,oBAAoB;AAAA,EACvH,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,2BAA2B;AAAA,EAC5H,EAAE,MAAM,wBAAwB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,oCAAoC;AAAA,EAC/I,EAAE,MAAM,qBAAqB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,4CAA4C;AAAA,EACpJ,EAAE,MAAM,mBAAmB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,8BAA8B;AAAA,EAChI,EAAE,MAAM,iBAAiB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,2DAA2D;AAAA,EAC3J,EAAE,MAAM,sBAAsB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,uBAAuB;AAAA,EAChI,EAAE,MAAM,iBAAiB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,4CAA4C;AAAA,EAC5I,EAAE,MAAM,qBAAqB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,iCAAiC;AAAA,EACzI,EAAE,MAAM,yBAAyB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,2BAA2B;AAAA,EACvI,EAAE,MAAM,kBAAkB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,0BAA0B;AAAA,EAC3H,EAAE,MAAM,mBAAmB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,iBAAiB,UAAU,CAAC,MAAM,kBAAkB,KAAK,CAAC,EAAE;AAAA,EAC9J,EAAE,MAAM,gBAAgB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,oBAAoB;AAAA;AAAA,EAEnH,EAAE,MAAM,wBAAwB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,iCAAiC;AAAA,EAC5I,EAAE,MAAM,qBAAqB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,mFAAmF;AAAA,EAC3L,EAAE,MAAM,cAAc,UAAU,UAAU,UAAU,QAAQ,eAAe,UAAU,SAAS,wDAAwD;AAAA,EACtJ,EAAE,MAAM,oBAAoB,UAAU,UAAU,UAAU,QAAQ,eAAe,UAAU,SAAS,+BAA+B;AAAA,EACnI,EAAE,MAAM,wBAAwB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,wEAAwE;AAAA,EACnL,EAAE,MAAM,2BAA2B,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,wEAAwE;AAAA;AAAA,EAElL,EAAE,MAAM,yBAAyB,UAAU,UAAU,UAAU,YAAY,eAAe,SAAS,SAAS,8BAA8B;AAAA;AAAA,EAE1I,EAAE,MAAM,mBAAmB,UAAU,UAAU,UAAU,QAAQ,eAAe,SAAS,SAAS,+BAA+B;AAAA;AAAA,EAEjI;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AACF;AAEA,IAAM,eAA6B;AAAA,EACjC,EAAE,MAAM,OAAO,UAAU,OAAO,UAAU,YAAY,eAAe,UAAU,SAAS,yBAAyB;AAAA,EACjH,EAAE,MAAM,eAAe,UAAU,OAAO,UAAU,YAAY,eAAe,UAAU,SAAS,4BAA4B,UAAU,UAAU;AAAA,EAChJ,EAAE,MAAM,SAAS,UAAU,OAAO,UAAU,UAAU,eAAe,QAAQ,SAAS,sDAAsD;AAAA,EAC5I,EAAE,MAAM,YAAY,UAAU,OAAO,UAAU,UAAU,eAAe,QAAQ,SAAS,2DAA2D;AAAA,EACpJ,EAAE,MAAM,cAAc,UAAU,OAAO,UAAU,OAAO,eAAe,QAAQ,SAAS,gFAAgF,UAAU,CAAC,OAAO,CAAC,GAAG,WAAW,MAAM,KAAK,CAAC,GAAG,WAAW,IAAI,KAAK,OAAO,kBAAkB;AACvQ;AAEA,IAAM,eAA6B;AAAA,EACjC,EAAE,MAAM,cAAc,UAAU,cAAc,UAAU,QAAQ,eAAe,SAAS,SAAS,8HAA8H;AACjO;AAEA,SAAS,UAAU,KAAsB;AACvC,QAAM,SAAS,IAAI,QAAQ,OAAO,EAAE;AACpC,MAAI,OAAO,SAAS,MAAM,OAAO,SAAS,GAAI,QAAO;AACrD,MAAI,MAAM;AACV,MAAI,YAAY;AAChB,WAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,QAAI,IAAI,SAAS,OAAO,CAAC,GAAI,EAAE;AAC/B,QAAI,WAAW;AAAE,WAAK;AAAG,UAAI,IAAI,EAAG,MAAK;AAAA,IAAG;AAC5C,WAAO;AACP,gBAAY,CAAC;AAAA,EACf;AACA,SAAO,MAAM,OAAO;AACtB;AAQO,SAAS,eAAe,KAAqB;AAClD,MAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,QAAM,OAAO,oBAAI,IAAoB;AACrC,aAAW,MAAM,KAAK;AACpB,SAAK,IAAI,KAAK,KAAK,IAAI,EAAE,KAAK,KAAK,CAAC;AAAA,EACtC;AACA,MAAI,UAAU;AACd,QAAM,MAAM,IAAI;AAChB,aAAW,SAAS,KAAK,OAAO,GAAG;AACjC,UAAM,IAAI,QAAQ;AAClB,QAAI,IAAI,EAAG,YAAW,IAAI,KAAK,KAAK,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAMO,SAAS,cAAc,KAAa,YAAY,IAAI,YAAY,KAAc;AACnF,MAAI,IAAI,UAAU,UAAW,QAAO;AACpC,SAAO,eAAe,GAAG,IAAI;AAC/B;AAEA,SAAS,UAAU,OAAe,MAAsB;AACtD,MAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,QAAQ,EAAG,QAAO,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ,MAAM,MAAM,EAAE;AAChI,MAAI,SAAS,MAAO,QAAO,YAAY,MAAM,MAAM,EAAE;AACrD,MAAI,SAAS,cAAe,QAAO,oBAAoB,MAAM,QAAQ,OAAO,EAAE,EAAE,MAAM,EAAE;AACxF,MAAI,SAAS,SAAS;AAAE,UAAM,CAAC,OAAO,MAAM,IAAI,MAAM,MAAM,GAAG;AAAG,YAAQ,QAAQ,CAAC,KAAK,OAAO,UAAU,UAAU;AAAA,EAAK;AACxH,MAAI,MAAM,SAAS,GAAI,QAAO,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ,MAAM,MAAM,EAAE;AACxE,SAAO;AACT;AAEA,IAAI,eAAe;AAKnB,IAAM,yBAAyB,MAAM;AAE9B,SAASC,MAAK,MAAc,iBAAyE;AAC1G,QAAM,QAAQ,YAAY,IAAI;AAC9B,QAAM,UAAuB,CAAC;AAC9B,QAAM,cAAc,CAAC,GAAG,iBAAiB,GAAG,cAAc,GAAG,YAAY;AAEzE,aAAW,OAAO,aAAa;AAC7B,QAAI,QAAQ,YAAY;AACxB,QAAI;AACJ,YAAQ,IAAI,IAAI,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC5C,UAAI,QAAQ,EAAE,CAAC;AACf,UAAIC,SAAQ,EAAE;AACd,UAAI,MAAMA,SAAQ,MAAM;AAExB,UAAI,IAAI,eAAe,QAAW;AAChC,cAAM,OAAO,EAAE,UAAU,IAAI,UAAU;AACvC,YAAI,CAAC,KAAM;AACX,cAAM,CAAC,IAAI,EAAE,IAAI;AACjB,gBAAQ,KAAK,MAAM,IAAI,EAAE;AACzB,QAAAA,SAAQ;AACR,cAAM;AAAA,MACR;AAEA,UAAI,IAAI,YAAY,CAAC,IAAI,SAAS,KAAK,EAAG;AAC1C,YAAM,SAAS,kBAAkB,IAAI,IAAI,KAAK,IAAI;AAClD;AACA,cAAQ,KAAK;AAAA,QACX,IAAI,QAAQ,YAAY;AAAA,QACxB,UAAU,IAAI;AAAA,QACd,MAAM,IAAI;AAAA,QACV;AAAA,QACA,QAAQ,UAAU,OAAO,IAAI,IAAI;AAAA,QACjC,OAAAA;AAAA,QACA;AAAA,QACA,UAAU,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAKA,MAAI,KAAK,UAAU,wBAAwB;AAIzC,UAAM,gBAAgB,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACnE,UAAM,aAAa,CAAC,QAAwB;AAE1C,UAAI,KAAK;AACT,UAAI,KAAK,cAAc,SAAS;AAChC,UAAI,OAAO;AACX,aAAO,MAAM,IAAI;AACf,cAAM,MAAO,KAAK,MAAO;AACzB,YAAI,cAAc,GAAG,EAAG,SAAS,KAAK;AACpC,iBAAO;AACP,eAAK,MAAM;AAAA,QACb,OAAO;AACL,eAAK,MAAM;AAAA,QACb;AAAA,MACF;AACA,aAAO,QAAQ,IAAI,cAAc,IAAI,EAAG,MAAM;AAAA,IAChD;AAEA,UAAM,qBAAqB;AAC3B,uBAAmB,YAAY;AAC/B,QAAI;AACJ,YAAQ,MAAM,mBAAmB,KAAK,IAAI,OAAO,MAAM;AACrD,YAAM,QAAQ,IAAI,CAAC;AACnB,YAAM,MAAM,IAAI,QAAQ,MAAM;AAE9B,UAAI,WAAW,IAAI,KAAK,KAAK,IAAK;AAClC,UAAI,cAAc,KAAK,GAAG;AACxB;AACA,gBAAQ,KAAK;AAAA,UACX,IAAI,QAAQ,YAAY;AAAA,UACxB,UAAU;AAAA,UACV,MAAM;AAAA,UACN;AAAA,UACA,QAAQ,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ,MAAM,MAAM,EAAE;AAAA,UAClD,OAAO,IAAI;AAAA,UACX;AAAA,UACA,UAAU;AAAA,UACV,QAAQ,kBAAkB,qBAAqB,KAAK;AAAA,QACtD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAA6C,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE;AAC7F,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,QAAQ,IAAI,aAAa,EAAE,QAAQ,CAAC;AAE/F,QAAM,UAAuB,CAAC;AAC9B,MAAI,UAAU;AACd,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,SAAS,SAAS;AAC1B,cAAQ,KAAK,KAAK;AAClB,gBAAU,MAAM;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE,WAAW,QAAQ,EAAE,WAAW;AAAA,IACvF,SAAS;AAAA,IACT,WAAW,KAAK,IAAI;AAAA,IACpB,YAAY,KAAK,OAAO,YAAY,IAAI,IAAI,SAAS,GAAG,IAAI;AAAA,EAC9D;AACF;AAEO,SAAS,gBAAgB,MAAc,SAA8B;AAC1E,SAAO,uBAAuB,MAAM,OAAO,EAAE;AAC/C;AASA,IAAM,wBAAwB;AAOvB,SAAS,uBACd,MACA,SACA,eAAuB,gBAAgB,UAAU,GAChC;AACjB,QAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE,WAAW,QAAQ;AACtF,QAAM,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAE/D,QAAM,aAAa,oBAAI,IAAoB;AAE3C,QAAM,eAAe,oBAAI,IAAoB;AAC7C,QAAM,UAAU,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAChE,aAAW,SAAS,SAAS;AAC3B,UAAM,MAAM,yBAAyB,GAAG,MAAM,EAAE,IAAI,MAAM,KAAK,IAAI,cAAc,qBAAqB;AACtG,iBAAa,IAAI,MAAM,IAAI,GAAG;AAC9B,eAAW,IAAI,KAAK,MAAM,KAAK;AAAA,EACjC;AAGA,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,aAAa,IAAI,MAAM,EAAE;AACrC,aAAS,OAAO,MAAM,GAAG,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM,MAAM,GAAG;AAAA,EACtE;AAEA,SAAO,EAAE,cAAc,QAAQ,WAAW;AAC5C;;;ACtWA,SAAS,gBAAAC,eAAc,iBAAAC,gBAAe,aAAAC,YAAW,cAAAC,mBAAkB;AACnE,SAAS,eAAe;AAGjB,IAAM,gBAAN,MAAoB;AAAA,EACjB,UAAmC,oBAAI,IAAI;AAAA,EAClC;AAAA,EAEjB,YAAY,UAAkB;AAC5B,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,OAAyB;AAC5B,SAAK,QAAQ,IAAI,MAAM,IAAI,EAAE,GAAG,MAAM,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,IAA+B;AACjC,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,MAAiC;AACzC,eAAW,SAAS,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,QAAQ,GAAG;AACxD,UAAI,MAAM,iBAAiB,KAAM,QAAO;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,QAAQ,IAAkB;AAC7B,UAAM,MAAM,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,QAAQ;AAC/C,WAAO,IAAI,MAAM,GAAG,KAAK;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,IAAqB;AAC1B,WAAO,KAAK,QAAQ,OAAO,EAAE;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,UAAM,MAAM,QAAQ,KAAK,QAAQ;AACjC,QAAI,CAACA,YAAW,GAAG,GAAG;AACpB,MAAAD,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AACA,UAAM,OAAO,KAAK,UAAU,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,GAAG,MAAM,CAAC;AAC/D,IAAAD,eAAc,KAAK,UAAU,MAAM,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAa;AACX,QAAI,CAACE,YAAW,KAAK,QAAQ,EAAG;AAChC,QAAI;AACF,YAAM,MAAMH,cAAa,KAAK,UAAU,OAAO;AAC/C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAK,QAAQ,MAAM;AACnB,iBAAW,SAAS,QAAQ;AAC1B,aAAK,QAAQ,IAAI,MAAM,IAAI,KAAK;AAAA,MAClC;AAAA,IACF,QAAQ;AAEN,WAAK,QAAQ,MAAM;AAAA,IACrB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,MAAM,OAAgC;AAC3C,WAAO,IAAI,IAAI,MAAM,UAAU;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAAQ,KAAsC;AACnD,WAAO,CAAC,GAAG,IAAI,QAAQ,CAAC;AAAA,EAC1B;AACF;;;AC7HA,SAAS,cAAAI,aAAY,aAAAC,YAAW,gBAAAC,eAAc,iBAAAC,sBAAqB;AACnE,SAAS,QAAAC,OAAM,eAAe;AAC9B,SAAS,kBAAkB;AAI3B,IAAM,kBAAkB;AACxB,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,aAAa;AAKZ,SAAS,aAAa,SAA0B;AACrD,QAAM,OAAO,WAAW,QAAQ,IAAI;AACpC,SAAO,QAAQ,MAAM,eAAe;AACtC;AAQO,SAAS,WAAW,KAAsB;AAC/C,QAAM,YAAY,aAAa,GAAG;AAElC,MAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,IAAAC,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AAGA,QAAM,aAAaC,MAAK,WAAW,WAAW;AAC9C,MAAI,CAACF,YAAW,UAAU,GAAG;AAC3B,UAAM,SAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,WAAW;AAAA,IACb;AACA,IAAAG,eAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAAA,EACpE;AAGA,QAAM,UAAUD,MAAK,WAAW,iBAAiB;AACjD,MAAI,CAACF,YAAW,OAAO,GAAG;AACxB,IAAAG,eAAc,SAAS,MAAM,OAAO;AAAA,EACtC;AAGA,QAAM,YAAYD,MAAK,WAAW,cAAc;AAChD,MAAI,CAACF,YAAW,SAAS,GAAG;AAC1B,IAAAG,eAAc,WAAW,IAAI,OAAO;AAAA,EACtC;AAGA,QAAM,YAAYD,MAAK,WAAW,UAAU;AAC5C,MAAI,CAACF,YAAW,SAAS,GAAG;AAC1B,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAClD,UAAM,QAAQ,MAAM,MAAM,GAAG,CAAC;AAC9B,UAAM,YAAuB,EAAE,OAAO,WAAW,GAAG,cAAc,MAAM;AACxE,IAAAG;AAAA,MACE;AAAA,MACA,KAAK,UAAU,EAAE,GAAG,WAAW,MAAM,OAAO,UAAU,qBAAqB,SAAS,EAAE,GAAG,MAAM,CAAC;AAAA,MAChG;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,WAAW,KAA8B;AACvD,QAAM,YAAY,aAAa,GAAG;AAClC,QAAM,aAAaD,MAAK,WAAW,WAAW;AAE9C,MAAI,CAACF,YAAW,UAAU,GAAG;AAC3B,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AAEA,MAAI;AACF,UAAM,MAAMI,cAAa,YAAY,OAAO;AAC5C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAAA,EACxC,QAAQ;AACN,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AACF;AAiBA,IAAM,oBAAoB;AAE1B,SAAS,iBAAyB;AAChC,SAAO,QAAQ,IAAI,uBAAuB,KAAK;AACjD;AAEA,SAAS,qBAAqB,MAA0E;AACtG,QAAM,UAAU,KAAK,UAAU,EAAE,OAAO,KAAK,OAAO,WAAW,KAAK,WAAW,cAAc,KAAK,aAAa,CAAC;AAChH,SAAO,WAAW,UAAU,eAAe,CAAC,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC5E;AAEA,SAAS,oBAAoB,MAA8F;AACzH,MAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,SAAO,KAAK,aAAa,qBAAqB,IAAI;AACpD;AAUO,SAAS,UAAU,KAAyB;AACjD,QAAM,YAAY,aAAa,GAAG;AAClC,QAAM,YAAYC,MAAK,WAAW,UAAU;AAE5C,QAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAClD,QAAM,eAAe,MAAM,MAAM,GAAG,CAAC;AAErC,MAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,WAAO,EAAE,OAAO,cAAc,WAAW,GAAG,cAAc,MAAM;AAAA,EAClE;AAEA,MAAI;AACF,UAAM,MAAMC,cAAa,WAAW,OAAO;AAC3C,UAAM,OAAO,KAAK,MAAM,GAAG;AAG3B,QAAI,KAAK,QAAQ,CAAC,KAAK,OAAO;AAC5B,YAAM,aAAa,KAAK;AACxB,aAAO,EAAE,OAAO,cAAc,WAAW,GAAG,cAAc,KAAK,gBAAgB,WAAW;AAAA,IAC5F;AAGA,QAAI,CAAC,oBAAoB,EAAE,OAAO,KAAK,OAAO,WAAW,KAAK,WAAW,cAAc,KAAK,cAAc,UAAU,KAAK,SAAS,CAAC,GAAG;AACpI,cAAQ,OAAO,MAAM,mFAAmF;AACxG,aAAO,EAAE,OAAO,cAAc,WAAW,GAAG,cAAc,KAAK,gBAAgB,MAAM;AAAA,IACvF;AAGA,QAAI,KAAK,UAAU,cAAc;AAC/B,aAAO,EAAE,OAAO,cAAc,WAAW,GAAG,cAAc,KAAK,gBAAgB,MAAM;AAAA,IACvF;AACA,WAAO,EAAE,OAAO,KAAK,OAAO,WAAW,KAAK,WAAW,cAAc,KAAK,aAAa;AAAA,EACzF,QAAQ;AACN,WAAO,EAAE,OAAO,cAAc,WAAW,GAAG,cAAc,MAAM;AAAA,EAClE;AACF;AAEO,SAAS,UAAU,OAAkB,KAAoB;AAC9D,QAAM,YAAY,aAAa,GAAG;AAClC,MAAI,CAACD,YAAW,SAAS,GAAG;AAC1B,IAAAE,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACA,QAAM,YAAYH,MAAK,WAAW,UAAU;AAC5C,QAAM,WAAW,qBAAqB,KAAK;AAC3C,EAAAI,eAAc,WAAW,KAAK,UAAU,EAAE,GAAG,OAAO,SAAS,GAAG,MAAM,CAAC,GAAG,OAAO;AACnF;AAOA,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAS9B,SAAS,kBAAkB,KAAa,QAAyB;AAC/D,MAAI,IAAI,SAAS,uBAAwB,QAAO;AAEhD,QAAM,cAAc,IAAI,MAAM,OAAO,MAAM;AAE3C,QAAM,aAAa,QAAQ,IAAI,yBAAyB;AACxD,MAAI,YAAY;AAEd,UAAM,iBAAiB,YAAY,YAAY,GAAG;AAClD,QAAI,mBAAmB,GAAI,QAAO;AAClC,UAAM,UAAU,YAAY,MAAM,GAAG,cAAc;AACnD,UAAM,eAAe,YAAY,MAAM,iBAAiB,CAAC;AACzD,QAAI,CAAC,WAAW,CAAC,aAAc,QAAO;AACtC,QAAI,CAAC,sBAAsB,KAAK,OAAO,EAAG,QAAO;AACjD,UAAM,eAAe,WAAW,UAAU,UAAU,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAC/F,WAAO,iBAAiB;AAAA,EAC1B;AAGA,SAAO,sBAAsB,KAAK,WAAW;AAC/C;AAEO,SAAS,aAA0B;AACxC,QAAM,MAAM,QAAQ,IAAI,sBAAsB,KAAK;AACnD,MAAI,IAAI,WAAW,UAAU,KAAK,kBAAkB,KAAK,UAAU,EAAG,QAAO;AAC7E,MAAI,IAAI,WAAW,UAAU,KAAK,kBAAkB,KAAK,UAAU,EAAG,QAAO;AAC7E,SAAO;AACT;AAGO,SAAS,sBACd,MACA,UACa;AACb,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,MAAO,QAAO;AAC3B,SAAO;AACT;AAEO,SAAS,cAAc,MAA6E;AACzG,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,kBAAkB,UAAU,oBAAoB,SAAS;AAAA,IACpE,KAAK;AACH,aAAO,EAAE,kBAAkB,UAAU,oBAAoB,GAAG;AAAA,IAC9D,KAAK;AAAA,IACL;AACE,aAAO,EAAE,kBAAkB,KAAM,oBAAoB,GAAG;AAAA,EAC5D;AACF;;;AClPA,SAAS,gBAAgB,cAAAC,aAAY,gBAAAC,eAAc,aAAAC,kBAAiB;AACpE,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AA0BvB,SAAS,gBAAgB,OAAmB,KAAoB;AACrE,QAAM,YAAY,aAAa,GAAG;AAClC,QAAM,YAAYC,MAAK,WAAW,WAAW;AAE7C,QAAM,SAASC,SAAQ,SAAS;AAChC,MAAI,CAACC,YAAW,MAAM,GAAG;AACvB,IAAAC,WAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AAEA,QAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,iBAAe,WAAW,MAAM,OAAO;AACzC;AAKO,SAAS,iBACd,WACA,MACA,oBACA,gBACA,aACA,WACY;AACZ,SAAO;AAAA,IACL,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,aAAa,UAA4B,CAAC,GAAiB;AACzE,QAAM,EAAE,OAAO,IAAI,IAAI;AACvB,QAAM,YAAY,aAAa,GAAG;AAClC,QAAM,YAAYH,MAAK,WAAW,WAAW;AAE7C,MAAI,CAACE,YAAW,SAAS,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,MAAME,cAAa,WAAW,OAAO;AAC3C,QAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEnD,MAAI,UAAwB,CAAC;AAC7B,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,cAAQ,KAAK,KAAK,MAAM,IAAI,CAAe;AAAA,IAC7C,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,OAAO,WAAW;AACxB,QAAM,EAAE,mBAAmB,IAAI,cAAc,IAAI;AAEjD,MAAI,uBAAuB,UAAU;AACnC,UAAM,SAAS,KAAK,IAAI,IAAI,qBAAqB,KAAK,KAAK,KAAK;AAChE,cAAU,QAAQ,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAA,EAC3E;AAGA,UAAQ,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AAGxF,MAAI,SAAS,QAAQ,GAAG;AACtB,cAAU,QAAQ,MAAM,GAAG,KAAK;AAAA,EAClC;AAEA,SAAO;AACT;AAOO,SAAS,WAAW,SAA+B;AACxD,SAAO,KAAK,UAAU,SAAS,MAAM,CAAC;AACxC;AAKO,SAAS,UAAU,SAA+B;AACvD,QAAM,UAAU;AAChB,QAAM,OAAO,QAAQ;AAAA,IAAI,CAAC,MACxB;AAAA,MACE,EAAE;AAAA,MACF,EAAE;AAAA,MACF,IAAI,EAAE,KAAK,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9B,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,IACJ,EAAE,KAAK,GAAG;AAAA,EACZ;AACA,SAAO,CAAC,SAAS,GAAG,IAAI,EAAE,KAAK,IAAI;AACrC;AAKO,SAAS,WAAW,SAA+B;AACxD,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAQ,QAAQ,IAAI,CAAC,MAAM;AAC/B,UAAM,OAAO,IAAI,KAAK,EAAE,SAAS,EAAE,eAAe;AAClD,WAAO,IAAI,IAAI,KAAK,EAAE,IAAI,MAAM,EAAE,kBAAkB,cAAc,EAAE,cAAc,sBAAsB,EAAE,WAAW,MAAM,EAAE,SAAS;AAAA,EACxI,CAAC;AAED,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,YAAY,SAAuB,SAAkC,QAAgB;AACnG,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,WAAW,OAAO;AAAA,IAC3B,KAAK;AACH,aAAO,UAAU,OAAO;AAAA,IAC1B,KAAK;AAAA,IACL;AACE,aAAO,WAAW,OAAO;AAAA,EAC7B;AACF;;;AC/JA,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,cAAAC,aAAY,aAAa;;;ACNlC,SAAS,kBAAkB;AAG3B,IAAM,eAAe,CAAC,iBAAiB,aAAa,gBAAgB;AAMpE,IAAM,eAAe,oBAAI,IAAY;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,SAAS,cAAc,GAA2B;AACvD,aAAW,KAAK,cAAc;AAC5B,UAAM,IAAI,EAAE,IAAI,OAAO,CAAC;AACxB,QAAI,KAAK,EAAE,SAAS,GAAG;AACrB,aAAO,EAAE,QAAQ,eAAe,EAAE,EAAE,KAAK;AAAA,IAC3C;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,YAAY,QAAwB;AAClD,SAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACtE;AAQO,IAAM,gBAAmC,OAAO,GAAG,SAAS;AACjE,MAAI,aAAa,IAAI,EAAE,IAAI,IAAI,GAAG;AAChC,WAAO,KAAK;AAAA,EACd;AACA,QAAM,MAAM,cAAc,CAAC;AAC3B,MAAI,CAAC,KAAK;AACR,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SACE;AAAA,QACJ;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,IAAE,IAAI,eAAe,YAAY,GAAG,CAAC;AACrC,SAAO,KAAK;AACd;;;ACrDA,IAAM,WAAW,oBAAI,IAA0B;AAMxC,SAAS,WAAW,MAA4B;AACrD,MAAI,IAAI,SAAS,IAAI,IAAI;AACzB,MAAI,CAAC,GAAG;AACN,QAAI;AAAA,MACF,aAAa,oBAAI,IAAI;AAAA,MACrB,YAAY,oBAAI,IAAI;AAAA,MACpB,WAAW,KAAK,IAAI;AAAA,MACpB,UAAU,KAAK,IAAI;AAAA,IACrB;AACA,aAAS,IAAI,MAAM,CAAC;AAAA,EACtB;AACA,IAAE,WAAW,KAAK,IAAI;AACtB,SAAO;AACT;AAGO,SAAS,eAAuB;AACrC,SAAO,SAAS;AAClB;;;AChCA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAE1B,IAAM,gBAAgB,UAAU,QAAQ;AAgBxC,IAAM,iBAAiB;AAEvB,eAAe,OAAO,MAAgB,KAA0C;AAC9E,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,MAAM;AAAA,MAClD;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AACD,UAAM,UAAU,OAAO,KAAK;AAC5B,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,eAAe,KAAqB;AAGlD,MAAI,kBAAkB,KAAK,GAAG,KAAK,CAAC,IAAI,SAAS,KAAK,GAAG;AACvD,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,GAAG;AACvB,QAAI,WAAW;AACf,QAAI,WAAW;AACf,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,eAAsB,kBAAkB,MAAc,QAAQ,IAAI,GAAwB;AAIxF,QAAM,aAAa,MAAM,OAAO,CAAC,aAAa,uBAAuB,GAAG,GAAG;AAC3E,MAAI,eAAe,OAAQ,QAAO,CAAC;AAEnC,QAAM,CAAC,QAAQ,QAAQ,GAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC9C,OAAO,CAAC,UAAU,WAAW,QAAQ,GAAG,GAAG;AAAA,IAC3C,OAAO,CAAC,aAAa,gBAAgB,MAAM,GAAG,GAAG;AAAA,IACjD,OAAO,CAAC,aAAa,MAAM,GAAG,GAAG;AAAA,EACnC,CAAC;AAED,QAAM,MAAkB,CAAC;AACzB,MAAI,OAAQ,KAAI,aAAa,eAAe,MAAM;AAGlD,MAAI,UAAU,WAAW,OAAQ,KAAI,aAAa;AAClD,MAAI,IAAK,KAAI,iBAAiB;AAC9B,SAAO;AACT;AAaA,IAAM,eAAe;AACrB,IAAM,QAAQ,oBAAI,IAAwB;AAE1C,eAAsB,wBACpB,MAAc,QAAQ,IAAI,GAC1B,MAAc,KAAK,IAAI,GACF;AACrB,QAAM,MAAM,MAAM,IAAI,GAAG;AACzB,MAAI,OAAO,IAAI,YAAY,IAAK,QAAO,IAAI;AAC3C,QAAM,QAAQ,MAAM,kBAAkB,GAAG;AACzC,QAAM,IAAI,KAAK,EAAE,OAAO,WAAW,MAAM,aAAa,CAAC;AACvD,SAAO;AACT;;;AC5GA,SAAS,cAAAC,aAAY,aAAAC,YAAW,iBAAAC,gBAAe,gBAAAC,eAAc,WAAW,gBAAgB;AACxF,SAAS,QAAAC,aAAY;AACrB,SAAS,WAAAC,gBAAe;AACxB,OAAO,cAAc;AACrB,OAAO,WAAW;AAElB,IAAMC,mBAAkB;AACxB,IAAMC,eAAc;AAOb,SAAS,4BAAoC;AAClD,SAAOH,MAAKC,SAAQ,GAAGC,gBAAe;AACxC;AAEO,SAAS,6BAAqC;AACnD,SAAOF,MAAK,0BAA0B,GAAGG,YAAW;AACtD;AAGO,SAAS,gBAAgB,KAAsB;AACpD,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,QAAQ,SAAS,GAAI,QAAO;AAChC,MAAI,CAAC,kBAAkB,KAAK,OAAO,EAAG,QAAO;AAC7C,SACE,QAAQ,WAAW,UAAU,KAC7B,QAAQ,WAAW,YAAY,KAC/B,QAAQ,WAAW,aAAa;AAEpC;AAMA,SAAS,mBAA2B;AAClC,MAAI,QAAQ,MAAM,MAAO,QAAO;AAChC,MAAI;AACF,UAAM,SAAmB,CAAC;AAC1B,UAAM,MAAM,OAAO,MAAM,IAAI;AAC7B,QAAI,YAAY;AAChB,OAAG;AACD,UAAI;AACF,oBAAY,SAAS,GAAG,KAAK,GAAG,IAAI,QAAQ,IAAI;AAAA,MAClD,QAAQ;AAEN,oBAAY;AAAA,MACd;AACA,UAAI,YAAY,EAAG,QAAO,KAAK,OAAO,KAAK,IAAI,SAAS,GAAG,SAAS,CAAC,CAAC;AAAA,IACxE,SAAS,cAAc,IAAI;AAC3B,WAAO,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO,EAAE,KAAK;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAQ,KAAqB;AACpC,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,QAAQ,UAAU,GAAI,QAAO;AACjC,SAAO,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,SAAI,OAAO,CAAC,CAAC,GAAG,QAAQ,MAAM,EAAE,CAAC;AACpE;AAGO,SAAS,6BAAmC;AACjD,QAAM,MAAM,QAAQ,IAAI,kBAAkB,GAAG,KAAK,KAAK;AACvD,QAAM,QAAQ,IAAI,SAAS,KAAK,gBAAgB,GAAG;AACnD,QAAM,MAAM,2BAA2B;AACvC,QAAM,KAAK,WAAW;AAEtB,MAAI,OAAO;AACT,YAAQ;AAAA,MACN,MAAM;AAAA,QACJ,qEAAqE,QAAQ,GAAG,CAAC;AAAA,MAEnF;AAAA,IACF;AAAA,EACF,WAAW,MAAM,gBAAgB,EAAE,GAAG;AACpC,YAAQ,MAAM,MAAM,KAAK,oCAAoC,GAAG,KAAK,QAAQ,EAAE,CAAC,GAAG,CAAC;AAAA,EACtF,OAAO;AACL,YAAQ,MAAM,MAAM,KAAK,mDAAmD,CAAC;AAAA,EAC/E;AACF;AAKO,SAAS,WAAW,KAAa,YAAoB,0BAA0B,GAAW;AAC/F,MAAI,CAACP,YAAW,SAAS,GAAG;AAC1B,IAAAC,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACA,QAAM,OAAOG,MAAK,WAAWG,YAAW;AAGxC,MAAI,WAAoC,CAAC;AACzC,MAAIP,YAAW,IAAI,GAAG;AACpB,QAAI;AACF,iBAAW,KAAK,MAAMG,cAAa,MAAM,OAAO,CAAC;AAAA,IACnD,QAAQ;AACN,iBAAW,CAAC;AAAA,IACd;AAAA,EACF;AACA,QAAM,OAAgC;AAAA,IACpC,GAAG;AAAA,IACH,SAAS,IAAI,KAAK;AAAA,IAClB,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,EACnC;AACA,EAAAD,eAAc,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AACrF,MAAI;AACF,cAAU,MAAM,GAAK;AAAA,EACvB,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGO,SAAS,gCAAgC,YAAoB,0BAA0B,GAG5F;AACA,QAAM,OAAOE,MAAK,WAAWG,YAAW;AACxC,MAAI,CAACP,YAAW,IAAI,EAAG,QAAO,EAAE,SAAS,OAAO,KAAK;AACrD,MAAI,WAAoC,CAAC;AACzC,MAAI;AACF,eAAW,KAAK,MAAMG,cAAa,MAAM,OAAO,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,EAAE,SAAS,OAAO,KAAK;AAAA,EAChC;AACA,QAAM,KAAK,SAAS;AACpB,QAAM,SAAS,OAAO,OAAO,YAAY,GAAG,KAAK,EAAE,SAAS;AAC5D,MAAI,CAAC,OAAQ,QAAO,EAAE,SAAS,OAAO,KAAK;AAE3C,SAAO,SAAS;AAChB,SAAO,SAAS;AAChB,EAAAD,eAAc,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AACzF,MAAI;AACF,cAAU,MAAM,GAAK;AAAA,EACvB,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,SAAS,MAAM,KAAK;AAC/B;AAMO,SAAS,WAAW,YAAoB,0BAA0B,GAAkB;AACzF,QAAM,OAAOE,MAAK,WAAWG,YAAW;AACxC,MAAI,CAACP,YAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,MAAMG,cAAa,MAAM,OAAO;AACtC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,OAAO,YAAY,UAAU;AACtC,YAAM,IAAI,OAAO,QAAQ,KAAK;AAC9B,UAAI,EAAE,SAAS,EAAG,QAAO;AAAA,IAC3B;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAWO,SAAS,+BAKd;AACA,QAAM,OAAO,QAAQ,IAAI,kBAAkB,KAAK,IAAI,KAAK;AACzD,MAAI,IAAI,SAAS,GAAG;AAClB,QAAI,CAAC,gBAAgB,GAAG,GAAG;AACzB,aAAO,EAAE,KAAK,MAAM,UAAU,OAAO,QAAQ,KAAK;AAAA,IACpD;AACA,WAAO,EAAE,KAAK,KAAK,UAAU,OAAO,QAAQ,MAAM;AAAA,EACpD;AACA,QAAM,UAAU,WAAW;AAC3B,MAAI,WAAW,gBAAgB,OAAO,GAAG;AACvC,WAAO,EAAE,KAAK,QAAQ,KAAK,GAAG,UAAU,MAAM,QAAQ,MAAM;AAAA,EAC9D;AACA,SAAO,EAAE,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,QAAQ,MAAM;AAChE;AAGO,SAAS,qCAAqC,KAAqB;AACxE,QAAM,UAAU,IAAI,KAAK;AACzB,QAAM,OAAO,WAAW,OAAO;AAC/B,UAAQ,IAAI,kBAAkB,IAAI;AAClC,SAAO;AACT;AAMA,eAAsB,oCAA4D;AAChF,MAAI,CAAC,QAAQ,MAAM,SAAS,CAAC,QAAQ,OAAO,MAAO,QAAO;AAC1D,QAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,MAAI;AACF,UAAM,QAAQ,MAAM,GAAG,SAAS,MAAM,KAAK,8BAA8B,CAAC,GAAG,KAAK;AAClF,WAAO,KAAK,SAAS,IAAI,OAAO;AAAA,EAClC,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAMA,eAAsB,6BAA4C;AAChE,QAAM,EAAE,KAAK,UAAU,OAAO,IAAI,6BAA6B;AAC/D,MAAI,QAAQ;AACV,YAAQ,MAAM,MAAM,IAAI,qFAAqF,CAAC;AAC9G,YAAQ;AAAA,MACN,MAAM,KAAK,kHAAwG;AAAA,IACrH;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,KAAK;AACP;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,YAAQ;AAAA,MACN,MAAM;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,MAAM;AAC9B,QAAM,WAAW,QAAQ,OAAO;AAChC,MAAI,CAAC,WAAW,CAAC,UAAU;AACzB,YAAQ,MAAM,MAAM,IAAI,sDAAsD,CAAC;AAC/E,YAAQ;AAAA,MACN,MAAM;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,MAAI;AACF,YAAQ,IAAI,MAAM,KAAK,4EAA4E,CAAC;AACpG,UAAM,WAAW,MAAM,GAAG,SAAS,MAAM,KAAK,+BAA+B,CAAC,GAAG,KAAK;AACtF,QAAI,CAAC,SAAS;AACZ,cAAQ,MAAM,MAAM,IAAI,0BAA0B,CAAC;AACnD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,QAAI,CAAC,gBAAgB,OAAO,GAAG;AAC7B,cAAQ,MAAM,MAAM,IAAI,0FAAgF,CAAC;AACzG,cAAQ,MAAM,MAAM,KAAK,4EAA4E,CAAC;AACtG,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,qCAAqC,OAAO;AACzD,YAAQ,IAAI,MAAM,MAAM,kBAAkB,GAAG,MAAM,KAAK,IAAI,CAAC;AAC7D,YAAQ,IAAI,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,CAAC;AAAA,EACjD,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AAEA,QAAM,YAAY,6BAA6B;AAC/C,MAAI,CAAC,UAAU,OAAO,UAAU,QAAQ;AACtC,YAAQ,MAAM,MAAM,IAAI,8EAA8E,CAAC;AACvG,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEO,SAAS,SAAS,OAAwB,CAAC,GAAW;AAC3D,QAAM,YACJ,KAAK,KAAK,KAAK,MACd,QAAQ,IAAI,kBAAkB,KAAK,IAAI,KAAK,KAC7C,iBAAiB;AAEnB,MAAI,CAAC,WAAW;AACd,YAAQ,MAAM,MAAM,IAAI,6BAA6B,CAAC;AACtD,YAAQ;AAAA,MACN,MAAM,KAAK,yCAAyC;AAAA,IACtD;AACA,YAAQ;AAAA,MACN,MAAM,KAAK,+CAA+C;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,gBAAgB,SAAS,GAAG;AAC/B,YAAQ,MAAM,MAAM,IAAI,oDAAoD,CAAC;AAC7E,YAAQ;AAAA,MACN,MAAM,KAAK,gFAAgF;AAAA,IAC7F;AACA,YAAQ;AAAA,MACN,MAAM,KAAK,4DAA4D;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,WAAW,WAAW,KAAK,SAAS;AACjD,UAAQ,IAAI,MAAM,MAAM,kBAAkB,GAAG,MAAM,KAAK,IAAI,CAAC;AAC7D,UAAQ,IAAI,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,EAAE,CAAC;AACjD,UAAQ,IAAI,MAAM,KAAK,8CAAyC,CAAC;AACjE,SAAO;AACT;;;ACtSO,SAAS,yBAAyB,GAAmC;AAC1E,SAAO;AAAA,IACL,MAAM,EAAE;AAAA,IACR,sBAAsB,EAAE;AAAA,IACxB,eAAe,EAAE;AAAA,IACjB,oBAAoB,EAAE;AAAA,IACtB,oBAAoB;AAAA,IACpB,0BAA0B;AAAA,IAC1B,gBAAgB,EAAE;AAAA,IAClB,cAAc;AAAA,IACd,WAAW;AAAA,EACb;AACF;AAIA,IAAM,2BAA2B;AACjC,IAAM,6BAA6B;AAU5B,SAAS,qBAAqB,cAA+B;AAClE,QAAM,OACJ,gBACA,QAAQ,IAAI,kBAAkB,KAC9B,0BACA,KAAK;AACP,MAAI,CAAC,KAAK;AACR,WAAO,yBAAyB,QAAQ,OAAO,EAAE;AAAA,EACnD;AACA,MAAI,aAAa;AACjB,MAAI,CAAC,gBAAgB,KAAK,UAAU,GAAG;AACrC,iBAAa,WAAW,UAAU;AAAA,EACpC;AACA,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,UAAU;AAC5B,UAAM,SACJ,kBAAkB,KAAK,EAAE,QAAQ,IAC7B,4BACA,EAAE;AACR,UAAM,OAAO,EAAE,aAAa,MAAM,KAAK,EAAE,SAAS,QAAQ,OAAO,EAAE;AACnE,WAAO,GAAG,MAAM,GAAG,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO,yBAAyB,QAAQ,OAAO,EAAE;AAAA,EACnD;AACF;AAMO,SAAS,aACd,eACA,cACQ;AACR,QAAM,OAAO,qBAAqB,YAAY;AAC9C,QAAM,OAAO,cAAc,QAAQ,QAAQ,EAAE;AAC7C,SAAO,GAAG,IAAI,YAAY,IAAI;AAChC;AAEO,SAAS,yBAAiC;AAC/C,QAAM,MAAM,QAAQ,IAAI,yBAAyB,GAAG,KAAK;AACzD,MAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,GAAG,EAAG,QAAO;AACvC,QAAM,IAAI,SAAS,KAAK,EAAE;AAC1B,SAAO,KAAK,IAAI,KAAK,IAAI,GAAG,GAAK,GAAG,IAAO;AAC7C;AAEA,SAAS,YAA2B;AAClC,QAAM,UAAU,QAAQ,IAAI,kBAAkB,GAAG,KAAK;AACtD,MAAI,QAAS,QAAO;AACpB,QAAM,WAAW,WAAW;AAC5B,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,IAAI,SAAS,KAAK;AACxB,SAAO,EAAE,SAAS,IAAI,IAAI;AAC5B;AAGO,SAAS,oBAAmC;AACjD,SAAO,UAAU;AACnB;AAIA,IAAI,mBAA4C;AAEhD,IAAI,0BAA0B;AAG9B,IAAM,4BAA4B;AAE3B,SAAS,sBAA+C;AAC7D,SAAO;AACT;AAEO,SAAS,uBAA6B;AAC3C,qBAAmB;AACnB,4BAA0B;AAC5B;AAMO,SAAS,wBAAwB,oBAAkC;AACxE,MAAI,CAAC,oBAAoB,sBAAsB,EAAG;AAClD,mBAAiB,iBAAiB;AAClC,MAAI,iBAAiB,uBAAuB,IAAI;AAC9C,qBAAiB,qBAAqB,KAAK;AAAA,MACzC;AAAA,MACA,iBAAiB,qBAAqB;AAAA,IACxC;AAAA,EACF;AACF;AAIA,SAAS,6BACP,MACA,SAC0B;AAC1B,QAAM,MAAM,IAAI,MAAM,OAAO;AAC7B,MAAI,OAAO;AACX,SAAO;AACT;AAgBA,eAAsB,YACpB,OAII,CAAC,GAC6B;AAClC,QAAM,sBAAsB,KAAK,wBAAwB;AACzD,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,aACJ,qBAAqB,QACrB,MAAM,0BAA0B;AAClC,MAAI,CAAC,KAAK,SAAS,YAAY;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,aAAa,eAAe;AAChD,QAAM,YAAY,uBAAuB;AACzC,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,QAAQ;AACX,QAAI,qBAAqB;AACvB,YAAM,MAAM,IAAI,MAAM,oCAAoC;AAG1D,UAAI,OAAO;AACX,yBAAmB;AACnB,gCAA0B;AAC1B,YAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,aAAa;AAAA,MACpC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,MAAM;AAAA,MACjC;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,WAAW;AAAA,IACrB,CAAC;AAED,QAAI,KAAK,WAAW,OAAO,KAAK,WAAW,KAAK;AAC9C,YAAM,MAAO,MAAM,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAI/C,YAAM,MACJ,OAAO,IAAI,YAAY,WACnB,IAAI,UACJ;AACN,YAAM,MAAM,IAAI,MAAM,GAAG;AACzB,UAAI,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AACrD,yBAAmB;AACnB,gCAA0B;AAC1B,YAAM;AAAA,IACR;AAEA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,MAAM,8BAA8B,KAAK,MAAM,SAAS,WAAW;AACzE,UAAI,qBAAqB;AACvB,2BAAmB;AACnB,kCAA0B;AAC1B,cAAM,6BAA6B,yBAAyB,GAAG;AAAA,MACjE;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI;AACF,aAAQ,MAAM,KAAK,KAAK;AAAA,IAC1B,QAAQ;AACN,UAAI,qBAAqB;AACvB,2BAAmB;AACnB,kCAA0B;AAC1B,cAAM;AAAA,UACJ;AAAA,UACA,qBAAqB,WAAW;AAAA,QAClC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,KAAK,UAAU,aAAa,KAAK,UAAU,OAAO;AAC3D,YAAM,MAAM,IAAI,MAAM,sBAAsB;AAC5C,UAAI,OAAO;AACX,yBAAmB;AACnB,gCAA0B;AAC1B,YAAM;AAAA,IACR;AAEA,uBAAmB;AACnB,8BAA0B,KAAK,IAAI;AACnC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QACG,IAAkC,SAAS,iBAC3C,IAAkC,SAAS,iBAC3C,IAAkC,SAAS,qBAC3C,IAAkC,SAAS,gBAC3C,IAAkC,SAAS,kBAC3C,IAAkC,SAAS,qBAC3C,IAAkC,SAAS,yBAC3C,IAAkC,SAAS,yBAC5C;AACA,YAAM;AAAA,IACR;AACA,QAAI,qBAAqB;AACvB,YAAM,MACH,IAAc,SAAS,eACpB,mBAAmB,SAAS,eAAe,WAAW,qCACtD,gCAAgC,WAAW,KAAM,IAAc,OAAO;AAC5E,yBAAmB;AACnB,gCAA0B;AAC1B,YAAM,6BAA6B,uBAAuB,GAAG;AAAA,IAC/D;AACA,QAAI,KAAK,SAAS;AAChB,cAAQ,OAAO;AAAA,QACb,yCAA0C,IAAc,OAAO;AAAA;AAAA,MACjE;AAAA,IACF;AACA,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AACF;AAKA,eAAsB,kBACpB,OAA8B,CAAC,GACD;AAC9B,QAAM,aAAa,aAAa,eAAe;AAC/C,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,uBAAuB,CAAC;AAE3E,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,YAAY;AAAA,MACnC,QAAQ;AAAA,MACR,SAAS,EAAE,eAAe,UAAU,MAAM,GAAG;AAAA,MAC7C,QAAQ,WAAW;AAAA,IACrB,CAAC;AAED,QAAI,CAAC,KAAK,GAAI,QAAO;AACrB,WAAQ,MAAM,KAAK,KAAK;AAAA,EAC1B,SAAS,KAAK;AACZ,QAAI,KAAK,SAAS;AAChB,cAAQ,OAAO;AAAA,QACb,0CAA2C,IAAc,OAAO;AAAA;AAAA,MAClE;AAAA,IACF;AACA,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AACF;AAWA,eAAsB,iBAGnB;AACD,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,EAAG,QAAO,EAAE,SAAS,KAAK;AAE/B,MAAI,EAAE,uBAAuB,MAAM,EAAE,sBAAsB,GAAG;AAC5D,UAAM,QAAQ,MAAM,YAAY,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,IAAI;AACjE,UAAM,QAAQ,SAAS;AACvB,QAAI,MAAM,uBAAuB,MAAM,MAAM,sBAAsB,GAAG;AACpE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,mCAAmC,MAAM,aAAa,IAAI,MAAM,oBAAoB;AAAA,MAC9F;AAAA,IACF;AACA,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACA,SAAO,EAAE,SAAS,KAAK;AACzB;;;ACtUA,eAAsB,UACpB,OACA,SACe;AACf,QAAM,UAAU,QAAQ,QAAQ,KAAK,KAAK;AAC1C,QAAM,WAAW,aAAa,OAAO,OAAO;AAC5C,QAAM,EAAE,QAAQ,UAAU,OAAO,YAAY,uBAAuB,EAAE,IAAI;AAC1E,MAAI,CAAC,OAAQ;AAEb,QAAM,SAAS,QAAQ,cAAe,MAAM,wBAAwB,QAAQ,GAAG;AAQ/E,QAAM,OAAO;AAAA,IACX,GAAG;AAAA,IACH,GAAG;AAAA,IACH,iBAAiB,OAAO;AAAA,IACxB,YAAY,OAAO;AAAA,IACnB,YAAY,OAAO;AAAA,EACrB;AAEA,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAC5D,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,UAAU;AAAA,MACjC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,MAAM;AAAA,MACjC;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,QAAQ,WAAW;AAAA,IACrB,CAAC;AACD,QAAI,CAAC,KAAK,MAAM,SAAS;AACvB,cAAQ,OAAO,MAAM,8BAA8B,KAAK,MAAM;AAAA,CAAI;AAAA,IACpE;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,SAAS;AACX,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,OAAO,MAAM,iCAAiC,GAAG;AAAA,CAAI;AAAA,IAC/D;AAAA,EACF,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AACF;;;AC9FA,OAAOK,YAAW;AAEX,SAAS,6BAA6B,MAAoB;AAC/D,QAAM,OAAO,oBAAoB,IAAI;AACrC,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,KAAK,gEAA4C,CAAC;AACzE,UAAQ,IAAIA,OAAM,KAAK,wEAAwE,CAAC;AAChG,UAAQ;AAAA,IACNA,OAAM,MAAM,mDAAmD;AAAA,EACjE;AACA,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,8CAA8C,CAAC;AACtE,UAAQ,IAAIA,OAAM,MAAM,4CAA4C,CAAC;AACrE,UAAQ,IAAI;AACZ,UAAQ;AAAA,IACNA,OAAM,KAAK,uDAAuD;AAAA,EACpE;AACA,UAAQ,IAAIA,OAAM,MAAM,8BAA8B,IAAI,GAAG,CAAC;AAC9D,UAAQ,IAAIA,OAAM,MAAM,6BAA6B,IAAI,EAAE,CAAC;AAC5D,UAAQ,IAAIA,OAAM,MAAM,0BAA0B,IAAI,KAAK,CAAC;AAC5D,UAAQ,IAAIA,OAAM,MAAM,0BAA0B,IAAI,SAAS,CAAC;AAChE,UAAQ,IAAIA,OAAM,MAAM,sBAAsB,IAAI,EAAE,CAAC;AACrD,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,iDAAiD,CAAC;AACzE,UAAQ,IAAIA,OAAM,MAAM,2CAA2C,CAAC;AACpE,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,KAAK,0CAAsB,CAAC;AACnD,UAAQ;AAAA,IACNA,OAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,UAAQ;AAAA,IACNA,OAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,UAAQ,IAAIA,OAAM,MAAM,iBAAiB,CAAC;AAC1C,UAAQ;AAAA,IACNA,OAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,UAAQ;AAAA,IACNA,OAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,UAAQ,IAAI;AACd;;;ACjDA,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,qBAAqB;AAE9B,IAAI,SAAwB;AAErB,SAAS,eAAuB;AACrC,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,mBAAmB,YAAY,GAAG;AACtD,UAAM,MAAMA,cAAa,cAAc,GAAG,GAAG,OAAO;AACpD,aAAU,KAAK,MAAM,GAAG,EAA2B,WAAW;AAAA,EAChE,QAAQ;AACN,aAAS;AAAA,EACX;AACA,SAAO;AACT;;;ARwCA,IAAI,mCAAmC;AAEvC,SAAS,6BAA6B,SAAwB;AAC5D,MAAI,CAAC,QAAS;AAEd,QAAM,MAAM,0BAA0B;AACtC,MAAI;AAEJ,QAAM,iCAAiC,MAAY;AACjD,UAAM,KAAK,WAAW;AACtB,QAAI,CAAC,IAAI;AACP,UAAI,iCAAkC;AACtC,yCAAmC;AACnC,aAAO,QAAQ,IAAI,kBAAkB;AACrC,2BAAqB;AACrB,UAAI;AACF,gBAAQ,OAAO;AAAA,UACb;AAAA;AAAA,QAEF;AAAA,MACF,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AACA,QAAI,kCAAkC;AACpC,yCAAmC;AACnC,2BAAqB;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,WAAW,MAAY;AAC3B,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,gCAAgC,GAAG;AAAA,EAChE;AAEA,MAAI;AACF,QAAI,CAACC,YAAW,GAAG,EAAG;AACtB,UAAM,KAAK,MAAM;AACf,eAAS;AAAA,IACX,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;AAIA,SAAS,oBAA4B;AAAE,SAAO,QAAQ,IAAI,wBAAwB,KAAK;AAA6B;AACpH,SAAS,iBAAyB;AAAE,SAAO,QAAQ,IAAI,qBAAqB,KAAK;AAA0B;AAC3G,SAAS,iBAAyB;AAAE,SAAO,QAAQ,IAAI,qBAAqB,KAAK;AAA6C;AAC9H,SAAS,iBAAyB;AAAE,SAAO,QAAQ,IAAI,qBAAqB,KAAK;AAA0B;AAE3G,SAAS,eAAe,MAAsB;AAE5C,MAAI,KAAK,WAAW,cAAc,EAAG,QAAO,kBAAkB;AAE9D,MACE,KAAK,WAAW,sBAAsB,KACtC,KAAK,WAAW,iBAAiB,KACjC,KAAK,WAAW,eAAe,GAC/B;AACA,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,KAAK,WAAW,UAAU,KAAK,KAAK,WAAW,YAAY,EAAG,QAAO,eAAe;AAExF,MAAI,KAAK,WAAW,WAAW,KAAK,KAAK,WAAW,eAAe,EAAG,QAAO,eAAe;AAE5F,SAAO,kBAAkB;AAC3B;AAEA,SAAS,eAAe,MAAsB;AAC5C,MAAI,KAAK,WAAW,cAAc,EAAG,QAAO;AAC5C,MACE,KAAK,WAAW,sBAAsB,KACtC,KAAK,WAAW,iBAAiB,KACjC,KAAK,WAAW,eAAe,GAC/B;AACA,WAAO;AAAA,EACT;AACA,MAAI,KAAK,WAAW,UAAU,KAAK,KAAK,WAAW,YAAY,EAAG,QAAO;AACzE,MAAI,KAAK,WAAW,WAAW,KAAK,KAAK,WAAW,eAAe,EAAG,QAAO;AAC7E,SAAO;AACT;AAGA,SAAS,mCAAmC,SAAuC;AACjF,QAAM,OAAO,oBAAI,IAAI,CAAC,sBAAsB,gBAAgB,CAAC;AAC7D,aAAW,KAAK,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,GAAG;AACzC,QAAI,KAAK,IAAI,EAAE,YAAY,CAAC,EAAG,QAAO,QAAQ,CAAC;AAAA,EACjD;AACF;AAIA,SAAS,YAAY,MAAuC;AAC1D,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO,KAAK,QAAQ,MAAM,SAAU,OAAM,KAAK,KAAK,QAAQ,CAAC;AACjE,MAAI,MAAM,QAAQ,KAAK,UAAU,CAAC,GAAG;AACnC,eAAW,OAAO,KAAK,UAAU,GAAgC;AAC/D,UAAI,OAAO,IAAI,SAAS,MAAM,SAAU,OAAM,KAAK,IAAI,SAAS,CAAC;AAAA,eACxD,MAAM,QAAQ,IAAI,SAAS,CAAC,GAAG;AACtC,mBAAW,SAAS,IAAI,SAAS,GAAgC;AAC/D,cAAI,MAAM,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM,MAAM,SAAU,OAAM,KAAK,MAAM,MAAM,CAAC;AAAA,QAC7F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAWA,SAAS,kBAAkB,MAA2B;AACpD,QAAM,SAAsB,CAAC;AAC7B,QAAM,KAAK;AACX,MAAI;AACJ,UAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,WAAO,KAAK;AAAA,MACV,MAAM,EAAE,CAAC,KAAK;AAAA,MACd,UAAU,EAAE,CAAC,KAAK;AAAA,MAClB,OAAO,EAAE;AAAA,MACT,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;AAAA,IACtB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAc,QAAqB,cAAgC;AAC5F,MAAI,SAAS;AAEb,WAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,UAAM,QAAQ,OAAO,CAAC;AACtB,UAAM,cAAc,aAAa,CAAC,KAAK,MAAM;AAC7C,UAAM,OAAO,MAAM,YAAY;AAC/B,aAAS,OAAO,MAAM,GAAG,MAAM,KAAK,IAAI,QAAQ,OAAO,OAAO,cAAc,QAAQ,OAAO,MAAM,MAAM,GAAG;AAAA,EAC5G;AACA,SAAO;AACT;AAIA,SAAS,YACP,MACA,WACyB;AACzB,QAAM,cAAc,CAAC,QAA0B;AAC7C,QAAI,OAAO,QAAQ,SAAU,QAAO,UAAU,GAAG;AACjD,QAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,WAAW;AAClD,QAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,YAAM,MAAM;AACZ,aAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;AAAA,IACpF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,YAAY,IAAI;AACzB;AAWA,IAAM,QAAoB;AAAA,EACxB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,WAAW,KAAK,IAAI;AACtB;AAIA,SAAS,oBAA4B;AACnC,QAAM,QAAQ,UAAU;AACxB,MAAI,CAAC,MAAM,aAAc,QAAO;AAChC,QAAM,QAAQ,IAAI,KAAK,MAAM,YAAY,EAAE,QAAQ;AACnD,SAAO,KAAK,OAAO,KAAK,IAAI,IAAI,UAAU,KAAK,KAAK,KAAK,IAAK;AAChE;AAEA,SAAS,kBAAkB,QAAsB;AAC/C,UAAQ,OAAO;AAAA,IACb;AAAA,qBAAwB,MAAM;AAAA;AAAA;AAAA;AAAA,EAEhC;AACF;AAYO,SAAS,YAAY,OAAqB,CAAC,GAAmB;AACnE,QAAM,SAAyB,EAAE,GAAG,gBAAgB,GAAG,KAAK,OAAO;AACnE,QAAM,QAAQ,KAAK,SAAS,IAAI,cAAc,GAAG,OAAO,SAAS,mBAAmB;AACpF,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,MAAM,IAAI,KAAe;AAK/B,MAAI,IAAI,KAAK,aAAa;AAG1B,MAAI;AAAA,IAAI;AAAA,IAAK,CAAC,MACZ,EAAE,KAAK;AAAA,MACL,MAAM;AAAA,MACN,SAAS,aAAa;AAAA,MACtB,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,SAAS;AAAA,QACT,eAAe;AAAA,QACf,cAAc;AAAA,QACd,cAAc;AAAA,QACd,WAAW;AAAA,MACb;AAAA,MACA,WAAW,CAAC,cAAc,cAAc,UAAU,MAAM,QAAQ,MAAM,QAAQ,MAAM;AAAA,MACpF,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAGA,MAAI;AAAA,IAAI;AAAA,IAAW,CAAC,MAClB,EAAE,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,aAAa;AAAA,MACtB,QAAQ,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,aAAa,GAAI;AAAA,MACxD,OAAO;AAAA,QACL,mBAAmB,MAAM;AAAA,QACzB,oBAAoB,MAAM;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI;AAAA,IAAI;AAAA,IAAU,CAAC,MACjB,EAAE,KAAK;AAAA,MACL,GAAG;AAAA,MACH,WAAW,MAAM;AAAA,MACjB,gBAAgB,aAAa;AAAA,IAC/B,CAAC;AAAA,EACH;AAGA,MAAI,IAAI,UAAU,CAAC,MAAM;AACvB,UAAM,QAAQ,SAAS,EAAE,IAAI,MAAM,OAAO,KAAK,IAAI;AACnD,WAAO,EAAE,KAAK,MAAM,KAAK,KAAK,CAAC;AAAA,EACjC,CAAC;AAGD,MAAI,IAAI,MAAM,OAAO,MAAM;AACzB,QAAI,EAAE,IAAI,WAAW,QAAQ;AAE3B,YAAMC,YAAW,EAAE,IAAI,OAAO,qBAAqB,KAAK,eAAe,EAAE,IAAI,IAAI;AACjF,YAAM,MAAMA,YAAW,EAAE,IAAI;AAC7B,YAAMC,WAAkC,CAAC;AACzC,QAAE,IAAI,IAAI,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,QAAAA,SAAQ,CAAC,IAAI;AAAA,MAAG,CAAC;AACvD,aAAOA,SAAQ,MAAM;AACrB,MAAAA,SAAQ,MAAM,IAAI,IAAI,IAAID,SAAQ,EAAE;AACpC,yCAAmCC,QAAO;AAC1C,YAAM,OAAO,MAAM,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,QAAQ,SAAAA,SAAQ,CAAC;AAC/D,aAAO,IAAI,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,QAAQ,SAAS,OAAO,YAAY,KAAK,QAAQ,QAAQ,CAAC,EAAE,CAAC;AAAA,IAC7G;AAEA,UAAM,eAAe,YAAY,IAAI;AAGrC,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,EAAE,IAAI,KAA8B;AAAA,IACnD,QAAQ;AACN,aAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,SAAS,oBAAoB,EAAE,GAAG,GAAG;AAAA,IACzF;AAEA,QAAI,CAAC,QAAQ,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAC3C,aAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,SAAS,qBAAqB,EAAE,GAAG,GAAG;AAAA,IAC1F;AAEA,UAAM,YAAY,OAAO,EAAE;AAC3B,UAAM,WAAW,EAAE,IAAI,OAAO,qBAAqB,KAAK,eAAe,EAAE,IAAI,IAAI;AACjF,UAAM,WAAW,eAAe,EAAE,IAAI,IAAI;AAE1C,QAAI,kCAAkC;AACpC,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SACE;AAAA,UACJ;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,uBAAuB,kBAAkB;AAC/C,QAAI,CAAC,sBAAsB;AACzB,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SACE;AAAA,UACJ;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,YAAY,EAAE,SAAS,OAAO,OAAO,qBAAqB,KAAK,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,YAAM,OAAQ,IAAkC,QAAQ;AACxD,YAAM,MAAO,IAAc;AAC3B,YAAM,iBAAiB,oBAAI,IAAI;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,eAAe,IAAI,IAAI,GAAG;AAC5B,eAAO,EAAE;AAAA,UACP,EAAE,OAAO,EAAE,MAAM,uBAAuB,MAAM,SAAS,IAAI,EAAE;AAAA,UAC7D;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,yBAAyB,SAAS,yBAAyB;AACtE,eAAO,EAAE;AAAA,UACP,EAAE,OAAO,EAAE,MAAM,+BAA+B,MAAM,SAAS,IAAI,EAAE;AAAA,UACrE;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,gBAAgB;AAC3B,eAAO,EAAE;AAAA,UACP,EAAE,OAAO,EAAE,MAAM,yBAAyB,MAAM,SAAS,IAAI,EAAE;AAAA,UAC/D;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE;AAAA,QACP,EAAE,OAAO,EAAE,MAAM,uBAAuB,SAAS,IAAI,EAAE;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAMA,UAAM,WAAW,EAAE,IAAI,aAAa;AACpC,UAAM,UAAU,WAAW,QAAQ;AAKnC,UAAM,OAAoB;AAAA,MACxB,oBAAoB,GAAG;AAAA,MACvB,WAAW;AAAA,IACb;AACA,UAAM,EAAE,iBAAiB,IAAI,cAAc,IAAI;AAC/C,UAAM,QAAQ,UAAU;AAExB,QAAI,SAAS,UAAU,MAAM,aAAa,kBAAkB;AAC1D,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,mCAAmC,gBAAgB;AAAA,UAC9D;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBAAgB,MAAM,eAAe;AAC3C,QAAI,CAAC,cAAc,SAAS;AAC1B,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,cAAc,UAAU;AAAA,UACnC;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,UAAU,oBAAoB;AACpC,QAAI,SAAS,eAAe,aAAa;AACvC,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SACE;AAAA,UACJ;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,YAAY,IAAI;AACjC,UAAM,aAAaC,MAAY,QAAQ;AACvC,UAAM,iBAAiB,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAE5E,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,uBAAuB,eAAe;AAG5C,UAAI,SAAS,QAAQ;AACnB,0BAAkB,GAAG,eAAe,MAAM,oFAAoF;AAAA,MAChI;AAEA,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,oBAAoB,eAAe,MAAM,+BAA+B,CAAC,GAAG,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,UAC7I;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBAAgB,YAAY,MAAM,CAAC,SAAS,gBAAgB,MAAM,WAAW,OAAO,CAAC;AAM3F,UAAM,cAAc,oBAAI,IAAoB;AAC5C,QAAI,gBAAgB;AAEpB,UAAM,cAAc,YAAY,eAAe,CAAC,SAAS;AACvD,YAAM,SAAS,kBAAkB,IAAI;AAErC,UAAI,OAAO,WAAW,GAAG;AACvB,cAAM,OAAO,eAAe,IAAI;AAChC,cAAM,SAAS,OAAO,MAAM,IAAI;AAChC,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,KAAK;AAC/B,sBAAY,IAAI,GAAG,CAAC;AACpB,kBAAQ,YAAY,IAAI,GAAG,CAAC;AAC5B,kBAAQ,WAAW,IAAI,GAAG,CAAC;AAAA,QAC7B;AACA,yBAAiB,OAAO,MAAM;AAC9B,eAAO,OAAO;AAAA,MAChB;AAEA,YAAM,gBAA0B,CAAC;AACjC,iBAAW,SAAS,QAAQ;AAC1B,cAAM,SAAS,OAAO,MAAM,MAAM,MAAM,QAAQ;AAChD,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,KAAK;AAC/B,sBAAY,IAAI,GAAG,CAAC;AACpB,kBAAQ,YAAY,IAAI,GAAG,CAAC;AAC5B,kBAAQ,WAAW,IAAI,GAAG,CAAC;AAAA,QAC7B;AACA,yBAAiB,OAAO,MAAM;AAC9B,sBAAc,KAAK,OAAO,WAAW;AAAA,MACvC;AAEA,aAAO,kBAAkB,MAAM,QAAQ,aAAa;AAAA,IACtD,CAAC;AAGD,UAAM,aAAa;AACnB,cAAU,KAAK;AAMf,UAAM,oBAAoB,QAAQ,IAAI,6BAA6B,MAAM;AACzE,QAAI,wBAAwB,CAAC,mBAAmB;AAC9C,WAAK;AAAA,QACH;AAAA,UACE,YAAY;AAAA,UACZ,qBAAqB;AAAA,UACrB,iBAAiB,eAAe;AAAA,UAChC,cAAc;AAAA,UACd,aAAa,aAAa;AAAA,QAC5B;AAAA,QACA,EAAE,QAAQ,sBAAsB,QAAQ;AAAA,MAC1C;AACA,8BAAwB,aAAa;AAAA,IACvC;AAGA,UAAM,mBAAmB,KAAK,MAAM,mBAAmB,GAAG;AAC1D,QAAI,SAAS,UAAU,MAAM,aAAa,oBAAoB,MAAM,YAAY,gBAAgB,kBAAkB;AAChH,wBAAkB,GAAG,MAAM,SAAS,IAAI,gBAAgB,uCAAuC;AAAA,IACjG;AAGA,QAAI,SAAS,UAAU,kBAAkB,KAAK,GAAG;AAC/C,wBAAkB,+GAA+G;AAAA,IACnI;AAGA,UAAM,QAAoB;AAAA,MACxB,IAAI;AAAA,MACJ,cAAc;AAAA,MACd,YAAY,CAAC,GAAG,YAAY,QAAQ,CAAC;AAAA,MACrC,WAAW,KAAK,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ;AACA,UAAM,KAAK,KAAK;AAChB,UAAM;AACN,UAAM,sBAAsB;AAG5B,UAAM,YAAY,KAAK,OAAO,YAAY,IAAI,IAAI,gBAAgB,GAAG,IAAI;AACzE;AAAA,MACE,iBAAiB,WAAW,iBAAiB,eAAe,eAAe,QAAQ,UAAU,SAAS;AAAA,IACxG;AAEA,QAAI,WAAW,gBAAgB,GAAG;AAChC,cAAQ,OAAO,MAAM,cAAc,aAAa,+BAA+B,SAAS;AAAA,CAAI;AAAA,IAC9F;AAGA,UAAM,UAAkC,CAAC;AACzC,MAAE,IAAI,IAAI,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,cAAQ,CAAC,IAAI;AAAA,IAAG,CAAC;AACvD,WAAO,QAAQ,MAAM;AACrB,WAAO,QAAQ,gBAAgB;AAC/B,YAAQ,MAAM,IAAI,IAAI,IAAI,QAAQ,EAAE;AACpC,YAAQ,uBAAuB,IAAI;AACnC,uCAAmC,OAAO;AAE1C,UAAM,cAAc,KAAK,UAAU,WAAW;AAE9C,QAAI;AACJ,QAAI;AACF,qBAAe,MAAM,MAAM,WAAW,EAAE,IAAI,MAAM;AAAA,QAChD,QAAQ;AAAA,QACR,SAAS,EAAE,GAAG,SAAS,gBAAgB,oBAAoB,kBAAkB,OAAO,OAAO,WAAW,WAAW,CAAC,EAAE;AAAA,QACpH,MAAM;AAAA,MACR,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,SAAS,oCAAoC,EAAE,GAAG,GAAG;AAAA,IACjH;AAGA,QAAI,KAAK,QAAQ,MAAM,MAAM;AAC3B,YAAM,mBAAmB,IAAI,IAAI,WAAW;AAC5C,YAAMF,YAAW,aAAa;AAC9B,UAAI,CAACA,aAAY,kBAAkB,GAAG;AAEpC,eAAO,IAAI,SAASA,WAAU;AAAA,UAC5B,QAAQ,aAAa;AAAA,UACrB,SAAS;AAAA,YACP,gBAAgB,aAAa,QAAQ,IAAI,cAAc,KAAK;AAAA,YAC5D,iBAAiB;AAAA,YACjB,yBAAyB;AAAA,YACzB,wBAAwB;AAAA,YACxB,wBAAwB,OAAO,aAAa;AAAA,UAC9C;AAAA,QACF,CAAC;AAAA,MACH;AAGA,YAAM,UAAU,IAAI,YAAY;AAChC,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,SAAS;AAEb,YAAM,YAAY,IAAI,gBAAwC;AAAA,QAC5D,UAAU,OAAO,YAAY;AAC3B,oBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,gBAAM,QAAQ,OAAO,MAAM,IAAI;AAE/B,mBAAS,MAAM,IAAI,KAAK;AAExB,qBAAW,QAAQ,OAAO;AACxB,gBAAI,KAAK,WAAW,QAAQ,KAAK,SAAS,gBAAgB;AACxD,kBAAI;AACF,sBAAM,OAAO,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AAErC,sBAAM,WAAW,YAAY,MAAM,CAAC,SAAS,QAAQ,MAAM,gBAAgB,CAAC;AAC5E,2BAAW,QAAQ,QAAQ,OAAO,SAAS,KAAK,UAAU,QAAQ,CAAC;AAAA,CAAI,CAAC;AAAA,cAC1E,QAAQ;AAEN,2BAAW,QAAQ,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,cAChD;AAAA,YACF,OAAO;AACL,yBAAW,QAAQ,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,YAChD;AAAA,UACF;AAAA,QACF;AAAA,QACA,MAAM,YAAY;AAChB,cAAI,OAAO,SAAS,GAAG;AACrB,uBAAW,QAAQ,QAAQ,OAAO,MAAM,CAAC;AAAA,UAC3C;AAAA,QACF;AAAA,MACF,CAAC;AAED,YAAM,iBAAiBA,UAAS,YAAY,SAAS;AACrD,aAAO,IAAI,SAAS,gBAAgB;AAAA,QAClC,QAAQ,aAAa;AAAA,QACrB,SAAS;AAAA,UACP,gBAAgB,aAAa,QAAQ,IAAI,cAAc,KAAK;AAAA,UAC5D,iBAAiB;AAAA,UACjB,yBAAyB;AAAA,UACzB,wBAAwB;AAAA,UACxB,wBAAwB,OAAO,aAAa;AAAA,UAC5C,8BAA8B;AAAA,QAChC;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,aAAa,IAAI,IAAI,WAAW;AACtC,QAAI;AACJ,QAAI;AACF,iBAAY,MAAM,aAAa,KAAK;AAAA,IACtC,QAAQ;AACN,aAAO,IAAI,SAAS,MAAM;AAAA,QACxB,QAAQ,aAAa;AAAA,QACrB,SAAS;AAAA,UACP,wBAAwB;AAAA,UACxB,wBAAwB,OAAO,aAAa;AAAA,QAC9C;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,eAAe,YAAY,UAAU,CAAC,SAAS;AACnD,YAAM,SAAS,kBAAkB,IAAI;AACrC,UAAI,OAAO,WAAW,EAAG,QAAO,QAAQ,MAAM,UAAU;AACxD,YAAM,iBAAiB,OAAO,IAAI,CAAC,MAAM,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpE,aAAO,kBAAkB,MAAM,QAAQ,cAAc;AAAA,IACvD,CAAC;AAED,MAAE,OAAO,yBAAyB,SAAS;AAC3C,MAAE,OAAO,wBAAwB,MAAM;AACvC,MAAE,OAAO,wBAAwB,OAAO,aAAa,CAAC;AACtD,WAAO,EAAE,KAAK,cAAc,aAAa,MAAa;AAAA,EACxD,CAAC;AAED,SAAO;AACT;AAOA,SAAS,gBAAgB,MAAgC;AACvD,SAAO,IAAI,QAAQ,CAACG,aAAY;AAC9B,UAAM,SAAS,aAAa,EACzB,KAAK,SAAS,MAAMA,SAAQ,KAAK,CAAC,EAClC,KAAK,aAAa,MAAM;AACvB,aAAO,KAAK,SAAS,MAAMA,SAAQ,IAAI,CAAC,EAAE,MAAM;AAAA,IAClD,CAAC,EACA,OAAO,MAAM,WAAW;AAAA,EAC7B,CAAC;AACH;AAMA,eAAsB,kBAAkB,WAAmB,cAAc,IAAqB;AAC5F,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAM,YAAY,YAAY;AAC9B,QAAI,YAAY,KAAK,YAAY,MAAO;AAExC,QAAI,MAAM,gBAAgB,SAAS,EAAG,QAAO;AAAA,EAC/C;AACA,QAAM,IAAI;AAAA,IACR,oCAAoC,SAAS,IAAI,YAAY,cAAc,CAAC;AAAA,EAE9E;AACF;AAIO,SAAS,WAAW,OAAyC,CAAC,GAAS;AAC5E,QAAM,gBAAgB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,eAAe;AACvE,QAAM,MAAM,YAAY,IAAI;AAE5B,QAAM,YAAY;AAChB,UAAM,sCAAsC,CAAC,CAAE,QAAQ,IAAI,kBAAkB,GAAG,KAAK;AAErF,UAAM,eAAe,kBAAkB;AAEvC,QAAI,CAAC,gBAAgB,CAAC,gBAAgB,YAAY,GAAG;AACnD,cAAQ,OAAO;AAAA,QACb;AAAA;AAAA;AAAA,MAEF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,cAAc,QAAQ,QAAQ,MAAM,SAAS,QAAQ,OAAO,KAAK;AAGvE,eAAS;AACP,UAAI;AACF,cAAM,aAAa,MAAM,YAAY;AAAA,UACnC,OAAO;AAAA,UACP,SAAS,KAAK;AAAA,UACd,qBAAqB;AAAA,QACvB,CAAC;AACD,YAAI,CAAC,YAAY;AACf,kBAAQ,OAAO;AAAA,YACb;AAAA;AAAA,UACF;AACA,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,cAAM,OAAO,WAAW,QAAQ;AAChC,cAAM,YACJ,WAAW,uBAAuB,KAAK,cAAc,OAAO,WAAW,kBAAkB;AAC3F,gBAAQ,OAAO;AAAA,UACb,qCAAqC,IAAI,WACtC,WAAW,mBAAmB,KAAK,WAAW,gBAAgB,MAAM,MACrE,WAAM,SAAS;AAAA;AAAA,QACnB;AACA;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,OAAQ,IAAkC;AAChD,cAAM,MAAO,IAAc;AAE3B,YAAI,SAAS,yBAAyB,SAAS,yBAAyB;AACtE,kBAAQ,OAAO,MAAM,sBAAsB,GAAG;AAAA,CAAW;AACzD,kBAAQ,OAAO,MAAM;AAAA,CAAwF;AAC7G,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,YAAI,SAAS,gBAAgB;AAC3B,kBAAQ,OAAO,MAAM,sBAAsB,GAAG;AAAA,CAAW;AACzD,kBAAQ,OAAO,MAAM;AAAA,CAA6E;AAClG,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,cAAM,gBACJ,SAAS,qBACT,SAAS,iBACT,SAAS,iBACT,SAAS,gBACT,SAAS;AAEX,YAAI,iBAAiB,aAAa;AAChC,kBAAQ,OAAO,MAAM,sBAAsB,GAAG;AAAA,CAAW;AACzD,kBAAQ,OAAO;AAAA,YACb;AAAA;AAAA,UACF;AACA,cAAI,UAAyB;AAC7B,qBAAS;AACP,sBAAU,MAAM,kCAAkC;AAClD,gBAAI,CAAC,SAAS;AACZ,sBAAQ,OAAO,MAAM;AAAA,CAAsD;AAC3E,sBAAQ,KAAK,CAAC;AAAA,YAChB;AACA,gBAAI,gBAAgB,OAAO,EAAG;AAC9B,oBAAQ,OAAO;AAAA,cACb;AAAA;AAAA,YACF;AAAA,UACF;AACA,gBAAM,YAAY,qCAAqC,OAAO;AAC9D,kBAAQ,OAAO,MAAM,uCAAuC,SAAS;AAAA,CAAW;AAChF,+BAAqB;AACrB;AAAA,QACF;AAEA,YACE,SAAS,iBACT,SAAS,iBACT,SAAS,qBACT,SAAS,gBACT,SAAS,mBACT;AACA,kBAAQ,OAAO,MAAM,sBAAsB,GAAG;AAAA,CAAW;AACzD,kBAAQ,OAAO,MAAM;AAAA,CAA0E;AAC/F,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,gBAAQ,OAAO,MAAM,sBAAsB,GAAG;AAAA,CAAW;AACzD,gBAAQ,OAAO,MAAM;AAAA,CAAyF;AAC9G,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,iCAA6B,CAAC,mCAAmC;AAEjE,UAAM,aAA0B;AAAA,MAC9B,oBAAoB,GAAG;AAAA,MACvB,WAAW;AAAA,IACb;AAEA,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,kBAAkB,eAAe,EAAE;AAAA,IAClD,SAAS,KAAK;AACZ,cAAQ,OAAO,MAAM,sBAAuB,IAAc,OAAO;AAAA,CAAW;AAC5E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,SAAS,eAAe;AAC1B,cAAQ,OAAO;AAAA,QACb,2BAA2B,aAAa,4BAA4B,IAAI;AAAA;AAAA,MAC1E;AAAA,IACF;AAEA,iCAA6B,IAAI;AAEjC,UAAM,EAAE,OAAO,IAAI,OAAO,KAAK,GAAG,MAAM;AACtC,YAAM,UAAU,OAAO,IAAI;AAC3B,cAAQ,OAAO,MAAM;AAAA,oBACP,aAAa,CAAC,MAAM,WAAW,YAAY,CAAC;AAAA;AAAA;AAAA,+BAGjC,OAAO;AAAA,+BACP,OAAO;AAAA,+BACP,OAAO;AAAA;AAAA;AAAA,0CAGI,OAAO;AAAA,uCACV,OAAO;AAAA,uCACP,OAAO;AAAA,mCACX,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAQzC;AAEK,kBAAY,MAAM;AAChB,YAAI,iCAAkC;AACtC,YAAI,CAAC,kBAAkB,EAAG;AAC1B,aAAK,YAAY;AAAA,UACf,OAAO;AAAA,UACP,SAAS,KAAK;AAAA,UACd,qBAAqB;AAAA,QACvB,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACnB,GAAG,GAAM;AAAA,IACX,CAAC;AAAA,EACH,GAAG;AACL;;;AS74BA,OAAOC,YAAW;AAUlB,IAAM,cAA+C;AAAA,EACnD,MAAM,EAAE,kBAAkB,KAAM,cAAc,KAAM,OAAO,GAAG,eAAe,WAAW;AAAA,EACxF,KAAK,EAAE,kBAAkB,KAAQ,cAAc,KAAQ,OAAO,IAAI,eAAe,iBAAiB;AAAA,EAClG,YAAY;AAAA,IACV,kBAAkB,OAAO;AAAA,IACzB,cAAc,OAAO;AAAA,IACrB,OAAO,OAAO;AAAA,IACd,eAAe;AAAA,EACjB;AACF;AAEO,SAAS,cAAc,MAA+B;AAC3D,SAAO,YAAY,IAAI;AACzB;AAEA,SAAS,IAAI,GAAmB;AAC9B,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,EAAE,eAAe,OAAO;AACjC;AAMO,SAAS,iBAAiB,cAAsB,eAA6B;AAClF,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,cAAc,IAAI;AACjC,QAAM,QAAQ,UAAU;AAGxB,MAAI,SAAS,cAAc;AACzB,YAAQ,OAAO;AAAA,MACbC,OAAM,KAAK;AAAA,IAAO,YAAY,WAAW,aAAa;AAAA;AAAA,CAAiD;AAAA,IACzG;AACA;AAAA,EACF;AAEA,QAAM,OAAO,MAAM;AACnB,QAAM,MAAM,OAAO;AACnB,QAAM,MAAM,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK,MAAO,OAAO,MAAO,GAAG,CAAC,IAAI;AAGtE,QAAM,WAAW,OAAO,KAAKA,OAAM,OAAO,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,IAAIA,OAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE;AAEjH,UAAQ,OAAO;AAAA,IACb;AAAA,IAAOA,OAAM,KAAK,eAAe,QAAQ,CAAC,KAAKA,OAAM,KAAK,gBAAgB,YAAY,CAAC,iBACzEA,OAAM,KAAK,KAAK,YAAY,CAAC,CAAC,iCAA8B,QAAQ,KAAK,GAAG;AAAA;AAAA,EAC5F;AAEA,MAAI,SAAS,QAAQ;AACnB,QAAI,OAAO,IAAI;AACb,cAAQ,OAAO;AAAA,QACbA,OAAM,OAAO,mDAA8CA,OAAM,KAAK,kBAAkB,CAAC;AAAA;AAAA,CAAM;AAAA,MACjG;AAAA,IACF,OAAO;AACL,cAAQ,OAAO;AAAA,QACbA,OAAM,KAAK,SAASA,OAAM,KAAK,iBAAiB,CAAC,iBAAiBA,OAAM,KAAK,kBAAkB,CAAC;AAAA;AAAA,CAAwB;AAAA,MAC1H;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,OAAO,MAAM,IAAI;AAAA,EAC3B;AACF;;;ACpEA,OAAOC,YAAW;AAElB,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWnB,IAAM,WAAW;AAEjB,SAAS,cAAuB;AAC9B,MAAI,QAAQ,IAAI,uBAAuB,IAAK,QAAO;AACnD,MAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAClC,MAAI,QAAQ,IAAI,GAAI,QAAO;AAC3B,SAAO;AACT;AAEA,SAAS,KAAK,MAAsB;AAIlC,MAAI;AACF,WAAOA,OAAM,IAAI,QAAQ,EAAE,IAAI;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAoB;AAClC,MAAI,CAAC,YAAY,EAAG;AACpB,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,aAAW,QAAQ,OAAO;AACxB,YAAQ,OAAO,MAAM,KAAK,IAAI,IAAI,IAAI;AAAA,EACxC;AACA,UAAQ,OAAO,MAAM,IAAI;AAC3B;;;AC7CA,OAAOC,YAAW;AAUlB,IAAM,aAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,KAAK;AAAA,EACL,YAAY;AACd;AAEA,SAASC,KAAI,GAAmB;AAC9B,MAAI,MAAM,MAAM,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAC5C,SAAO,EAAE,eAAe,OAAO;AACjC;AAEA,eAAsB,YAA2B;AAG/C,MAAI,SAAS,MAAM,kBAAkB;AACrC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,YAAY,EAAE,OAAO,KAAK,CAAC;AAC3C,QAAI,GAAG,OAAO;AACZ,eAAS,yBAAyB,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,QAAQ;AACV,UAAM,OAAO,OAAO;AACpB,UAAMC,aACJ,SAAS,eACLC,OAAM,UAAU,MAAM,KAAK,cAAc,IACzC,SAAS,QACPA,OAAM,OAAO,MAAM,KAAK,OAAO,IAC/BA,OAAM,OAAO,MAAM,KAAK,QAAQ;AAExC,UAAMC,SAAkB,CAAC;AACzB,IAAAA,OAAM,KAAK,EAAE;AACb,IAAAA,OAAM,KAAK,GAAGD,OAAM,KAAK,UAAU,CAAC,IAAIA,OAAM,KAAK,IAAI,aAAa,CAAC,EAAE,CAAC,KAAKD,UAAS,KAAKC,OAAM,MAAM,UAAU,CAAC,EAAE;AACpH,IAAAC,OAAM,KAAK,EAAE;AACb,IAAAA,OAAM,KAAK,kBAAkBD,OAAM,KAAK,IAAI,CAAC,EAAE;AAC/C,IAAAC,OAAM,KAAK,kBAAkBH,KAAI,OAAO,aAAa,CAAC,MAAMA,KAAI,OAAO,oBAAoB,CAAC,aAAa;AACzG,IAAAG,OAAM,KAAK,kBAAkBH,KAAI,OAAO,kBAAkB,CAAC,EAAE;AAC7D,IAAAG,OAAM,KAAK,kBAAkBH,KAAI,OAAO,kBAAkB,CAAC,cAAc;AACzE,IAAAG,OAAM,KAAK,kBAAkBH,KAAI,OAAO,wBAAwB,CAAC,UAAU;AAC3E,IAAAG,OAAM,KAAK,kBAAkB,OAAO,cAAc,WAAWD,OAAM,MAAM,QAAQ,IAAIA,OAAM,IAAI,SAAS,CAAC,EAAE;AAC3G,IAAAC,OAAM,KAAK,kBAAkB,IAAI,KAAK,OAAO,cAAc,EAAE,mBAAmB,CAAC,EAAE;AACnF,QAAI,OAAO,cAAc;AACvB,MAAAA,OAAM,KAAK,kBAAkB,IAAI,KAAK,OAAO,YAAY,EAAE,mBAAmB,CAAC,EAAE;AAAA,IACnF;AACA,IAAAA,OAAM,KAAK,EAAE;AAEb,QAAI,SAAS,QAAQ;AACnB,MAAAA,OAAM,KAAK,KAAKD,OAAM,KAAK,UAAU,CAAC,KAAKA,OAAM,KAAK,kBAAkB,CAAC,EAAE;AAC3E,MAAAC,OAAM,KAAK,EAAE;AAAA,IACf;AAEA,YAAQ,OAAO,MAAMA,OAAM,KAAK,IAAI,IAAI,IAAI;AAC5C;AAAA,EACF;AAGA,QAAM,OAAO,WAAW;AACxB,QAAM,aAAa,cAAc,IAAI;AACrC,QAAM,aAAa,cAAc,IAAI;AACrC,QAAM,QAAQ,UAAU;AAExB,QAAM,YACJ,SAAS,eACLD,OAAM,UAAU,MAAM,KAAK,cAAc,IACzC,SAAS,QACPA,OAAM,OAAO,MAAM,KAAK,OAAO,IAC/BA,OAAM,OAAO,MAAM,KAAK,QAAQ;AAExC,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,GAAGA,OAAM,KAAK,UAAU,CAAC,IAAIA,OAAM,KAAK,IAAI,aAAa,CAAC,EAAE,CAAC,KAAK,SAAS,KAAKA,OAAM,OAAO,WAAW,CAAC,EAAE;AACtH,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkBA,OAAM,KAAK,WAAW,IAAI,CAAC,CAAC,IAAIA,OAAM,KAAK,MAAM,WAAW,gBAAgB,GAAG,CAAC,EAAE;AAC/G,QAAM,KAAK,kBAAkBF,KAAI,MAAM,SAAS,CAAC,MAAMA,KAAI,WAAW,gBAAgB,CAAC,aAAa;AACpG,QAAM,KAAK,sBAAsBA,KAAI,WAAW,YAAY,CAAC,aAAa;AAC1E,QAAM,KAAK,sBAAsBA,KAAI,WAAW,KAAK,CAAC,EAAE;AACxD,QAAM,KAAK,kBAAkB,OAAO,SAAS,WAAW,kBAAkB,IAAI,GAAG,WAAW,kBAAkB,UAAU,WAAW,EAAE;AACrI,QAAM,KAAK,EAAE;AAEb,MAAI,SAAS,QAAQ;AACnB,UAAM,KAAK,KAAKE,OAAM,KAAK,UAAU,CAAC,KAAKA,OAAM,KAAK,kBAAkB,CAAC,EAAE;AAC3E,UAAM,KAAK,KAAKA,OAAM,KAAK,UAAU,CAAC,KAAKA,OAAM,KAAK,kBAAkB,CAAC,EAAE;AAC3E,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,UAAQ,OAAO,MAAM,MAAM,KAAK,IAAI,IAAI,IAAI;AAC9C;;;AClGA,OAAOE,YAAW;AAGlB,IAAM,cAAc;AAEb,SAAS,aAAmB;AACjC,QAAM,OAAO,WAAW;AAExB,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,EAAE;AACb,QAAM,KAAKC,OAAM,KAAK,KAAK,kBAAkB,CAAC;AAC9C,QAAM,KAAK,EAAE;AACb,QAAM,KAAKA,OAAM,KAAK,4TAAwD,CAAC;AAC/E,QAAM,KAAKA,OAAM,KAAK,iFAAwD,CAAC;AAC/E,QAAM,KAAKA,OAAM,KAAK,4TAAwD,CAAC;AAC/E,QAAM,KAAK,gCAAsBA,OAAM,KAAK,IAAI,CAAC,gBAAWA,OAAM,KAAK,KAAK,CAAC,eAAUA,OAAM,KAAK,KAAK,CAAC,iBAAY;AACpH,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAK,iFAAwD;AACnE,QAAM,KAAKA,OAAM,KAAK,4TAAwD,CAAC;AAC/E,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,KAAKA,OAAM,KAAK,eAAe,CAAC,IAAIA,OAAM,KAAK,KAAK,YAAY,CAAC,CAAC,EAAE;AAC/E,QAAM,KAAK,KAAKA,OAAM,KAAK,aAAa,CAAC,OAAOA,OAAM,KAAK,UAAU,WAAW,CAAC,EAAE;AACnF,QAAM,KAAK,EAAE;AACb,QAAM,KAAKA,OAAM,KAAK,wBAAwB,CAAC;AAC/C,QAAM,KAAKA,OAAM,KAAK,wEAAwE,CAAC;AAC/F,QAAM,KAAK,EAAE;AAEb,UAAQ,OAAO,MAAM,MAAM,KAAK,IAAI,IAAI,IAAI;AAC9C;;;AChCA,OAAOC,YAAW;AASlB,IAAMC,cAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,KAAK;AAAA,EACL,YAAY;AACd;AAEA,SAASC,KAAI,GAAmB;AAC9B,MAAI,MAAM,MAAM,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAC5C,SAAO,EAAE,eAAe,OAAO;AACjC;AAEA,SAAS,YAAY,MAAc,KAAa,QAAQ,IAAY;AAClE,MAAI,QAAQ,MAAM,CAAC,OAAO,SAAS,GAAG,KAAK,OAAO,EAAG,QAAOC,OAAM,MAAM,MAAM,IAAI,OAAO,KAAK,IAAI,GAAG;AACrG,QAAM,MAAM,KAAK,IAAI,GAAG,OAAO,GAAG;AAClC,QAAM,SAAS,KAAK,MAAM,MAAM,KAAK;AACrC,QAAM,MAAM,IAAI,OAAO,MAAM,IAAI,IAAI,OAAO,QAAQ,MAAM;AAC1D,QAAM,UAAU,OAAO,MAAMA,OAAM,OAAO,GAAG,IAAI,OAAO,IAAIA,OAAM,IAAI,GAAG,IAAIA,OAAM,MAAM,GAAG;AAC5F,SAAO,MAAM,UAAU;AACzB;AAEA,eAAsB,aAA4B;AAChD,MAAI,SAAS,MAAM,kBAAkB;AACrC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,YAAY,EAAE,OAAO,KAAK,CAAC;AAC3C,QAAI,GAAG,OAAO;AACZ,eAAS,yBAAyB,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,QAAQ;AACV,UAAMC,QAAO,OAAO;AACpB,UAAMC,OAAM,OAAO;AACnB,UAAMC,aAAY,OAAO;AACzB,UAAMC,OAAMF,OAAM,KAAKA,SAAQ,KAAK,KAAK,MAAOD,QAAOC,OAAO,GAAG,IAAI;AAErE,UAAMG,SAAkB,CAAC;AACzB,IAAAA,OAAM,KAAK,EAAE;AACb,IAAAA,OAAM,KAAKL,OAAM,KAAK,KAAK,oBAAoB,IAAI,OAAOA,OAAM,MAAM,UAAU,CAAC;AACjF,IAAAK,OAAM,KAAK,EAAE;AACb,IAAAA,OAAM,KAAK,kBAAkBL,OAAM,KAAK,OAAO,IAAI,CAAC,EAAE;AACtD,IAAAK,OAAM,KAAK,kBAAkB,IAAI,KAAK,OAAO,cAAc,EAAE,mBAAmB,CAAC,EAAE;AACnF,IAAAA,OAAM,KAAK,EAAE;AACb,IAAAA,OAAM,KAAK,kBAAkB,YAAYJ,OAAMC,IAAG,CAAC,KAAKH,KAAIE,KAAI,CAAC,MAAMF,KAAIG,IAAG,CAAC,EAAE;AACjF,IAAAG,OAAM,KAAK,kBAAkBD,IAAG,GAAG;AACnC,IAAAC,OAAM,KAAK,kBAAkBN,KAAII,UAAS,CAAC,EAAE;AAC7C,IAAAE,OAAM,KAAK,EAAE;AAEb,QAAI,OAAO,SAAS,UAAUH,SAAQ,MAAMD,SAAQC,OAAM,KAAK;AAC7D,MAAAG,OAAM,KAAKL,OAAM,OAAO,+EAA+E,CAAC;AACxG,MAAAK,OAAM,KAAK,EAAE;AAAA,IACf,WAAW,OAAO,SAAS,QAAQ;AACjC,MAAAA,OAAM,KAAKL,OAAM,KAAK,iDAAiD,CAAC;AACxE,MAAAK,OAAM,KAAK,EAAE;AAAA,IACf;AAEA,YAAQ,OAAO,MAAMA,OAAM,KAAK,IAAI,IAAI,IAAI;AAC5C;AAAA,EACF;AAGA,QAAM,OAAO,WAAW;AACxB,QAAM,SAAS,cAAc,IAAI;AACjC,QAAM,QAAQ,UAAU;AAExB,QAAM,OAAO,MAAM;AACnB,QAAM,MAAM,OAAO;AACnB,QAAM,YAAY,OAAO,SAAS,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,IAAI,OAAO;AAC1E,QAAM,MAAM,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,KAAK,MAAO,OAAO,MAAO,GAAG,IAAI;AAE/E,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,EAAE;AACb,QAAM,KAAKL,OAAM,KAAK,KAAK,oBAAoB,IAAI,OAAOA,OAAM,OAAO,WAAW,CAAC;AACnF,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkBA,OAAM,KAAKF,YAAW,IAAI,CAAC,CAAC,EAAE;AAC3D,QAAM,KAAK,kBAAkB,MAAM,KAAK,EAAE;AAC1C,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB,YAAY,MAAM,GAAG,CAAC,KAAKC,KAAI,IAAI,CAAC,MAAMA,KAAI,GAAG,CAAC,EAAE;AACjF,QAAM,KAAK,kBAAkB,GAAG,GAAG;AACnC,QAAM,KAAK,kBAAkBA,KAAI,SAAS,CAAC,EAAE;AAC7C,QAAM,KAAK,EAAE;AAEb,MAAI,SAAS,UAAU,OAAO,SAAS,GAAG,KAAK,QAAQ,MAAM,KAAK;AAChE,UAAM,KAAKC,OAAM,OAAO,+EAA+E,CAAC;AACxG,UAAM,KAAK,EAAE;AAAA,EACf,WAAW,SAAS,QAAQ;AAC1B,UAAM,KAAKA,OAAM,KAAK,iDAAiD,CAAC;AACxE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,UAAQ,OAAO,MAAM,MAAM,KAAK,IAAI,IAAI,IAAI;AAC9C;;;ACtGA,OAAOM,eAAc;AACrB,OAAOC,YAAW;AAIlB,eAAsB,UAAU,OAAgC,CAAC,GAAoB;AACnF,MAAI,CAAC,WAAW,GAAG;AACjB,YAAQ,IAAIC,OAAM,KAAK,iEAAiE,CAAC;AACzF,YAAQ,IAAIA,OAAM,KAAK,wEAAwE,CAAC;AAChG,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,KAAK,WAAW;AACnB,QAAI,CAAC,QAAQ,MAAM,SAAS,CAAC,QAAQ,OAAO,OAAO;AACjD,cAAQ,MAAMA,OAAM,IAAI,uDAAuD,CAAC;AAChF,cAAQ,MAAMA,OAAM,KAAK,iDAAiD,CAAC;AAC3E,aAAO;AAAA,IACT;AACA,UAAM,KAAKC,UAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,QAAI;AACF,YAAM,MAAM,MAAM,GAAG;AAAA,QACnBD,OAAM,KAAK,mEAAmE;AAAA,MAChF;AACA,YAAM,SAAS,IAAI,KAAK,EAAE,YAAY;AACtC,UAAI,WAAW,OAAO,WAAW,OAAO;AACtC,gBAAQ,IAAIA,OAAM,OAAO,mBAAmB,CAAC;AAC7C,eAAO;AAAA,MACT;AAAA,IACF,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAEA,QAAM,qBAAqB,CAAC,CAAE,QAAQ,IAAI,kBAAkB,GAAG,KAAK;AACpE,QAAM,EAAE,SAAS,KAAK,IAAI,gCAAgC;AAC1D,uBAAqB;AACrB,SAAO,QAAQ,IAAI,kBAAkB;AAErC,MAAI,SAAS;AACX,YAAQ,IAAIA,OAAM,MAAM,wCAAwC,GAAGA,OAAM,KAAK,IAAI,CAAC;AACnF,YAAQ,IAAIA,OAAM,KAAK,oGAAoG,CAAC;AAC5H,QAAI,oBAAoB;AACtB,cAAQ;AAAA,QACNA,OAAM;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AzB9CA;AACE,QAAM,QAAQ,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,GAAI,EAAE;AAC/D,MAAI,OAAO,MAAM,KAAK,KAAK,QAAQ,IAAI;AACrC,YAAQ,OAAO;AAAA,MACb,oDAAoD,QAAQ,SAAS,IAAI;AAAA;AAAA,IAC3E;AACA,YAAQ,OAAO,MAAM;AAAA,CAAiD;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAmCA,IAAM,UAAU,aAAa;AAU7B,IAAM,mBAAmB,KAAK,IAAI,GAAG,GAAG,KAAK,EAAE,MAAM;AAErD,IAAM,uBAAuB;AAI7B,IAAM,sBAAsB,CAAC,cAAc,cAAc,UAAU,MAAM,QAAQ,UAAU,QAAQ,MAAM;AAEzG,IAAM,uBAAuB,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,OAAO,OAAO,SAAS,OAAO,OAAO,KAAK,CAAC;AAG/H,IAAM,8BAA8B,oBAAI,IAAI;AAAA,EAC1C;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACnD;AAAA,EAAO;AAAA,EAAY;AAAA,EAAW;AAAA,EAC9B;AAAA,EAAe;AAAA,EAAS;AAAA,EAAQ;AAAA,EAChC;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAClD,CAAC;AAED,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,gBAAgB,UAA2B;AAClD,QAAM,MAAM,QAAQ,QAAQ,EAAE,YAAY;AAC1C,SACE,qBAAqB,IAAI,GAAG,KAC5B,4BAA4B,IAAI,GAAG,KACnC,oBAAoB,IAAI,SAAS,QAAQ,CAAC;AAE9C;AAEA,SAAS,iBAAiB,UAA2B;AACnD,SAAO,qBAAqB,IAAI,QAAQ,QAAQ,EAAE,YAAY,CAAC;AACjE;AAEA,SAAS,YAAY,UAA0B;AAC7C,QAAM,MAAM,QAAQ,QAAQ,EAAE,YAAY;AAC1C,QAAM,MAA8B;AAAA,IAClC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACA,SAAO,IAAI,GAAG,KAAK;AACrB;AAKA,SAAS,aAAa,OAA8B;AAClD,QAAM,OAAO,SAAS,OAAO,EAAE;AAC/B,MAAI,MAAM,IAAI,KAAK,KAAK,SAAS,MAAM,MAAM,KAAK,EAAG,QAAO;AAC5D,MAAI,OAAO,KAAK,OAAO,MAAO,QAAO;AACrC,SAAO;AACT;AAMA,SAAS,aAAa,UAA2B;AAC/C,MAAI;AACJ,MAAI;AACF,SAAK,SAAS,UAAU,GAAG;AAC3B,UAAM,MAAM,OAAO,MAAM,IAAI;AAC7B,UAAM,YAAYE,UAAS,IAAI,KAAK,GAAG,MAAM,CAAC;AAC9C,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,UAAI,IAAI,CAAC,MAAM,EAAG,QAAO;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,QAAI,OAAO,OAAW,WAAU,EAAE;AAAA,EACpC;AACF;AAMA,eAAe,kBAAkB,UAAoC;AACnE,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,OAAO,UAAU,GAAG;AACnC,UAAM,MAAM,OAAO,MAAM,IAAI;AAC7B,UAAM,EAAE,UAAU,IAAI,MAAM,OAAO,KAAK,KAAK,GAAG,MAAM,CAAC;AACvD,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,UAAI,IAAI,CAAC,MAAM,EAAG,QAAO;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,QAAI,OAAQ,OAAM,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACjD;AACF;AAMA,SAAS,iBAAiB,MAA6B;AACrD,QAAM,aAAa,KAAK,YAAY;AACpC,QAAM,UAAkC;AAAA,IACtC,IAAI;AAAA,IAAc,KAAK;AAAA,IACvB,IAAI;AAAA,IAAc,KAAK;AAAA,IACvB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AACA,QAAM,WAAW,QAAQ,UAAU,KAAK;AACxC,SAAO,oBAAoB,SAAS,QAAQ,IAAI,WAAW;AAC7D;AAEA,SAAS,aAAa,QAA0B;AAC9C,QAAM,MAAMC,SAAQ,MAAM;AAC1B,MAAI,CAACC,YAAW,GAAG,GAAG;AACpB,WAAO,CAAC;AAAA,EACV;AACA,QAAM,OAAO,SAAS,GAAG;AACzB,MAAI,KAAK,OAAO,EAAG,QAAO,CAAC,GAAG;AAE9B,QAAM,QAAkB,CAAC;AAEzB,WAAS,KAAK,KAAmB;AAC/B,QAAI;AACJ,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACpD,QAAQ;AAEN;AAAA,IACF;AACA,UAAM,WAAW,oBAAI,IAAI;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAWC,MAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,YAAY,GAAG;AACvB,YAAI,SAAS,IAAI,MAAM,IAAI,EAAG;AAC9B,aAAK,QAAQ;AAAA,MACf,WAAW,MAAM,OAAO,KAAK,gBAAgB,MAAM,IAAI,GAAG;AACxD,cAAM,KAAK,QAAQ;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,OAAK,GAAG;AACR,SAAO;AACT;AAIA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,sEAAiE,EAC7E,QAAQ,OAAO,EACf,KAAK,aAAa,MAAM;AACvB,cAAY;AACd,CAAC;AAIH,QACG,QAAQ,MAAM,EACd,YAAY,mDAAmD,EAC/D,OAAO,oBAAoB,oBAAoB,QAAQ,IAAI,CAAC,EAC5D,OAAO,CAAC,SAA0B;AACjC,QAAM,MAAMF,SAAQ,KAAK,GAAG;AAC5B,UAAQ,IAAIG,OAAM,KAAK,0BAA0B,GAAGA,OAAM,KAAK,GAAG,CAAC;AAEnE,QAAM,YAAY,WAAW,GAAG;AAGhC,QAAM,QAAQ,aAAa,GAAG;AAC9B,QAAM,aAAqC,CAAC;AAC5C,aAAW,KAAK,OAAO;AACrB,UAAM,OAAO,YAAY,CAAC;AAC1B,eAAW,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK;AAAA,EAC/C;AAEA,UAAQ,IAAIA,OAAM,MAAM,2BAA2B,GAAGA,OAAM,KAAK,SAAS,CAAC;AAC3E,UAAQ,IAAIA,OAAM,KAAK;AAAA,YAAe,MAAM,MAAM,gBAAgB,CAAC;AACnE,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACtD,YAAQ,IAAIA,OAAM,KAAK,OAAO,IAAI,KAAK,KAAK,QAAQ,CAAC;AAAA,EACvD;AACA,UAAQ,IAAIA,OAAM,KAAK,eAAe,GAAGA,OAAM,KAAK,gBAAgB,GAAGA,OAAM,KAAK,qBAAqB,CAAC;AACxG,UAAQ,IAAI;AACd,CAAC;AAIH,QACG,QAAQ,OAAO,EACf,YAAY,iCAAiC,EAC7C,OAAO,uBAAuB,eAAe,MAAM,EACnD,OAAO,iBAAiB,0BAA0B,KAAK,EACvD,OAAO,OAAO,SAA6C;AAC1D,QAAM,SAAS,WAAW;AAC1B,QAAM,OAAO,aAAa,KAAK,IAAI;AACnC,MAAI,SAAS,MAAM;AACjB,YAAQ,MAAMA,OAAM,IAAI,6BAA6B,GAAGA,OAAM,KAAK,KAAK,IAAI,CAAC;AAC7E,YAAQ,MAAMA,OAAM,KAAK,8CAA8C,CAAC;AACxE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,2BAA2B;AACjC,6BAA2B;AAC3B,aAAW,EAAE,QAAQ,MAAM,SAAS,KAAK,QAAQ,CAAC;AACpD,CAAC;AAkBH,eAAe,YACb,MACA,MAC+B;AAC/B,MAAI,OAAO;AACX,MAAI;AACF,UAAM,KAAK,MAAM,OAAO,IAAI;AAC5B,WAAO,GAAG;AACV,QAAI,GAAG,OAAO,KAAK,aAAa;AAC9B,aAAO,EAAE,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC,GAAG,SAAS,aAAa,WAAW,KAAK;AAAA,IACpG;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC,GAAG,SAAS,aAAa;AAAA,EACpF;AAIA,MAAI,CAAC,iBAAiB,IAAI,GAAG;AAC3B,QAAI;AACF,UAAI,MAAM,kBAAkB,IAAI,GAAG;AACjC,eAAO,EAAE,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC,GAAG,SAAS,UAAU,WAAW,KAAK;AAAA,MACjG;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,MAAM,OAAO;AAAA,EACrC,QAAQ;AACN,WAAO,EAAE,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC,GAAG,SAAS,cAAc,WAAW,KAAK;AAAA,EACrG;AAEA,QAAM,OAAO,YAAY,IAAI;AAC7B,MAAI,cAAc;AAClB,MAAI,CAAC,KAAK,eAAe,iBAAiB,IAAI,GAAG;AAC/C,QAAI;AACF,YAAM,aAAa,KAAK,MAAM,IAAI;AAClC,oBAAc,WAAW,OAAO;AAAA,IAClC,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,UAAmC,CAAC;AACxC,MAAI;AACF,UAAM,eAAeC,MAAY,IAAI;AACrC,cAAU,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE,WAAW,QAAQ;AAAA,EAC5F,QAAQ;AAAA,EAER;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,aAAa,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IACtC,WAAW;AAAA,EACb;AACF;AAMA,eAAe,kBACb,OACA,MAC6D;AAC7D,QAAM,UAA2B,CAAC;AAClC,MAAI,SAAS;AACb,MAAI,OAAO;AACX,MAAI,YAAY;AAChB,MAAI,cAAc;AAElB,QAAM,cAAc,MAAY;AAAE,kBAAc;AAAA,EAAM;AACtD,UAAQ,GAAG,UAAU,WAAW;AAChC,UAAQ,GAAG,WAAW,WAAW;AAEjC,QAAM,QAAQ,QAAQ,OAAO,UAAU;AACvC,QAAM,gBAAgB,CAAC,QAAQ,UAAgB;AAC7C,QAAI,KAAK,MAAO;AAChB,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,SAAS,MAAM,YAAY,qBAAsB;AACtD,gBAAY;AACZ,UAAM,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,CAAC;AAC3D,UAAM,MAAM,YAAY,IAAI,IAAI,MAAM,MAAM,WAAW,KAAK;AAC5D,QAAI,OAAO;AACT,cAAQ,OAAO,MAAM,WAAW,GAAG,EAAE;AAAA,IACvC,OAAO;AACL,cAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,CAAI;AAAA,IACjC;AAAA,EACF;AAEA,iBAAe,SAAwB;AACrC,WAAO,CAAC,aAAa;AACnB,YAAM,IAAI;AACV,UAAI,KAAK,MAAM,OAAQ;AACvB,YAAM,OAAO,MAAM,CAAC;AACpB,YAAM,MAAM,MAAM,YAAY,MAAM,EAAE,aAAa,KAAK,aAAa,aAAa,KAAK,YAAY,CAAC;AACpG,UAAI,IAAK,SAAQ,KAAK,GAAG;AACzB;AACA,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,gBAAc,IAAI;AAClB,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAK,aAAa,MAAM,UAAU,CAAC,EAAE,GAAG,MAAM,OAAO,CAAC;AACpG,QAAM,QAAQ,IAAI,OAAO;AAEzB,UAAQ,eAAe,UAAU,WAAW;AAC5C,UAAQ,eAAe,WAAW,WAAW;AAE7C,MAAI,CAAC,KAAK,SAAS,OAAO;AACxB,YAAQ,OAAO,MAAM,UAAU;AAAA,EACjC;AACA,SAAO,EAAE,SAAS,YAAY;AAChC;AAEA,SAAS,gBAAgB,OAA8B;AAErD,QAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,QAAM,IAAI,0CAA0C,KAAK,OAAO;AAChE,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,WAAW,EAAE,CAAC,CAAE;AAC1B,MAAI,CAAC,SAAS,CAAC,KAAK,KAAK,EAAG,QAAO;AACnC,QAAM,OAAO,EAAE,CAAC,KAAK;AACrB,QAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ,IAAI,KAAK,WAAW,GAAG,IAAI,QAAQ,IAAI,KAAK,WAAW,GAAG,IAAI,OAAO;AACjH,SAAO,KAAK,MAAM,IAAI,IAAI;AAC5B;AAEA,QACG,QAAQ,eAAe,EACvB,YAAY,kEAAkE,EAC9E,OAAO,kBAAkB,qCAAqC,KAAK,EACnE,OAAO,UAAU,kBAAkB,KAAK,EACxC,OAAO,0BAA0B,iDAAiD,MAAM,EACxF,OAAO,qBAAqB,iCAAiC,OAAO,gBAAgB,CAAC,EACrF,OAAO,WAAW,4BAA4B,KAAK,EACnD,OAAO,OACN,QACA,SACG;AACH,QAAM,YAAYJ,SAAQ,MAAM;AAChC,MAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,YAAQ,MAAME,OAAM,IAAI,wBAAwB,GAAGA,OAAM,KAAK,SAAS,CAAC;AACxE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,gBAAgB,KAAK,WAAW;AACpD,MAAI,gBAAgB,MAAM;AACxB,YAAQ,MAAMA,OAAM,IAAI,uCAAuC,GAAGA,OAAM,KAAK,KAAK,WAAW,CAAC;AAC9F,YAAQ,MAAMA,OAAM,KAAK,sDAAsD,CAAC;AAChF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,cAAc,KAAK,IAAI,GAAG,SAAS,KAAK,aAAa,EAAE,KAAK,gBAAgB;AAElF,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM;AAC7B,YAAQ,OAAO,MAAMA,OAAM,KAAK,wBAAwB,SAAS;AAAA,CAAO,CAAC;AAAA,EAC3E;AACA,QAAM,QAAQ,aAAa,MAAM;AACjC,MAAI,MAAM,WAAW,GAAG;AACtB,YAAQ,MAAMA,OAAM,IAAI,iCAAiC,GAAGA,OAAM,KAAK,SAAS,CAAC;AACjF,YAAQ,MAAMA,OAAM,KAAK,2BAA2B,CAAC,GAAG,oBAAoB,EAAE,KAAK,IAAI,CAAC,CAAC;AACzF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM;AAC7B,YAAQ,OAAO,MAAMA,OAAM,KAAK,SAAS,MAAM,MAAM,+CAA+C,WAAW;AAAA,CAAO,CAAC;AAAA,EACzH;AAEA,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,EAAE,SAAS,YAAY,YAAY,IAAI,MAAM,kBAAkB,OAAO;AAAA,IAC1E,aAAa,KAAK;AAAA,IAClB;AAAA,IACA,OAAO,KAAK,SAAS,KAAK;AAAA,IAC1B;AAAA,EACF,CAAC;AACD,QAAM,YAAY,KAAK,IAAI,IAAI;AAE/B,QAAM,mBAAmB,WAAW,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAC7E,QAAM,eAAe,WAAW,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,CAAC;AACrE,QAAM,eAAe,WAAW,OAAO,CAAC,MAAM,EAAE,YAAY,WAAW,EAAE;AACzE,QAAM,gBAAgB,WAAW,OAAO,CAAC,MAAM,EAAE,YAAY,QAAQ,EAAE;AAEvE,MAAI,KAAK,MAAM;AACb,YAAQ,IAAI,KAAK,UAAU;AAAA,MACzB,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAAG,MAAM,CAAC,CAAC;AAAA,EACb,OAAO;AACL,YAAQ,IAAIA,OAAM,KAAK,2BAA2B,CAAC;AACnD,eAAW,KAAK,YAAY;AAC1B,UAAI,EAAE,SAAS;AACb,YAAI,EAAE,YAAY,aAAa;AAC7B,gBAAM,OAAO,EAAE,aAAa,KAAK,OAAO,MAAM,QAAQ,CAAC;AACvD,kBAAQ,IAAIA,OAAM,KAAK,KAAK,EAAE,IAAI,oBAAe,EAAE,cAAc,CAAC;AAAA,QACpE;AACA;AAAA,MACF;AACA,YAAM,cAAc,EAAE,UAAU,IAC5BA,OAAM,IAAI,KAAK,EAAE,OAAO,UAAU,EAAE,UAAU,IAAI,MAAM,EAAE,GAAG,IAC7D;AACJ,YAAM,UAAU,EAAE,UAAU,KAAM,CAAC,KAAK,eAAe,EAAE,cAAc;AACvE,UAAI,CAAC,QAAS;AACd,cAAQ;AAAA,QACNA,OAAM,KAAK,IAAI,IAAIA,OAAM,MAAM,EAAE,IAAI,IAAIA,OAAM,KAAK,WAAM,EAAE,WAAW,cAAc,IAAI;AAAA,MAC3F;AACA,UAAI,EAAE,UAAU,GAAG;AACjB,mBAAW,KAAK,EAAE,aAAa;AAC7B,kBAAQ,IAAIA,OAAM,IAAI,SAAS,CAAC,EAAE,CAAC;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AACA,UAAM,WAAW,eAAe,gBAAgB,IAC5CA,OAAM,KAAK,aAAa,YAAY,WAAW,aAAa,UAAU,IACtE;AACJ,YAAQ;AAAA,MACNA,OAAM,KAAK;AAAA,WAAc,WAAW,MAAM,cAAc,YAAY,KAAM,QAAQ,CAAC,CAAC,MAAM,gBAAgB,gBAAgB,KACzH,eAAe,IAAIA,OAAM,IAAI,GAAG,YAAY,gBAAgB,IAAIA,OAAM,MAAM,WAAW,KACxF;AAAA,IACF;AACA,QAAI,aAAa;AACf,cAAQ,IAAIA,OAAM,OAAO,qDAAgD,CAAC;AAAA,IAC5E;AACA,YAAQ,IAAI;AAAA,EACd;AAEA,MAAI,CAAC,KAAK,MAAM;AACd,qBAAiB,WAAW,QAAQ,gBAAgB;AAAA,EACtD;AAEA,MAAI,aAAa;AAEf,YAAQ,KAAK,GAAG;AAAA,EAClB;AAEA,MAAI,eAAe,GAAG;AACpB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAIH,QACG,QAAQ,eAAe,EACvB,YAAY,iFAAiF,EAC7F,OAAO,qBAAqB,iBAAiB,UAAU,EACvD,OAAO,yBAAyB,gFAAgF,EAChH,OAAO,UAAU,mCAAmC,KAAK,EACzD,OAAO,UAAU,yCAAyC,KAAK,EAC/D,OAAO,CAAC,MAAc,SAA4E;AACjG,QAAM,UAAUH,SAAQ,IAAI;AAC5B,MAAI,CAACC,YAAW,OAAO,GAAG;AACxB,YAAQ,MAAME,OAAM,IAAI,wBAAwB,GAAGA,OAAM,KAAK,OAAO,CAAC;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,KAAK,UAAU;AACjB,UAAM,YAAY,iBAAiB,KAAK,QAAQ;AAChD,QAAI,CAAC,WAAW;AACd,cAAQ,MAAMA,OAAM,IAAI,8BAA8B,GAAGA,OAAM,KAAK,KAAK,QAAQ,CAAC;AAClF,cAAQ,MAAMA,OAAM,KAAK,0BAA0B,oBAAoB,KAAK,IAAI,CAAC,CAAC;AAClF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI,CAAC,qBAAqB,IAAI,QAAQ,OAAO,EAAE,YAAY,CAAC,KAAK,aAAa,OAAO,GAAG;AACtF,YAAQ,MAAMA,OAAM,IAAI,qCAAqC,GAAGA,OAAM,KAAK,OAAO,CAAC;AACnF,YAAQ,MAAMA,OAAM,KAAK,2BAA2B,CAAC,GAAG,oBAAoB,EAAE,KAAK,IAAI,CAAC,CAAC;AACzF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,OAAOE,cAAa,SAAS,OAAO;AAC1C,QAAM,OAAO,KAAK,WAAW,iBAAiB,KAAK,QAAQ,IAAK,YAAY,OAAO;AACnF,QAAM,aAAaD,MAAY,IAAI;AACnC,QAAM,gBAAgB,KAAK,SAAS,aAAa,gBAAgB,KAAK,IAAI,IAAI,KAAK;AACnF,QAAM,EAAE,cAAc,UAAU,WAAW,IAAI,uBAAuB,MAAM,WAAW,SAAS,aAAa;AAC7G,QAAM,kBAAkB,WAAW;AACnC,QAAM,SAAS,OAAO,UAAU,MAAM,KAAK,IAAI;AAE/C,MAAI,KAAK,MAAM;AACb,UAAM,YAAY,aAAa;AAC/B,UAAM,QAAQ,IAAI,cAAcF,MAAK,WAAW,mBAAmB,CAAC;AACpE,UAAM,KAAK;AACX,UAAM,KAAK;AAAA,MACT,IAAI;AAAA,MACJ,cAAc;AAAA,MACd,YAAY,cAAc,QAAQ,OAAO,GAAG;AAAA,MAC5C,mBAAmB,CAAC,GAAG,WAAW,QAAQ,CAAC;AAAA,MAC3C,WAAW,KAAK,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AACD,UAAM,QAAQ;AACd,YAAQ,OAAO,MAAMC,OAAM,KAAK,yBAAyB,SAAS;AAAA,CAAsB,CAAC;AAAA,EAC3F;AAEA,MAAI,KAAK,MAAM;AACb,YAAQ,IAAI,KAAK,UAAU;AAAA,MACzB,aAAa,OAAO;AAAA,MACpB,KAAK,OAAO,YAAY,OAAO,GAAG;AAAA,MAClC,OAAO,OAAO;AAAA,MACd;AAAA,MACA,YAAY,OAAO,YAAY,UAAU;AAAA,IAC3C,GAAG,MAAM,CAAC,CAAC;AAAA,EACb,OAAO;AACL,YAAQ,OAAO,MAAM,OAAO,WAAW;AACvC,QAAI,kBAAkB,GAAG;AACvB,cAAQ,OAAO;AAAA,QACbA,OAAM,KAAK,OAAO,eAAe;AAAA,CAA+D;AAAA,MAClG;AAAA,IACF;AACA,YAAQ,OAAO,MAAMA,OAAM,KAAK;AAAA,MAAS,OAAO,MAAM,aAAa,2BAA2B,OAAO,MAAM,UAAU;AAAA,CAAU,CAAC;AAChI,qBAAiB,GAAG,OAAO,MAAM,aAAa;AAAA,EAChD;AACF,CAAC;AAIH,QACG,QAAQ,gBAAgB,EACxB,YAAY,oCAAoC,EAChD,OAAO,oBAAoB,gCAAgC,EAC3D,OAAO,CAAC,MAAc,SAA2B;AAChD,QAAM,UAAUH,SAAQ,IAAI;AAC5B,MAAI,CAACC,YAAW,OAAO,GAAG;AACxB,YAAQ,MAAME,OAAM,IAAI,wBAAwB,GAAGA,OAAM,KAAK,OAAO,CAAC;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAcE,cAAa,SAAS,OAAO;AAGjD,QAAM,UAAU,KAAK,MACjBL,SAAQ,KAAK,GAAG,IAChBE,MAAK,aAAa,GAAG,mBAAmB;AAE5C,MAAI,CAACD,YAAW,OAAO,GAAG;AACxB,YAAQ,MAAME,OAAM,IAAI,gCAAgC,GAAGA,OAAM,KAAK,OAAO,CAAC;AAC9E,YAAQ,MAAMA,OAAM,KAAK,6DAA6D,CAAC;AACvF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACJ,MAAI;AACF,YAAQ,IAAI,cAAc,OAAO;AACjC,UAAM,KAAK;AAAA,EACb,QAAQ;AACN,YAAQ,MAAMA,OAAM,IAAI,qCAAqC,GAAGA,OAAM,KAAK,OAAO,CAAC;AACnF,YAAQ,MAAMA,OAAM,KAAK,wEAAwE,CAAC;AAClG,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,MAAM,UAAU,OAAO,KAAK,MAAM,KAAK,CAAC,EAAE,CAAC;AAC/E,MAAI,CAAC,OAAO;AACV,YAAQ,MAAMA,OAAM,IAAI,uCAAuC,CAAC;AAChE,YAAQ,MAAMA,OAAM,KAAK,8DAA8D,CAAC;AACxF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,MAAM,cAAc,MAAM,KAAK;AACrC,QAAM,aAAa,MAAM,oBACrB,IAAI,IAAI,MAAM,iBAAiB,IAC/B;AACJ,QAAM,WAAW,QAAQ,aAAa,KAAK,UAAU;AAErD,UAAQ,OAAO,MAAM,QAAQ;AAC7B,QAAM,eAAe,YAAY,QAAQ;AACzC,QAAM,gBAAgB,eAAe,IAAI,MAAM,YAAY,eAAe;AAC1E,UAAQ,OAAO,MAAMA,OAAM,KAAK;AAAA,eAAkB,IAAI,IAAI,aAAa,aAAa;AAAA,CAAQ,CAAC;AAC/F,CAAC;AAIH,QACG,QAAQ,OAAO,EACf,YAAY,oBAAoB,EAChC,OAAO,UAAU,kBAAkB,KAAK,EACxC,OAAO,SAAS,iBAAiB,KAAK,EACtC,OAAO,wBAAwB,iBAAiB,IAAI,EACpD,OAAO,CAAC,SAAyD;AAChE,QAAM,SAAS,KAAK,OAAO,SAAS,KAAK,MAAM,QAAQ;AACvD,QAAM,QAAQ,SAAS,KAAK,KAAK,KAAK;AAEtC,QAAM,UAAU,aAAa,EAAE,OAAO,OAAO,CAAC;AAC9C,QAAM,SAAS,YAAY,SAAS,MAAM;AAC1C,UAAQ,IAAI,MAAM;AACpB,CAAC;AAIH,QACG,QAAQ,SAAS,EACjB,YAAY,4BAA4B,EACxC,OAAO,MAAM;AACZ,UAAQ,IAAI,kBAAkB,OAAO,EAAE;AACzC,CAAC;AAIH,QACG,QAAQ,QAAQ,EAChB,YAAY,8CAA8C,EAC1D,OAAO,YAAY;AAClB,QAAM,UAAU;AAClB,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,6DAAwD,EACpE,OAAO,YAAY;AAClB,QAAM,UAAU;AAClB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,oEAA+D,EAC3E,OAAO,YAAY;AAClB,QAAM,WAAW;AACnB,CAAC;AAIH,QACG,QAAQ,SAAS,EACjB,YAAY,gDAAgD,EAC5D,OAAO,MAAM;AACZ,aAAW;AACb,CAAC;AAEH,QACG,QAAQ,SAAS,EACjB,YAAY,2DAA2D,EACvE,OAAO,YAAY;AAClB,QAAM,WAAW;AACnB,CAAC;AAIH,QACG,QAAQ,OAAO,EACf,YAAY,wEAAwE,EACpF,OAAO,mBAAmB,4FAA4F,EACtH,OAAO,CAAC,SAA2B;AAClC,QAAM,OAAO,SAAS,EAAE,KAAK,KAAK,IAAI,CAAC;AACvC,MAAI,SAAS,EAAG,SAAQ,KAAK,IAAI;AACnC,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0EAA0E,EACtF,OAAO,aAAa,4BAA4B,KAAK,EACrD,OAAO,OAAO,SAA2B;AACxC,QAAM,OAAO,MAAM,UAAU,EAAE,WAAW,KAAK,QAAQ,KAAK,CAAC;AAC7D,MAAI,SAAS,EAAG,SAAQ,KAAK,IAAI;AACnC,CAAC;AAIH,SAAS,iBAAiB,KAAoB;AAC5C,MAAI,eAAe,SAAS,IAAI,SAAS;AACvC,YAAQ,MAAMA,OAAM,IAAI,QAAQ,GAAG,IAAI,OAAO;AAAA,EAChD,OAAO;AACL,YAAQ,MAAMA,OAAM,IAAI,+BAA+B,CAAC;AAAA,EAC1D;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,GAAG,qBAAqB,gBAAgB;AAChD,QAAQ,GAAG,sBAAsB,gBAAgB;AAIjD,QACG,yBAAyB,IAAI,EAC7B,mBAAmB,qCAAqC;AAE3D,QAAQ,MAAM;","names":["chalk","readFileSync","existsSync","readSync","resolve","join","scan","start","readFileSync","writeFileSync","mkdirSync","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","join","writeFileSync","readFileSync","join","existsSync","readFileSync","mkdirSync","writeFileSync","existsSync","readFileSync","mkdirSync","join","dirname","join","dirname","existsSync","mkdirSync","readFileSync","existsSync","existsSync","mkdirSync","writeFileSync","readFileSync","join","homedir","CONFIG_DIR_NAME","CONFIG_FILE","chalk","readFileSync","existsSync","upstream","headers","scan","resolve","chalk","chalk","chalk","chalk","fmt","tierBadge","chalk","lines","chalk","chalk","chalk","PLAN_LABEL","fmt","chalk","used","cap","remaining","pct","lines","readline","chalk","chalk","readline","readSync","resolve","existsSync","join","chalk","scan","readFileSync"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/scanner.ts","../src/salt.ts","../src/config-dir.ts","../src/deterministic-id.ts","../src/mutator.ts","../src/reverser.ts","../src/secrets.ts","../src/store.ts","../src/config.ts","../src/audit.ts","../src/proxy.ts","../src/auth.ts","../src/session-store.ts","../src/git-context.ts","../src/commands/login.ts","../src/dashboard-env.ts","../src/publish-info.ts","../src/backend-client.ts","../src/log-uploader.ts","../src/start-client-instructions.ts","../src/version.ts","../src/token-footer.ts","../src/banner.ts","../src/commands/status.ts","../src/commands/upgrade.ts","../src/commands/credits.ts","../src/commands/logout.ts"],"sourcesContent":["/**\n * Pretest CLI — Entry Point\n *\n * AI firewall CLI that mutates proprietary code identifiers before\n * sending to LLM APIs. Commands: init, start, scan, mutate, reverse,\n * audit, status, usage, tokens, upgrade, credits, login, logout, version.\n */\n\n// ─── Node version preflight (must run before any other imports execute) ─────\n{\n const major = parseInt(process.versions.node.split(\".\")[0]!, 10);\n if (Number.isNaN(major) || major < 18) {\n process.stderr.write(\n `pretest requires Node.js 18 or newer (you have v${process.versions.node}).\\n`,\n );\n process.stderr.write(`Upgrade via nvm: nvm install 20 && nvm use 20\\n`);\n process.exit(1);\n }\n}\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport {\n readFileSync,\n existsSync,\n readdirSync,\n statSync,\n openSync,\n readSync,\n closeSync,\n Dirent,\n} from \"fs\";\nimport { readFile, stat as fsStat, open as fsOpen } from \"fs/promises\";\nimport { resolve, extname, join, basename } from \"path\";\nimport os from \"node:os\";\nimport { scan, detectLanguage } from \"./scanner.js\";\nimport { mutate } from \"./mutator.js\";\nimport { reverse } from \"./reverser.js\";\nimport { scan as scanSecrets, applyRedactionsTracked } from \"./secrets.js\";\nimport { effectiveSeedForMutation } from \"./salt.js\";\nimport { MutationStore } from \"./store.js\";\nimport { initConfig, loadConfig, getConfigDir } from \"./config.js\";\nimport { readAuditLog, formatAudit } from \"./audit.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { printTokenFooter } from \"./token-footer.js\";\nimport { printBanner } from \"./banner.js\";\nimport { runStatus } from \"./commands/status.js\";\nimport { runUpgrade } from \"./commands/upgrade.js\";\nimport { runCredits } from \"./commands/credits.js\";\nimport { ensureDashboardKeyForStart, logDashboardCredentialHint, runLogin } from \"./commands/login.js\";\nimport { runLogout } from \"./commands/logout.js\";\nimport { getCliSemver } from \"./version.js\";\n\nconst VERSION = getCliSemver();\n\n// ─── Scan defaults (P0 hang fix) ─────────────────────────────────────────────\n// Files larger than the --max-file-size value (default: 10mb) are skipped.\n// Real-world source files are almost always < 1 MB; anything larger is\n// typically generated/minified/vendored data that wedges the regex scanner\n// with no useful signal.\n//\n// Concurrency cap for parallel file scanning (1 worker per logical CPU,\n// minimum 2 to keep things moving on single-core CI).\nconst SCAN_CONCURRENCY = Math.max(2, os.cpus().length);\n// Throttle for streaming progress updates so we don't flood stderr.\nconst PROGRESS_INTERVAL_MS = 500;\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst SUPPORTED_LANGUAGES = [\"typescript\", \"javascript\", \"python\", \"go\", \"java\", \"csharp\", \"ruby\", \"rust\"];\n\nconst SUPPORTED_EXTENSIONS = new Set([\".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".py\", \".go\", \".java\", \".cs\", \".rb\", \".rs\"]);\n\n// Additional config/data file types scanned for secrets (not for identifier mutation).\nconst SUPPORTED_CONFIG_EXTENSIONS = new Set([\n \".json\", \".yaml\", \".yml\", \".toml\", \".env\", \".cfg\", \".ini\",\n \".tf\", \".tfstate\", \".tfvars\", \".hcl\",\n \".properties\", \".conf\", \".xml\", \".plist\",\n \".pem\", \".key\", \".crt\", \".pub\", \".pfx\", \".p12\", \".htpasswd\",\n]);\n\nconst SUPPORTED_FILENAMES = new Set([\n \".env\",\n \".env.local\",\n \".env.production\",\n \".env.development\",\n \".env.staging\",\n \".env.test\",\n \".npmrc\",\n \".netrc\",\n \".pypirc\",\n \"Dockerfile\",\n \"docker-compose.yml\",\n \"docker-compose.yaml\",\n]);\n\nfunction isScannableFile(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return (\n SUPPORTED_EXTENSIONS.has(ext) ||\n SUPPORTED_CONFIG_EXTENSIONS.has(ext) ||\n SUPPORTED_FILENAMES.has(basename(filePath))\n );\n}\n\nfunction isSourceCodeFile(filePath: string): boolean {\n return SUPPORTED_EXTENSIONS.has(extname(filePath).toLowerCase());\n}\n\nfunction langFromExt(filePath: string): string {\n const ext = extname(filePath).toLowerCase();\n const map: Record<string, string> = {\n \".ts\": \"typescript\",\n \".tsx\": \"typescript\",\n \".js\": \"javascript\",\n \".jsx\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".py\": \"python\",\n \".go\": \"go\",\n \".java\": \"java\",\n \".cs\": \"csharp\",\n \".rb\": \"ruby\",\n \".rs\": \"rust\",\n };\n return map[ext] ?? \"typescript\";\n}\n\n/**\n * Validate a port number string. Returns the parsed integer or null if invalid.\n */\nfunction validatePort(value: string): number | null {\n const port = parseInt(value, 10);\n if (isNaN(port) || port.toString() !== value.trim()) return null;\n if (port < 1 || port > 65535) return null;\n return port;\n}\n\n/**\n * Detect if a file is likely binary by checking for null bytes\n * in the first 8KB. Only reads the bytes needed, not the whole file.\n */\nfunction isBinaryFile(filePath: string): boolean {\n let fd: number | undefined;\n try {\n fd = openSync(filePath, \"r\");\n const buf = Buffer.alloc(8192);\n const bytesRead = readSync(fd, buf, 0, 8192, 0);\n for (let i = 0; i < bytesRead; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n } catch {\n return false;\n } finally {\n if (fd !== undefined) closeSync(fd);\n }\n}\n\n/**\n * Async binary-file probe — reads only the first 8KB.\n * Used by the concurrent scanner so we never block the event loop.\n */\nasync function isBinaryFileAsync(filePath: string): Promise<boolean> {\n let handle: import(\"fs/promises\").FileHandle | undefined;\n try {\n handle = await fsOpen(filePath, \"r\");\n const buf = Buffer.alloc(8192);\n const { bytesRead } = await handle.read(buf, 0, 8192, 0);\n for (let i = 0; i < bytesRead; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n } catch {\n return false;\n } finally {\n if (handle) await handle.close().catch(() => {});\n }\n}\n\n/**\n * Validate that a language string is supported. Returns the normalized\n * language or null if unsupported.\n */\nfunction validateLanguage(lang: string): string | null {\n const normalized = lang.toLowerCase();\n const aliases: Record<string, string> = {\n ts: \"typescript\", tsx: \"typescript\",\n js: \"javascript\", jsx: \"javascript\",\n py: \"python\",\n cs: \"csharp\",\n rb: \"ruby\",\n rs: \"rust\",\n };\n const resolved = aliases[normalized] ?? normalized;\n return SUPPORTED_LANGUAGES.includes(resolved) ? resolved : null;\n}\n\nfunction collectFiles(target: string): string[] {\n const abs = resolve(target);\n if (!existsSync(abs)) {\n return [];\n }\n const stat = statSync(abs);\n if (stat.isFile()) return [abs];\n\n const files: string[] = [];\n\n function walk(dir: string): void {\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n // EPERM on ~/.Trash and similar protected dirs (macOS); ENOENT races; skip.\n return;\n }\n const skipDirs = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".pretest\",\n \".pretense\",\n \".next\",\n \"__pycache__\",\n \".Trash\",\n ]);\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (skipDirs.has(entry.name)) continue;\n walk(fullPath);\n } else if (entry.isFile() && isScannableFile(entry.name)) {\n files.push(fullPath);\n }\n }\n }\n\n walk(abs);\n return files;\n}\n\n// ─── CLI ─────────────────────────────────────────────────────────────────────\n\nconst program = new Command();\n\nprogram\n .name(\"pretest\")\n .description(\"AI firewall CLI — mutates proprietary code before LLM API calls\")\n .version(VERSION)\n .hook(\"preAction\", () => {\n printBanner();\n });\n\n// ── init ──────────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"init\")\n .description(\"Initialize .pretest/ config in current directory\")\n .option(\"-d, --dir <path>\", \"Target directory\", process.cwd())\n .action((opts: { dir: string }) => {\n const dir = resolve(opts.dir);\n console.log(chalk.cyan(\"Initializing Pretest in\"), chalk.bold(dir));\n\n const configDir = initConfig(dir);\n\n // Scan for source files\n const files = collectFiles(dir);\n const langCounts: Record<string, number> = {};\n for (const f of files) {\n const lang = langFromExt(f);\n langCounts[lang] = (langCounts[lang] ?? 0) + 1;\n }\n\n console.log(chalk.green(\"\\n .pretest/ created at\"), chalk.bold(configDir));\n console.log(chalk.gray(`\\n Scanned ${files.length} source files:`));\n for (const [lang, count] of Object.entries(langCounts)) {\n console.log(chalk.gray(` ${lang}: ${count} files`));\n }\n console.log(chalk.cyan(\"\\n Next: run\"), chalk.bold(\"pretest start\"), chalk.cyan(\"to launch the proxy\"));\n console.log();\n });\n\n// ── start ─────────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"start\")\n .description(\"Start the Pretest proxy server\")\n .option(\"-p, --port <number>\", \"Port number\", \"9339\")\n .option(\"-v, --verbose\", \"Enable verbose logging\", false)\n .action(async (opts: { port: string; verbose: boolean }) => {\n const config = loadConfig();\n const port = validatePort(opts.port);\n if (port === null) {\n console.error(chalk.red(\"Error: Invalid port number:\"), chalk.bold(opts.port));\n console.error(chalk.gray(\"Port must be an integer between 1 and 65535.\"));\n process.exit(1);\n }\n await ensureDashboardKeyForStart();\n logDashboardCredentialHint();\n startProxy({ config, port, verbose: opts.verbose });\n });\n\n// ── scan ──────────────────────────────────────────────────────────────────────\n\ninterface ScanRowResult {\n file: string;\n identifiers: number;\n secrets: number;\n secretTypes: string[];\n skipped?: \"too-large\" | \"binary\" | \"read-error\";\n sizeBytes?: number;\n}\n\n/**\n * Scan a single file. Pure async, fully bounded (file-size + binary checks\n * happen before reading). Returns null on unrecoverable read errors so the\n * caller can keep going on the next file.\n */\nasync function scanOneFile(\n file: string,\n opts: { secretsOnly: boolean; maxFileSize: number },\n): Promise<ScanRowResult | null> {\n let size = 0;\n try {\n const st = await fsStat(file);\n size = st.size;\n if (st.size > opts.maxFileSize) {\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"too-large\", sizeBytes: size };\n }\n } catch {\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"read-error\" };\n }\n\n // Cheap binary probe for unknown source extensions to avoid wedging\n // the regex engine on minified bundles, fixtures, or vendored blobs.\n if (!isSourceCodeFile(file)) {\n try {\n if (await isBinaryFileAsync(file)) {\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"binary\", sizeBytes: size };\n }\n } catch {\n /* fall through and try to read */\n }\n }\n\n let code: string;\n try {\n code = await readFile(file, \"utf-8\");\n } catch {\n return { file, identifiers: 0, secrets: 0, secretTypes: [], skipped: \"read-error\", sizeBytes: size };\n }\n\n const lang = langFromExt(file);\n let identifiers = 0;\n if (!opts.secretsOnly && isSourceCodeFile(file)) {\n try {\n const scanResult = scan(code, lang);\n identifiers = scanResult.tokens.length;\n } catch {\n /* identifier scan failures are non-fatal */\n }\n }\n\n let blocked: Array<{ type: string }> = [];\n try {\n const secretResult = scanSecrets(code);\n blocked = secretResult.matches.filter((m) => m.action === \"block\" || m.action === \"redact\");\n } catch {\n /* secret scan failures are non-fatal */\n }\n\n return {\n file,\n identifiers,\n secrets: blocked.length,\n secretTypes: blocked.map((m) => m.type),\n sizeBytes: size,\n };\n}\n\n/**\n * Process `files` with bounded concurrency, streaming progress to stderr\n * and listening for SIGINT/SIGTERM so partial results can be flushed.\n */\nasync function scanFilesParallel(\n files: string[],\n opts: { secretsOnly: boolean; maxFileSize: number; quiet: boolean; concurrency: number },\n): Promise<{ results: ScanRowResult[]; interrupted: boolean }> {\n const results: ScanRowResult[] = [];\n let cursor = 0;\n let done = 0;\n let lastPrint = 0;\n let interrupted = false;\n\n const stopHandler = (): void => { interrupted = true; };\n process.on(\"SIGINT\", stopHandler);\n process.on(\"SIGTERM\", stopHandler);\n\n const isTTY = process.stderr.isTTY === true;\n const printProgress = (force = false): void => {\n if (opts.quiet) return;\n const now = Date.now();\n if (!force && now - lastPrint < PROGRESS_INTERVAL_MS) return;\n lastPrint = now;\n const found = results.reduce((acc, r) => acc + r.secrets, 0);\n const msg = `Scanning ${done}/${files.length} files (${found} secrets so far)...`;\n if (isTTY) {\n process.stderr.write(`\\r\\x1b[K${msg}`);\n } else {\n process.stderr.write(`${msg}\\n`);\n }\n };\n\n async function worker(): Promise<void> {\n while (!interrupted) {\n const i = cursor++;\n if (i >= files.length) return;\n const file = files[i]!;\n const row = await scanOneFile(file, { secretsOnly: opts.secretsOnly, maxFileSize: opts.maxFileSize });\n if (row) results.push(row);\n done++;\n printProgress();\n }\n }\n\n printProgress(true);\n const workers = Array.from({ length: Math.min(opts.concurrency, files.length || 1) }, () => worker());\n await Promise.all(workers);\n\n process.removeListener(\"SIGINT\", stopHandler);\n process.removeListener(\"SIGTERM\", stopHandler);\n\n if (!opts.quiet && isTTY) {\n process.stderr.write(`\\r\\x1b[K`);\n }\n return { results, interrupted };\n}\n\nfunction parseSizeOption(value: string): number | null {\n // Accept plain bytes, or \"10m\" / \"10mb\" / \"500k\" / \"500kb\"\n const trimmed = value.trim().toLowerCase();\n const m = /^(\\d+(?:\\.\\d+)?)\\s*(b|k|kb|m|mb|g|gb)?$/.exec(trimmed);\n if (!m) return null;\n const n = parseFloat(m[1]!);\n if (!isFinite(n) || n <= 0) return null;\n const unit = m[2] ?? \"b\";\n const mult = unit.startsWith(\"g\") ? 1024 ** 3 : unit.startsWith(\"m\") ? 1024 ** 2 : unit.startsWith(\"k\") ? 1024 : 1;\n return Math.floor(n * mult);\n}\n\nprogram\n .command(\"scan <target>\")\n .description(\"Scan file or directory for identifiers and secrets (no mutation)\")\n .option(\"--secrets-only\", \"Only scan for secrets/credentials\", false)\n .option(\"--json\", \"Output as JSON\", false)\n .option(\"--max-file-size <size>\", \"Skip files larger than this (e.g. 10mb, 500k)\", \"10mb\")\n .option(\"--concurrency <n>\", \"Max files scanned in parallel\", String(SCAN_CONCURRENCY))\n .option(\"--quiet\", \"Suppress progress output\", false)\n .action(async (\n target: string,\n opts: { secretsOnly: boolean; json: boolean; maxFileSize: string; concurrency: string; quiet: boolean },\n ) => {\n const absTarget = resolve(target);\n if (!existsSync(absTarget)) {\n console.error(chalk.red(\"Error: Path not found:\"), chalk.bold(absTarget));\n process.exit(1);\n }\n\n const maxFileSize = parseSizeOption(opts.maxFileSize);\n if (maxFileSize === null) {\n console.error(chalk.red(\"Error: Invalid --max-file-size value:\"), chalk.bold(opts.maxFileSize));\n console.error(chalk.gray(\"Use bytes or a unit suffix, e.g. 10mb, 500k, 1048576\"));\n process.exit(1);\n }\n const concurrency = Math.max(1, parseInt(opts.concurrency, 10) || SCAN_CONCURRENCY);\n\n if (!opts.quiet && !opts.json) {\n process.stderr.write(chalk.gray(`Discovering files in ${absTarget}...\\n`));\n }\n const files = collectFiles(target);\n if (files.length === 0) {\n console.error(chalk.red(\"Error: No source files found at\"), chalk.bold(absTarget));\n console.error(chalk.gray(\"Supported extensions: \" + [...SUPPORTED_EXTENSIONS].join(\", \")));\n process.exit(1);\n }\n if (!opts.quiet && !opts.json) {\n process.stderr.write(chalk.gray(`Found ${files.length} candidate files. Scanning with concurrency=${concurrency}...\\n`));\n }\n\n const startedAt = Date.now();\n const { results: allResults, interrupted } = await scanFilesParallel(files, {\n secretsOnly: opts.secretsOnly,\n maxFileSize,\n quiet: opts.quiet || opts.json,\n concurrency,\n });\n const elapsedMs = Date.now() - startedAt;\n\n const totalIdentifiers = allResults.reduce((acc, r) => acc + r.identifiers, 0);\n const totalSecrets = allResults.reduce((acc, r) => acc + r.secrets, 0);\n const skippedLarge = allResults.filter((r) => r.skipped === \"too-large\").length;\n const skippedBinary = allResults.filter((r) => r.skipped === \"binary\").length;\n\n if (opts.json) {\n console.log(JSON.stringify({\n files: allResults,\n totalIdentifiers,\n totalSecrets,\n skippedLarge,\n skippedBinary,\n elapsedMs,\n interrupted,\n }, null, 2));\n } else {\n console.log(chalk.cyan(\"\\nPretest Scan Results\\n\"));\n for (const r of allResults) {\n if (r.skipped) {\n if (r.skipped === \"too-large\") {\n const mb = ((r.sizeBytes ?? 0) / 1024 / 1024).toFixed(1);\n console.log(chalk.gray(` ${r.file} — skipped (${mb} MB > limit)`));\n }\n continue;\n }\n const secretBadge = r.secrets > 0\n ? chalk.red(` [${r.secrets} SECRET${r.secrets > 1 ? \"S\" : \"\"}]`)\n : \"\";\n const showRow = r.secrets > 0 || (!opts.secretsOnly && r.identifiers > 0);\n if (!showRow) continue;\n console.log(\n chalk.gray(\" \") + chalk.white(r.file) + chalk.gray(` — ${r.identifiers} identifiers`) + secretBadge,\n );\n if (r.secrets > 0) {\n for (const t of r.secretTypes) {\n console.log(chalk.red(` ! ${t}`));\n }\n }\n }\n const skipNote = skippedLarge + skippedBinary > 0\n ? chalk.gray(` (skipped ${skippedLarge} large, ${skippedBinary} binary)`)\n : \"\";\n console.log(\n chalk.gray(`\\n Total: ${allResults.length} files in ${(elapsedMs / 1000).toFixed(2)}s, ${totalIdentifiers} identifiers, `) +\n (totalSecrets > 0 ? chalk.red(`${totalSecrets} secrets found`) : chalk.green(\"0 secrets\")) +\n skipNote,\n );\n if (interrupted) {\n console.log(chalk.yellow(\"\\n Interrupted — partial results shown above.\"));\n }\n console.log();\n }\n\n if (!opts.json) {\n printTokenFooter(allResults.length, totalIdentifiers);\n }\n\n if (interrupted) {\n // Flushed partial results; signal interruption with non-zero exit.\n process.exit(130);\n }\n // Exit code 2 if secrets found\n if (totalSecrets > 0) {\n process.exit(2);\n }\n });\n\n// ── mutate ────────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"mutate <file>\")\n .description(\"Mutate identifiers for stdout (scanner redacts secrets/PII in the source first)\")\n .option(\"-s, --seed <seed>\", \"Mutation seed\", \"pretest\")\n .option(\"-l, --language <lang>\", \"Source language (typescript, javascript, python, go, java, csharp, ruby, rust)\")\n .option(\"--save\", \"Save mutation map to .pretest/\", false)\n .option(\"--json\", \"Output as JSON (includes map + stats)\", false)\n .action((file: string, opts: { seed: string; language?: string; save: boolean; json: boolean }) => {\n const absPath = resolve(file);\n if (!existsSync(absPath)) {\n console.error(chalk.red(\"Error: File not found:\"), chalk.bold(absPath));\n process.exit(1);\n }\n\n // Validate language option if provided\n if (opts.language) {\n const validLang = validateLanguage(opts.language);\n if (!validLang) {\n console.error(chalk.red(\"Error: Unsupported language:\"), chalk.bold(opts.language));\n console.error(chalk.gray(\"Supported languages: \" + SUPPORTED_LANGUAGES.join(\", \")));\n process.exit(1);\n }\n }\n\n // Check for binary files\n if (!SUPPORTED_EXTENSIONS.has(extname(absPath).toLowerCase()) && isBinaryFile(absPath)) {\n console.error(chalk.red(\"Error: Not a supported source file:\"), chalk.bold(absPath));\n console.error(chalk.gray(\"Supported extensions: \" + [...SUPPORTED_EXTENSIONS].join(\", \")));\n process.exit(1);\n }\n\n const code = readFileSync(absPath, \"utf-8\");\n const lang = opts.language ? validateLanguage(opts.language)! : langFromExt(absPath);\n const secretScan = scanSecrets(code);\n const effectiveSeed = effectiveSeedForMutation(opts.seed);\n const { redactedCode: redacted, secretsMap } = applyRedactionsTracked(code, secretScan.matches, effectiveSeed);\n const secretsRedacted = secretsMap.size;\n const result = mutate(redacted, lang, opts.seed);\n\n if (opts.save) {\n const configDir = getConfigDir();\n const store = new MutationStore(join(configDir, \"mutation-map.json\"));\n store.load();\n store.save({\n id: absPath,\n originalHash: absPath,\n mapEntries: MutationStore.fromMap(result.map),\n secretsMapEntries: [...secretsMap.entries()],\n timestamp: Date.now(),\n language: lang,\n });\n store.persist();\n process.stderr.write(chalk.gray(`Mutation map saved to ${configDir}/mutation-map.json\\n`));\n }\n\n if (opts.json) {\n console.log(JSON.stringify({\n mutatedCode: result.mutatedCode,\n map: Object.fromEntries(result.map),\n stats: result.stats,\n secretsRedacted,\n secretsMap: Object.fromEntries(secretsMap),\n }, null, 2));\n } else {\n process.stdout.write(result.mutatedCode);\n if (secretsRedacted > 0) {\n process.stderr.write(\n chalk.gray(`--- ${secretsRedacted} secret/PII span(s) redacted before identifier mutation ---\\n`),\n );\n }\n process.stderr.write(chalk.gray(`\\n--- ${result.stats.tokensMutated} identifiers mutated in ${result.stats.durationMs}ms ---\\n`));\n printTokenFooter(1, result.stats.tokensMutated);\n }\n });\n\n// ── reverse ───────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"reverse <file>\")\n .description(\"Reverse mutations using stored map\")\n .option(\"-m, --map <path>\", \"Path to mutation map JSON file\")\n .action((file: string, opts: { map?: string }) => {\n const absPath = resolve(file);\n if (!existsSync(absPath)) {\n console.error(chalk.red(\"Error: File not found:\"), chalk.bold(absPath));\n process.exit(1);\n }\n\n const mutatedCode = readFileSync(absPath, \"utf-8\");\n\n // Load map from specified path or .pretest/mutation-map.json\n const mapPath = opts.map\n ? resolve(opts.map)\n : join(getConfigDir(), \"mutation-map.json\");\n\n if (!existsSync(mapPath)) {\n console.error(chalk.red(\"Error: Mutation map not found:\"), chalk.bold(mapPath));\n console.error(chalk.gray(\"Run 'pretest mutate --save' first, or specify --map <path>\"));\n process.exit(1);\n }\n\n let store: MutationStore;\n try {\n store = new MutationStore(mapPath);\n store.load();\n } catch {\n console.error(chalk.red(\"Error: Failed to load mutation map:\"), chalk.bold(mapPath));\n console.error(chalk.gray(\"The file may be corrupted. Run 'pretest mutate --save' to regenerate.\"));\n process.exit(1);\n }\n\n // Try to find map by file path, or use the most recent entry\n const entry = store.get(absPath) ?? store.getByHash(absPath) ?? store.list(1)[0];\n if (!entry) {\n console.error(chalk.red(\"Error: No mutation map entries found.\"));\n console.error(chalk.gray(\"Run 'pretest mutate --save <file>' first to generate a map.\"));\n process.exit(1);\n }\n\n const map = MutationStore.toMap(entry);\n const secretsMap = entry.secretsMapEntries\n ? new Map(entry.secretsMapEntries)\n : undefined;\n const restored = reverse(mutatedCode, map, secretsMap);\n\n process.stdout.write(restored);\n const secretsCount = secretsMap?.size ?? 0;\n const secretsSuffix = secretsCount > 0 ? ` + ${secretsCount} secret(s)` : \"\";\n process.stderr.write(chalk.gray(`\\n--- Reversed ${map.size} mutations${secretsSuffix} ---\\n`));\n });\n\n// ── audit ─────────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"audit\")\n .description(\"View the audit log\")\n .option(\"--json\", \"Output as JSON\", false)\n .option(\"--csv\", \"Output as CSV\", false)\n .option(\"-l, --limit <number>\", \"Limit entries\", \"50\")\n .action((opts: { json: boolean; csv: boolean; limit: string }) => {\n const format = opts.json ? \"json\" : opts.csv ? \"csv\" : \"text\";\n const limit = parseInt(opts.limit) || 50;\n\n const entries = readAuditLog({ limit, format });\n const output = formatAudit(entries, format);\n console.log(output);\n });\n\n// ── version ───────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"version\")\n .description(\"Print Pretest CLI version\")\n .action(() => {\n console.log(`@blockyfy/stg-cli v${VERSION}`);\n });\n\n// ── status / usage / tokens ─────────────────────────────────────────────────\n\nprogram\n .command(\"status\")\n .description(\"Show current plan, monthly quota, seat usage\")\n .action(async () => {\n await runStatus();\n });\n\nprogram\n .command(\"usage\")\n .description(\"Alias for `pretest status` — show monthly quota usage\")\n .action(async () => {\n await runStatus();\n });\n\nprogram\n .command(\"tokens\")\n .description(\"Alias for `pretest credits` — show remaining mutation budget\")\n .action(async () => {\n await runCredits();\n });\n\n// ── upgrade / credits ────────────────────────────────────────────────────────\n\nprogram\n .command(\"upgrade\")\n .description(\"Compare plans and upgrade to Pro or Enterprise\")\n .action(() => {\n runUpgrade();\n });\n\nprogram\n .command(\"credits\")\n .description(\"Show remaining mutation/scan budget for the current month\")\n .action(async () => {\n await runCredits();\n });\n\n// ── login ─────────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"login\")\n .description(\"Save a dashboard API key to ~/.pretest/config.json for future CLI runs\")\n .option(\"-k, --key <key>\", \"API key (prtns_live_... or pk_live_...). If omitted, read from $PRETEST_API_KEY or stdin.\")\n .action((opts: { key?: string }) => {\n const code = runLogin({ key: opts.key });\n if (code !== 0) process.exit(code);\n });\n\nprogram\n .command(\"logout\")\n .description(\"Remove the saved dashboard API key from ~/.pretest/config.json\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\", false)\n .action(async (opts: { yes: boolean }) => {\n const code = await runLogout({ assumeYes: opts.yes === true });\n if (code !== 0) process.exit(code);\n });\n\n// ─── Global error handler ───────────────────────────────────────────────────\n\nfunction handleFatalError(err: unknown): void {\n if (err instanceof Error && err.message) {\n console.error(chalk.red(\"Error:\"), err.message);\n } else {\n console.error(chalk.red(\"An unexpected error occurred.\"));\n }\n process.exit(1);\n}\n\nprocess.on(\"uncaughtException\", handleFatalError);\nprocess.on(\"unhandledRejection\", handleFatalError);\n\n// ─── Parse and run ───────────────────────────────────────────────────────────\n\nprogram\n .showSuggestionAfterError(true)\n .showHelpAfterError(\"(use --help for available commands)\");\n\nprogram.parse();\n","/**\n * Pretest Core — Shared Types\n * All domain interfaces and enums used across the mutation pipeline.\n */\n\n// ─── Token Types ───────────────────────────────────────────────────────────────\n\nexport enum TokenType {\n Variable = \"Variable\",\n Function = \"Function\",\n Class = \"Class\",\n String = \"String\",\n /** Quoted HTTP header name (e.g. \"x-api-key\", \"Authorization\") — mutated to hide provider hints */\n HttpHeaderString = \"HttpHeaderString\",\n Comment = \"Comment\",\n Import = \"Import\",\n Property = \"Property\",\n Method = \"Method\",\n}\n\nexport interface Token {\n type: TokenType;\n value: string;\n start: number;\n end: number;\n line: number;\n}\n\n// ─── Scan ──────────────────────────────────────────────────────────────────────\n\nexport interface ScanResult {\n tokens: Token[];\n language: string;\n}\n\n// ─── Mutation ─────────────────────────────────────────────────────────────────\n\nexport interface MutationRule {\n /** Token type this rule targets */\n tokenType: TokenType;\n /** Whether to strip this token type entirely (e.g. comments) */\n strip?: boolean;\n /** Custom prefix to use instead of the default per-type prefix */\n prefix?: string;\n}\n\n/**\n * Maps every original token value to its mutated synthetic.\n * Used during forward mutation and exact reversal.\n */\nexport type MutationMap = Map<string, string>;\n\nexport interface MutationStats {\n tokensScanned: number;\n tokensMutated: number;\n durationMs: number;\n language: string;\n}\n\nexport interface MutationResult {\n mutatedCode: string;\n map: MutationMap;\n stats: MutationStats;\n}\n\n// ─── Store ────────────────────────────────────────────────────────────────────\n\nexport interface StoreEntry {\n id: string;\n originalHash: string;\n /** Serialized MutationMap (array of [original, synthetic] tuples) */\n mapEntries: [string, string][];\n /** Serialized secrets map (array of [placeholder, originalValue] tuples) for reversal */\n secretsMapEntries?: [string, string][];\n timestamp: number;\n language: string;\n}\n\n// ─── Proxy ────────────────────────────────────────────────────────────────────\n\nexport interface ProxyRequest {\n body: string;\n targetUrl: string;\n headers: Record<string, string>;\n}\n\nexport interface ProxyResponse {\n body: string;\n statusCode: number;\n reversed: boolean;\n}\n\n// ─── Config ───────────────────────────────────────────────────────────────────\n\nexport interface PretenseConfig {\n port: number;\n targetApis: string[];\n languages: string[];\n mutationRules: MutationRule[];\n storePath: string;\n}\n\nexport const DEFAULT_CONFIG: PretenseConfig = {\n port: 9339,\n targetApis: [\"https://api.anthropic.com\", \"https://api.openai.com\"],\n languages: [\"typescript\", \"javascript\", \"python\", \"go\", \"java\", \"csharp\", \"ruby\", \"rust\"],\n mutationRules: [\n { tokenType: TokenType.Variable, prefix: \"_v\" },\n { tokenType: TokenType.Function, prefix: \"_fn\" },\n { tokenType: TokenType.Class, prefix: \"_cls\" },\n { tokenType: TokenType.String },\n { tokenType: TokenType.Comment, strip: true },\n { tokenType: TokenType.Import },\n { tokenType: TokenType.Property, prefix: \"_prop\" },\n { tokenType: TokenType.Method, prefix: \"_fn\" },\n ],\n storePath: `${process.env[\"HOME\"] ?? \"/tmp\"}/.pretest`,\n};\n","/**\n * Pretest Core — Token Scanner\n *\n * Regex-based token scanner for TypeScript/JavaScript, Python, Go, and Java.\n * Extracts mutable tokens (variables, functions, classes, strings, imports,\n * comments) with exact positions for accurate reversal.\n *\n * No tree-sitter dependency — pure regex MVP, production-ready accuracy.\n */\n\nimport { TokenType, type Token, type ScanResult } from \"./types.js\";\n\n// ─── Language keyword sets ─────────────────────────────────────────────────────\n\nconst TS_JS_KEYWORDS = new Set([\n \"abstract\", \"any\", \"as\", \"async\", \"await\", \"boolean\", \"break\", \"case\",\n \"catch\", \"class\", \"const\", \"constructor\", \"continue\", \"debugger\", \"declare\",\n \"default\", \"delete\", \"do\", \"else\", \"enum\", \"export\", \"extends\", \"false\",\n \"finally\", \"for\", \"from\", \"function\", \"get\", \"if\", \"implements\", \"import\",\n \"in\", \"instanceof\", \"interface\", \"keyof\", \"let\", \"module\", \"namespace\",\n \"never\", \"new\", \"null\", \"number\", \"object\", \"of\", \"package\", \"private\",\n \"protected\", \"public\", \"readonly\", \"require\", \"return\", \"set\", \"static\",\n \"string\", \"super\", \"switch\", \"symbol\", \"this\", \"throw\", \"true\", \"try\",\n \"type\", \"typeof\", \"undefined\", \"unknown\", \"var\", \"void\", \"while\", \"with\",\n \"yield\", \"satisfies\", \"using\", \"infer\", \"asserts\",\n]);\n\nconst PYTHON_KEYWORDS = new Set([\n \"False\", \"None\", \"True\", \"and\", \"as\", \"assert\", \"async\", \"await\",\n \"break\", \"class\", \"continue\", \"def\", \"del\", \"elif\", \"else\", \"except\",\n \"finally\", \"for\", \"from\", \"global\", \"if\", \"import\", \"in\", \"is\",\n \"lambda\", \"nonlocal\", \"not\", \"or\", \"pass\", \"raise\", \"return\", \"try\",\n \"while\", \"with\", \"yield\", \"self\", \"cls\",\n]);\n\nconst GO_KEYWORDS = new Set([\n \"break\", \"case\", \"chan\", \"const\", \"continue\", \"default\", \"defer\", \"else\",\n \"fallthrough\", \"for\", \"func\", \"go\", \"goto\", \"if\", \"import\", \"interface\",\n \"map\", \"package\", \"range\", \"return\", \"select\", \"struct\", \"switch\", \"type\",\n \"var\", \"nil\", \"true\", \"false\", \"error\", \"string\", \"int\", \"int8\", \"int16\",\n \"int32\", \"int64\", \"uint\", \"uint8\", \"uint16\", \"uint32\", \"uint64\", \"float32\",\n \"float64\", \"complex64\", \"complex128\", \"bool\", \"byte\", \"rune\", \"uintptr\",\n \"make\", \"new\", \"len\", \"cap\", \"append\", \"copy\", \"close\", \"delete\", \"panic\",\n \"recover\", \"print\", \"println\",\n]);\n\nconst JAVA_KEYWORDS = new Set([\n \"abstract\", \"assert\", \"boolean\", \"break\", \"byte\", \"case\", \"catch\", \"char\",\n \"class\", \"const\", \"continue\", \"default\", \"do\", \"double\", \"else\", \"enum\",\n \"extends\", \"final\", \"finally\", \"float\", \"for\", \"goto\", \"if\", \"implements\",\n \"import\", \"instanceof\", \"int\", \"interface\", \"long\", \"native\", \"new\",\n \"package\", \"private\", \"protected\", \"public\", \"return\", \"short\", \"static\",\n \"strictfp\", \"super\", \"switch\", \"synchronized\", \"this\", \"throw\", \"throws\",\n \"transient\", \"try\", \"void\", \"volatile\", \"while\", \"true\", \"false\", \"null\",\n \"var\", \"record\", \"sealed\", \"permits\", \"yield\",\n]);\n\nconst CSHARP_KEYWORDS = new Set([\n \"class\", \"interface\", \"namespace\", \"public\", \"private\", \"protected\",\n \"internal\", \"static\", \"void\", \"return\", \"new\", \"using\", \"override\", \"sealed\",\n \"abstract\", \"virtual\", \"readonly\", \"const\", \"var\", \"int\", \"string\", \"bool\",\n \"double\", \"float\", \"object\", \"null\", \"true\", \"false\", \"if\", \"else\", \"for\",\n \"foreach\", \"while\", \"do\", \"switch\", \"case\", \"break\", \"continue\", \"try\",\n \"catch\", \"finally\", \"throw\", \"async\", \"await\", \"get\", \"set\", \"partial\",\n \"enum\", \"struct\", \"delegate\", \"event\",\n]);\n\nconst RUBY_KEYWORDS = new Set([\n \"def\", \"class\", \"module\", \"end\", \"do\", \"if\", \"else\", \"elsif\", \"unless\",\n \"while\", \"until\", \"for\", \"begin\", \"rescue\", \"ensure\", \"raise\", \"return\",\n \"yield\", \"self\", \"super\", \"true\", \"false\", \"nil\", \"and\", \"or\", \"not\", \"in\",\n \"then\", \"case\", \"when\", \"puts\", \"print\", \"require\", \"require_relative\",\n \"include\", \"extend\", \"attr_accessor\", \"attr_reader\", \"attr_writer\",\n \"initialize\", \"new\", \"public\", \"private\", \"protected\",\n]);\n\nconst RUST_KEYWORDS = new Set([\n \"fn\", \"struct\", \"enum\", \"trait\", \"impl\", \"mod\", \"pub\", \"let\", \"mut\",\n \"const\", \"type\", \"use\", \"crate\", \"self\", \"super\", \"move\", \"ref\", \"match\",\n \"if\", \"else\", \"loop\", \"while\", \"for\", \"return\", \"break\", \"continue\",\n \"where\", \"as\", \"in\", \"true\", \"false\", \"unsafe\", \"extern\", \"dyn\", \"box\",\n \"static\", \"async\", \"await\", \"Box\", \"String\", \"Vec\", \"Option\", \"Result\",\n \"Ok\", \"Err\", \"Some\", \"None\",\n]);\n\n// ─── Language detection ────────────────────────────────────────────────────────\n\n/**\n * Detect the programming language from code heuristics.\n *\n * @example\n * detectLanguage(\"const x: number = 1;\") // => \"typescript\"\n * detectLanguage(\"def foo(x):\\n return x\") // => \"python\"\n */\nexport function detectLanguage(code: string): string {\n if (/:[\\s]*\\w+[\\s]*[;,{)]/.test(code) || /import.*from\\s+['\"]/.test(code) || /interface\\s+\\w+/.test(code)) return \"typescript\";\n if (/\\bdef\\s+\\w+\\s*\\(/.test(code) || /\\bimport\\s+\\w+/.test(code) && /:$/.test(code)) return \"python\";\n if (/\\bfunc\\s+\\w+\\s*\\(/.test(code) || /\\bpackage\\s+\\w+/.test(code)) return \"go\";\n if (/\\bpublic\\s+class\\s+\\w+/.test(code) || /\\bimport\\s+java\\./.test(code)) return \"java\";\n if (/\\bnamespace\\s+\\w+/.test(code) || /\\busing\\s+System/.test(code)) return \"csharp\";\n if (/\\bfn\\s+\\w+\\s*\\(/.test(code) || /\\blet\\s+mut\\s+\\w+/.test(code)) return \"rust\";\n if (/\\bdef\\s+\\w+/.test(code) && /\\bend\\b/.test(code)) return \"ruby\";\n if (/\\bconst\\s+\\w+\\s*=/.test(code) || /\\bfunction\\s+\\w+\\s*\\(/.test(code)) return \"javascript\";\n return \"typescript\"; // default\n}\n\n// ─── Line-number helper ────────────────────────────────────────────────────────\n\n/**\n * Build a sorted array of newline byte offsets so we can convert any\n * index → 1-based line number in O(log lines) via binary search.\n *\n * Replaces the old per-call O(N) lineAt() walk. On a 400 KB file with\n * 7K tokens, the old impl was ~3 billion char comparisons (O(tokens × file))\n * which made the scanner appear to hang on real-world repos.\n */\nfunction buildLineIndex(code: string): number[] {\n const offsets: number[] = [];\n for (let i = 0; i < code.length; i++) {\n if (code.charCodeAt(i) === 10 /* \\n */) offsets.push(i);\n }\n return offsets;\n}\n\nfunction lineFromIndex(lineOffsets: number[], index: number): number {\n // Binary search for first newline >= index. Lines are 1-based.\n let lo = 0;\n let hi = lineOffsets.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (lineOffsets[mid]! < index) lo = mid + 1;\n else hi = mid;\n }\n return lo + 1;\n}\n\n// ─── Per-language scanners ─────────────────────────────────────────────────────\n\nfunction scanTypeScript(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n // Single-line comment\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\n // Multi-line comment\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\n // Quoted HTTP header names (fetch/axios headers objects) — mutated, not vendor-identifying literals\n { re: /\"(?:x-[a-z0-9][a-z0-9-]*|authorization|api-key)\"/gi, type: TokenType.HttpHeaderString },\n { re: /'(?:x-[a-z0-9][a-z0-9-]*|authorization|api-key)'/gi, type: TokenType.HttpHeaderString },\n // Unquoted `Authorization` key — value must start with a string/template (skips interface/type shapes)\n {\n re: /(?:\\{|\\,)\\s*(Authorization)\\s*:\\s*(?=[`'\"])/g,\n type: TokenType.HttpHeaderString,\n groupIndex: 1,\n },\n // Import source (the module path string)\n { re: /\\bimport\\b[^'\"]*['\"]([^'\"]+)['\"]/g, type: TokenType.Import, groupIndex: 1 },\n // Class name\n { re: /\\bclass\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Function/method name (function keyword)\n { re: /\\bfunction\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Function, groupIndex: 1 },\n // Arrow function assigned to const/let/var\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*[-.][A-Za-z0-9_$])\\s*=\\s*(?:async\\s*)?\\(/g, type: TokenType.Function, groupIndex: 1 },\n // Method: identifier followed by (\n { re: /\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\n // Env-style binding names with hyphens or dots (e.g. AWS-SECRET-KEY, AWS.SECRET.KEY) — not valid JS identifiers but common in pasted config\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*(?:(?:-|\\.)(?:[A-Za-z0-9_$]+))+)(?=\\s*=)/g, type: TokenType.Variable, groupIndex: 1 },\n // Variable declarations (exclude names continued with -/. so AWS-SECRET-KEY is captured only by the rule above)\n { re: /\\b(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*[-.][A-Za-z0-9_$])/g, type: TokenType.Variable, groupIndex: 1 },\n // Member receiver: matches in matches.push, row in row.patientId, def in def.name\n { re: /\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*(?:\\.|\\?\\.)[^0-9]/g, type: TokenType.Variable, groupIndex: 1 },\n // Property after . or ?. when not immediately followed by ( — method calls use Method rule\n { re: /\\.([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\n { re: /\\?\\.([A-Za-z_$][A-Za-z0-9_$]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\n // Template literals (preserve backtick wrapper)\n { re: /`[^`]*`/g, type: TokenType.String },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n // Single-quoted strings\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n // Skip language keywords for identifier tokens\n if (\n type === TokenType.Variable ||\n type === TokenType.Function ||\n type === TokenType.Class ||\n type === TokenType.Method ||\n type === TokenType.Property\n ) {\n if (TS_JS_KEYWORDS.has(captureValue)) continue;\n // Skip console/process/Object etc.\n if (/^(console|process|Object|Array|Math|JSON|Promise|Error|Map|Set|Date|RegExp|Symbol|Proxy|Reflect|global|globalThis|window|document|module|exports|require|__dirname|__filename|Intl|WebAssembly)$/.test(captureValue)) continue;\n // Skip single-character identifiers (loop vars, etc.)\n if (captureValue.length <= 1) continue;\n }\n\n // import.meta must stay verbatim for valid ESM\n if (\n type === TokenType.Property &&\n captureValue === \"meta\" &&\n code.slice(Math.max(0, captureStart - 7), captureStart) === \"import.\"\n ) {\n continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n const commentSpans = tokens.filter((t) => t.type === TokenType.Comment);\n const stringLikeSpans = tokens.filter(\n (t) => t.type === TokenType.String || t.type === TokenType.HttpHeaderString,\n );\n const dropsSpanOverlap = (t: Token) => {\n if (\n t.type === TokenType.Variable ||\n t.type === TokenType.Function ||\n t.type === TokenType.Class ||\n t.type === TokenType.Method ||\n t.type === TokenType.Property\n ) {\n if (commentSpans.some((c) => t.start < c.end && t.end > c.start)) return false;\n if (stringLikeSpans.some((s) => t.start < s.end && t.end > s.start)) return false;\n }\n return true;\n };\n\n return deduplicate(tokens.filter(dropsSpanOverlap));\n}\n\nfunction scanPython(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n // Triple-quoted docstrings\n { re: /\"\"\"[\\s\\S]*?\"\"\"|'''[\\s\\S]*?'''/g, type: TokenType.Comment },\n // Line comments\n { re: /#[^\\n]*/g, type: TokenType.Comment },\n // Import module name\n { re: /\\bimport\\s+([A-Za-z_][A-Za-z0-9_.]*)/g, type: TokenType.Import, groupIndex: 1 },\n { re: /\\bfrom\\s+([A-Za-z_.][A-Za-z0-9_.]*)\\s+import/g, type: TokenType.Import, groupIndex: 1 },\n // Class name\n { re: /\\bclass\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Function/method def\n { re: /\\bdef\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Function, groupIndex: 1 },\n // Call site: method name in obj.method(\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\n // obj.attr receiver and attribute (matches.push-style)\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*\\.\\s*(?=[a-zA-Z_])/g, type: TokenType.Variable, groupIndex: 1 },\n { re: /\\.([A-Za-z_][A-Za-z0-9_]*)\\b(?!\\s*\\()/g, type: TokenType.Property, groupIndex: 1 },\n // Variable assignment (simple name = ...)\n { re: /^([A-Za-z_][A-Za-z0-9_]*)\\s*=/gm, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n // Single-quoted strings\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Function ||\n type === TokenType.Class ||\n type === TokenType.Method ||\n type === TokenType.Property\n ) {\n if (PYTHON_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n // Skip dunder methods/vars\n if (captureValue.startsWith(\"__\") && captureValue.endsWith(\"__\")) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n const pyCommentSpans = tokens.filter((t) => t.type === TokenType.Comment);\n const pyStringSpans = tokens.filter((t) => t.type === TokenType.String);\n const dropsPyOverlap = (t: Token) => {\n if (\n t.type === TokenType.Variable ||\n t.type === TokenType.Function ||\n t.type === TokenType.Class ||\n t.type === TokenType.Method ||\n t.type === TokenType.Property\n ) {\n if (pyCommentSpans.some((c) => t.start < c.end && t.end > c.start)) return false;\n if (pyStringSpans.some((s) => t.start < s.end && t.end > s.start)) return false;\n }\n return true;\n };\n\n return deduplicate(tokens.filter(dropsPyOverlap));\n}\n\nfunction scanGo(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\n // Import path\n { re: /import\\s*\\(\\s*([\\s\\S]*?)\\s*\\)/g, type: TokenType.Import },\n { re: /import\\s+\"([^\"]+)\"/g, type: TokenType.Import, groupIndex: 1 },\n // Type declaration\n { re: /\\btype\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+(?:struct|interface)/g, type: TokenType.Class, groupIndex: 1 },\n // Func name\n { re: /\\bfunc\\s+(?:\\([^)]*\\)\\s*)?([A-Za-z_][A-Za-z0-9_]*)\\s*\\(/g, type: TokenType.Function, groupIndex: 1 },\n // Var/const declaration\n { re: /\\b(?:var|const)\\s+([A-Za-z_][A-Za-z0-9_]*)\\b/g, type: TokenType.Variable, groupIndex: 1 },\n // Short variable declaration\n { re: /\\b([A-Za-z_][A-Za-z0-9_]*)\\s*:=/g, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n // Backtick raw strings\n { re: /`[^`]*`/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Function ||\n type === TokenType.Class\n ) {\n if (GO_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n return deduplicate(tokens);\n}\n\nfunction scanJava(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\n // Import statement\n { re: /\\bimport\\s+([\\w.]+);/g, type: TokenType.Import, groupIndex: 1 },\n // Class/interface/enum\n { re: /\\b(?:class|interface|enum|record)\\s+([A-Za-z_$][A-Za-z0-9_$]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Method declaration\n { re: /\\b(?:public|private|protected|static|final|abstract|synchronized|native|default)[\\w\\s<>\\[\\],]*\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\n // Variable declaration\n { re: /\\b(?:int|long|double|float|boolean|char|byte|short|String|Object|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\s*[=;,)]/g, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Method ||\n type === TokenType.Class\n ) {\n if (JAVA_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n // Skip common stdlib class names\n if (/^(String|Object|Integer|Long|Double|Boolean|List|Map|Set|Array|Exception|Error|System|Math|Thread|Class|Enum)$/.test(captureValue)) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n return deduplicate(tokens);\n}\n\nfunction scanCSharp(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\n // Namespace/using import\n { re: /\\busing\\s+([\\w.]+);/g, type: TokenType.Import, groupIndex: 1 },\n // Class/interface/struct/enum names\n { re: /\\b(?:class|interface|struct|enum)\\s+([A-Za-z_][A-Za-z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Method/property declaration\n { re: /\\b(?:public|private|protected|internal|static|virtual|override|async)\\s+(?:\\w+\\s+)+([a-zA-Z_]\\w*)\\s*\\(/g, type: TokenType.Method, groupIndex: 1 },\n // Local variable declarations\n { re: /\\b(?:var|int|string|bool|double|float|object)\\s+([a-zA-Z_]\\w*)\\b/g, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n // Verbatim strings\n { re: /@\"(?:[^\"]|\"\")*\"/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Method ||\n type === TokenType.Class\n ) {\n if (CSHARP_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n if (/^(String|Object|Integer|Boolean|Double|Float|List|Dictionary|Array|Exception|Task|Console|Math|Enum|Delegate)$/.test(captureValue)) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n return deduplicate(tokens);\n}\n\nfunction scanRuby(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n // Single-line comment\n { re: /#[^\\n]*/g, type: TokenType.Comment },\n // Method names\n { re: /\\bdef\\s+([a-zA-Z_]\\w*[!?]?)/g, type: TokenType.Function, groupIndex: 1 },\n // Class and module names\n { re: /\\b(?:class|module)\\s+([A-Z][a-zA-Z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Instance variables\n { re: /@([a-zA-Z_]\\w*)/g, type: TokenType.Property, groupIndex: 1 },\n // All-caps constants (3+ chars to avoid single-letter constants)\n { re: /\\b([A-Z][A-Z0-9_]{2,})\\b/g, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n // Single-quoted strings\n { re: /'(?:[^'\\\\]|\\\\.)*'/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Function ||\n type === TokenType.Class ||\n type === TokenType.Property\n ) {\n if (RUBY_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n return deduplicate(tokens);\n}\n\nfunction scanRust(code: string): Token[] {\n const tokens: Token[] = [];\n if (!code.trim()) return tokens;\n const lineOffsets = buildLineIndex(code);\n\n const patterns: Array<{ re: RegExp; type: TokenType; groupIndex?: number }> = [\n { re: /\\/\\/[^\\n]*/g, type: TokenType.Comment },\n { re: /\\/\\*[\\s\\S]*?\\*\\//g, type: TokenType.Comment },\n // Use declarations\n { re: /\\buse\\s+([\\w:]+)/g, type: TokenType.Import, groupIndex: 1 },\n // Named type declarations (struct, enum, trait)\n { re: /\\b(?:struct|enum|trait)\\s+([A-Z][a-zA-Z0-9_]*)/g, type: TokenType.Class, groupIndex: 1 },\n // Function names\n { re: /\\bfn\\s+([a-zA-Z_]\\w*)/g, type: TokenType.Function, groupIndex: 1 },\n // Constants (ALL_CAPS)\n { re: /\\bconst\\s+([A-Z_][A-Z0-9_]*)\\s*:/g, type: TokenType.Variable, groupIndex: 1 },\n // Variable bindings\n { re: /\\blet\\s+(?:mut\\s+)?([a-zA-Z_]\\w*)/g, type: TokenType.Variable, groupIndex: 1 },\n // Double-quoted strings\n { re: /\"(?:[^\"\\\\]|\\\\.)*\"/g, type: TokenType.String },\n ];\n\n for (const { re, type, groupIndex } of patterns) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(code)) !== null) {\n const fullMatch = m[0];\n const captureValue = groupIndex !== undefined ? (m[groupIndex] ?? fullMatch) : fullMatch;\n const captureStart = groupIndex !== undefined\n ? m.index + fullMatch.indexOf(captureValue)\n : m.index;\n\n if (!captureValue || captureValue.trim() === \"\") continue;\n\n if (\n type === TokenType.Variable ||\n type === TokenType.Function ||\n type === TokenType.Class\n ) {\n if (RUST_KEYWORDS.has(captureValue)) continue;\n if (captureValue.length <= 1) continue;\n }\n\n tokens.push({\n type,\n value: captureValue,\n start: captureStart,\n end: captureStart + captureValue.length,\n line: lineFromIndex(lineOffsets, captureStart),\n });\n }\n }\n\n return deduplicate(tokens);\n}\n\n// ─── Deduplication ────────────────────────────────────────────────────────────\n\nfunction deduplicate(tokens: Token[]): Token[] {\n tokens.sort((a, b) => a.start - b.start);\n const seen = new Set<string>();\n const result: Token[] = [];\n for (const token of tokens) {\n const key = `${token.start}:${token.end}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push(token);\n }\n }\n return result;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Scan source code and extract mutable tokens with their positions.\n *\n * @example\n * const result = scan(\"const greeting = 'hello';\", \"typescript\");\n * result.tokens.map(t => t.value) // => [\"greeting\", \"'hello'\"]\n */\nexport function scan(code: string, language: string): ScanResult {\n if (!code || !code.trim()) {\n return { tokens: [], language };\n }\n\n const lang = language.toLowerCase();\n let tokens: Token[];\n\n switch (lang) {\n case \"typescript\":\n case \"javascript\":\n case \"ts\":\n case \"js\":\n case \"tsx\":\n case \"jsx\":\n tokens = scanTypeScript(code);\n break;\n case \"python\":\n case \"py\":\n tokens = scanPython(code);\n break;\n case \"go\":\n tokens = scanGo(code);\n break;\n case \"java\":\n tokens = scanJava(code);\n break;\n case \"csharp\":\n case \"cs\":\n tokens = scanCSharp(code);\n break;\n case \"ruby\":\n case \"rb\":\n tokens = scanRuby(code);\n break;\n case \"rust\":\n case \"rs\":\n tokens = scanRust(code);\n break;\n default:\n tokens = scanTypeScript(code);\n }\n\n return { tokens, language: lang };\n}\n","/**\n * Pretest — Mutation Salt Manager\n *\n * Per-installation random salt for mutation hashing.\n * Stored at ~/.pretest/mutation.salt, never transmitted.\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, renameSync } from \"fs\";\nimport { join } from \"path\";\nimport { homedir } from \"os\";\nimport { randomBytes } from \"crypto\";\nimport {\n migrateLegacyProjectConfigDir,\n PROJECT_CONFIG_DIR_NAME,\n LEGACY_PROJECT_CONFIG_DIR_NAME,\n} from \"./config-dir.js\";\n\nconst SALT_BYTES = 32;\n\n// Paths are computed lazily so that tests can override HOME before calling getMutationSalt()\nfunction getSaltPath(): { dir: string; path: string } {\n const home = homedir();\n migrateLegacyProjectConfigDir(home);\n const dir = join(home, PROJECT_CONFIG_DIR_NAME);\n const legacyDir = join(home, LEGACY_PROJECT_CONFIG_DIR_NAME);\n const path = join(dir, \"mutation.salt\");\n const legacySalt = join(legacyDir, \"mutation.salt\");\n if (!existsSync(path) && existsSync(legacySalt)) {\n try {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n renameSync(legacySalt, path);\n } catch {\n /* keep trying reads below */\n }\n }\n return { dir, path };\n}\n\nlet _cachedSalt: string | null = null;\n\nexport function getMutationSalt(): string {\n if (_cachedSalt) return _cachedSalt;\n\n const { dir, path } = getSaltPath();\n\n if (existsSync(path)) {\n try {\n const raw = readFileSync(path, \"utf-8\").trim();\n if (/^[0-9a-f]{64}$/i.test(raw)) {\n _cachedSalt = raw.toLowerCase();\n return _cachedSalt;\n }\n } catch {\n // fall through\n }\n }\n\n const salt = randomBytes(SALT_BYTES).toString(\"hex\");\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(path, salt, { mode: 0o600 });\n } catch {\n // in-memory only if FS is read-only\n }\n\n _cachedSalt = salt;\n return salt;\n}\n\nexport function buildSaltedSeed(baseSeed: string): string {\n return `${baseSeed}:${getMutationSalt()}`;\n}\n\n/**\n * Default CLI seeds `pretense` (legacy input) and `pretest` both resolve to the same\n * salted material as historic `pretense` so existing mutation maps stay stable.\n */\nexport function effectiveSeedForMutation(userSeed: string): string {\n if (userSeed === \"pretense\" || userSeed === \"pretest\") {\n return buildSaltedSeed(\"pretense\");\n }\n return userSeed;\n}\n\n/** @internal */\nexport function _resetSaltCache(): void {\n _cachedSalt = null;\n}\n","import { existsSync, renameSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** Project-local config (mutation map, usage, audit, etc.) */\nexport const PROJECT_CONFIG_DIR_NAME = \".pretest\";\nexport const LEGACY_PROJECT_CONFIG_DIR_NAME = \".pretense\";\n\n/** Rename legacy `.pretense` → `.pretest` when the new dir is absent (one-time per directory). */\nexport function migrateLegacyProjectConfigDir(parentDir: string): void {\n const next = join(parentDir, PROJECT_CONFIG_DIR_NAME);\n const prev = join(parentDir, LEGACY_PROJECT_CONFIG_DIR_NAME);\n if (existsSync(next)) return;\n if (!existsSync(prev)) return;\n try {\n renameSync(prev, next);\n } catch {\n /* ignore cross-device / permissions */\n }\n}\n","/**\n * Deterministic synthetic identifiers — shared by identifier mutation\n * and secret-span placeholders (same hash + seed semantics).\n */\n\nfunction hash32(str: string): number {\n let h = 5381;\n for (let i = 0; i < str.length; i++) {\n h = ((h << 5) + h) ^ str.charCodeAt(i);\n }\n return h >>> 0;\n}\n\nfunction toAlphaNum(n: number, len: number): string {\n const CHARS = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let result = \"\";\n let v = n;\n for (let i = 0; i < len; i++) {\n result = CHARS[v % CHARS.length]! + result;\n v = Math.floor(v / CHARS.length);\n }\n return result;\n}\n\n/**\n * @example deterministicSyntheticId(\"getUserById\", seed, \"_fn\") // => \"_fnx3k7\"\n */\nexport function deterministicSyntheticId(original: string, seed: string, prefix: string, len = 4): string {\n const combined = `${seed}:${prefix}:${original}`;\n const h = hash32(combined);\n return prefix + toAlphaNum(h, len);\n}\n","/**\n * Pretest Core — Deterministic Mutation Engine\n *\n * Replaces identifiers, strings, and comments with synthetic tokens.\n * Same input + same seed always produces the same output (seeded PRNG).\n * Tracks every substitution in a MutationMap for exact reversal.\n */\n\nimport { TokenType, type MutationMap, type MutationResult, type MutationStats } from \"./types.js\";\nimport { scan, detectLanguage } from \"./scanner.js\";\nimport { effectiveSeedForMutation } from \"./salt.js\";\nimport { deterministicSyntheticId } from \"./deterministic-id.js\";\n\n// ─── Mutation logic ────────────────────────────────────────────────────────────\n\nfunction prefixForType(type: TokenType): string {\n switch (type) {\n case TokenType.Class: return \"_cls\";\n case TokenType.Function:\n case TokenType.Method: return \"_fn\";\n case TokenType.Variable: return \"_v\";\n case TokenType.Property: return \"_prop\";\n case TokenType.HttpHeaderString: return \"_hk\";\n default: return \"_tok\";\n }\n}\n\n/**\n * Mutate source code deterministically. Returns mutated code and the\n * MutationMap needed to reverse it.\n *\n * @param code - Source code string\n * @param language - Language identifier (\"typescript\", \"python\", \"go\", \"java\")\n * @param seed - Optional seed for determinism (default: \"pretest\")\n *\n * @example\n * const { mutatedCode, map } = mutate(\"const apiKey = 'secret';\", \"typescript\");\n * mutatedCode // => \"const _va1b2 = '_strc3d4';\"\n */\nexport function mutate(code: string, language?: string, seed = \"pretest\"): MutationResult {\n const startMs = performance.now();\n const lang = language ?? detectLanguage(code);\n\n if (!code || !code.trim()) {\n const emptyMap: MutationMap = new Map();\n return {\n mutatedCode: code,\n map: emptyMap,\n stats: { tokensScanned: 0, tokensMutated: 0, durationMs: 0, language: lang },\n };\n }\n\n // Mix in per-installation salt when using the default seed (production path).\n // This prevents dictionary brute-force reversal of mutation hashes.\n const effectiveSeed = effectiveSeedForMutation(seed);\n\n const { tokens } = scan(code, lang);\n const map: MutationMap = new Map<string, string>();\n\n // Build mutation map — one synthetic per unique original value\n for (const token of tokens) {\n if (map.has(token.value)) continue; // already mapped\n\n if (token.type === TokenType.Comment) {\n // Comments preserved verbatim — stripping breaks round-trip\n continue;\n }\n\n if (token.type === TokenType.String) {\n // Strings preserved verbatim — mutations break round-trip for multi-line strings\n continue;\n }\n\n if (token.type === TokenType.HttpHeaderString) {\n const qm = /^(\"|')(.+)\\1$/.exec(token.value);\n if (qm) {\n const inner = qm[2]!;\n const q = qm[1]!;\n const syntheticInner = deterministicSyntheticId(inner, effectiveSeed, prefixForType(TokenType.HttpHeaderString));\n map.set(token.value, `${q}${syntheticInner}${q}`);\n } else {\n // Bare property name (e.g. Authorization: `Bearer …`)\n const syntheticInner = deterministicSyntheticId(token.value, effectiveSeed, prefixForType(TokenType.HttpHeaderString));\n map.set(token.value, syntheticInner);\n }\n continue;\n }\n\n if (token.type === TokenType.Import) {\n // Keep import paths intact — they refer to packages, not IP\n continue;\n }\n\n const prefix = prefixForType(token.type);\n const synthetic = deterministicSyntheticId(token.value, effectiveSeed, prefix);\n map.set(token.value, synthetic);\n }\n\n // Apply substitutions — longest-first to avoid partial match issues\n const entries = [...map.entries()].sort((a, b) => b[0].length - a[0].length);\n\n let mutatedCode = code;\n for (const [original, synthetic] of entries) {\n if (!synthetic) continue;\n // Use word-boundary aware replacement for identifiers\n const escaped = original.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n if (original.match(/^[A-Za-z_$][A-Za-z0-9_$]*$/)) {\n // Identifier: use word boundaries\n mutatedCode = mutatedCode.replace(new RegExp(`\\\\b${escaped}\\\\b`, \"g\"), synthetic);\n } else {\n // String literals or other: exact replacement\n mutatedCode = mutatedCode.split(original).join(synthetic);\n }\n }\n\n const durationMs = Math.round((performance.now() - startMs) * 100) / 100;\n\n return {\n mutatedCode,\n map,\n stats: {\n tokensScanned: tokens.length,\n tokensMutated: map.size,\n durationMs,\n language: lang,\n },\n };\n}\n","/**\n * Pretest Core — Exact Reverser\n *\n * Uses the MutationMap produced by mutate() to restore original code.\n * Applies replacements longest-first to prevent partial-match bugs.\n * After reversal, output must equal the original input byte-for-byte.\n */\n\nimport type { MutationMap } from \"./types.js\";\n\n/**\n * Reverse a previously mutated string back to the original.\n * Throws if the map contains entries whose synthetic values are not\n * present in the mutated code (indicates map/code mismatch).\n *\n * @param mutatedCode - Code that was produced by mutate()\n * @param map - The MutationMap returned by the same mutate() call\n * @param secretsMap - Optional map of synthetic secret placeholders (`_sl…`) → original values\n *\n * @example\n * const { mutatedCode, map } = mutate(\"const apiKey = 'secret';\", \"typescript\");\n * reverse(mutatedCode, map) // => \"const apiKey = 'secret';\"\n */\nexport function reverse(mutatedCode: string, map: MutationMap, secretsMap?: Map<string, string>): string {\n if (!mutatedCode) return mutatedCode;\n\n let result = mutatedCode;\n\n // 1. Restore identifiers from the mutation map\n if (map.size > 0) {\n const reverseMap = new Map<string, string>();\n for (const [original, synthetic] of map.entries()) {\n if (synthetic === \"\" || !synthetic) continue;\n reverseMap.set(synthetic, original);\n }\n\n if (reverseMap.size > 0) {\n const sortedEntries = [...reverseMap.entries()].sort((a, b) => b[0].length - a[0].length);\n\n for (const [synthetic, original] of sortedEntries) {\n const escaped = synthetic.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n if (synthetic.match(/^[A-Za-z_$][A-Za-z0-9_$]*$/) || synthetic.match(/^_[a-z]+[a-z0-9]{4,}$/)) {\n result = result.replace(new RegExp(`\\\\b${escaped}\\\\b`, \"g\"), original);\n } else {\n result = result.split(synthetic).join(original);\n }\n }\n }\n }\n\n // 2. Restore secret values from the secrets map\n if (secretsMap && secretsMap.size > 0) {\n const sortedSecrets = [...secretsMap.entries()].sort((a, b) => b[0].length - a[0].length);\n for (const [placeholder, original] of sortedSecrets) {\n result = result.split(placeholder).join(original);\n }\n }\n\n return result;\n}\n","/**\n * Pretest Core — Secret Detection Engine\n *\n * 40+ regex patterns for API keys, tokens, credentials, and PII.\n * Sub-5ms per scan. Zero dependencies beyond regex.\n * Includes Shannon entropy check for high-entropy strings.\n */\n\nimport { buildSaltedSeed } from \"./salt.js\";\nimport { deterministicSyntheticId } from \"./deterministic-id.js\";\n\nexport type ScanCategory = \"secret\" | \"pii\" | \"credential\" | \"proprietary\";\nexport type ScanAction = \"block\" | \"redact\" | \"mutate\" | \"warn\" | \"pass\";\nexport type ScanSeverity = \"critical\" | \"high\" | \"medium\" | \"low\";\n\nexport interface ScanMatch {\n id: string;\n category: ScanCategory;\n type: string;\n value: string;\n masked: string;\n start: number;\n end: number;\n severity: ScanSeverity;\n action: ScanAction;\n}\n\nexport interface SecretScanResult {\n clean: boolean;\n matches: ScanMatch[];\n scannedAt: number;\n durationMs: number;\n}\n\ninterface PatternDef {\n name: string;\n category: ScanCategory;\n severity: ScanSeverity;\n defaultAction: ScanAction;\n /** Must include flag `d` so `exec` returns `indices` for this group. */\n pattern: RegExp;\n validate?: (match: string) => boolean;\n /**\n * When set, only this capture group's span is redacted and stored as `value`\n * (avoids eating `TOKEN =` / quotes into the placeholder and secretsMap).\n */\n valueGroup?: number;\n}\n\nconst SECRET_PATTERNS: PatternDef[] = [\n { name: \"anthropic-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sk-ant-api\\d{2}-[A-Za-z0-9_-]{40,}/g },\n /** Legacy `sk-…` and modern `sk-proj-…` (hyphenated body); aligned with upstream scanner heuristics */\n { name: \"openai-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g },\n { name: \"aws-access-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /AKIA[0-9A-Z]{16}/g },\n /** `AWS_SECRET = '…40 chars…'` (not `AWS_SECRET_ACCESS_KEY`, which is covered below). */\n { name: \"aws-secret-assignment\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bAWS_SECRET\\s*=\\s*['\"]([A-Za-z0-9/+=]{40})['\"]/gd, valueGroup: 1 },\n /**\n * Env-style labels with `-` or `.` (e.g. `AWS-SECRET-KEY`, `AWS.SECRET.KEY`, long `ACCESS` forms).\n * Case-insensitive `AWS` / `SECRET` / `KEY`. Value: 40-char secret; quotes optional (matches aws-secret-key).\n */\n {\n name: \"aws-secret-key-delimited\",\n category: \"secret\",\n severity: \"critical\",\n defaultAction: \"block\",\n pattern: /\\bAWS[-.]SECRET(?:[-.]ACCESS)?[-.]KEY\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gdi,\n valueGroup: 1,\n },\n { name: \"aws-secret-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\\s*[=:]\\s*['\"]?([A-Za-z0-9/+=]{40})['\"]?/gd, valueGroup: 1 },\n { name: \"github-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /gh[ps]_[A-Za-z0-9_]{36,}/g },\n { name: \"github-fine-grained\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /github_pat_[A-Za-z0-9_]{22,}/g },\n { name: \"stripe-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:sk|pk|rk)_(?:test|live)_[A-Za-z0-9]{20,}/g },\n { name: \"private-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g },\n /** Three base64url JWT segments; payload segment is not required to start with `eyJ` (Supabase and many issuers use compact payloads). */\n { name: \"jwt-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{4,}/g },\n { name: \"database-url\", category: \"credential\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:postgres|mysql|mongodb|redis|amqp):\\/\\/[^\\s'\"\\\\)]+:[^\\s'\"\\\\)]+@[^\\s'\"\\\\)]+/g },\n {\n name: \"generic-password\",\n category: \"credential\",\n severity: \"high\",\n defaultAction: \"redact\",\n // Do not match `token` / `secret` inside identifiers (e.g. GITHUB_TOKEN, AWS_SECRET): require no word/underscore before keyword.\n pattern: /(?<![A-Za-z0-9_])(?:password|passwd|pwd|secret|token|api_key|apikey|api-key)\\s*[=:]\\s*['\"]([^\\s'\"]{8,})['\"]/gid,\n valueGroup: 1,\n },\n { name: \"slack-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /xox[bpors]-[A-Za-z0-9-]{10,}/g },\n { name: \"google-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /AIza[A-Za-z0-9_-]{35}/g },\n { name: \"npm-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /npm_[A-Za-z0-9]{36}/g },\n { name: \"sendgrid-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}/g },\n { name: \"twilio-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /SK[a-f0-9]{32}/g },\n // ─── Additional patterns (v0.3) ──────────────────────────────────────────────\n { name: \"azure-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /(?:AccountKey|SharedAccessKey)=[A-Za-z0-9+/=]{40,}/g },\n { name: \"mailgun-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /key-[a-f0-9]{32}/g },\n { name: \"twilio-sid\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /AC[a-f0-9]{32}/g },\n { name: \"heroku-api-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /[hH]eroku.*[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g },\n { name: \"shopify-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /shpat_[a-fA-F0-9]{32}/g },\n { name: \"datadog-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /dd[a-z]{1,2}_[a-zA-Z0-9]{32,}/g },\n { name: \"vercel-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /vc_[a-zA-Z0-9]{24,}/g },\n { name: \"supabase-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /sbp_[a-f0-9]{40}/g },\n { name: \"linear-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /lin_api_[A-Za-z0-9]{40}/g },\n { name: \"cloudflare-api-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /v1\\.0-[a-f0-9]{24}-[a-f0-9]{146}/g },\n { name: \"discord-bot-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /[MN][A-Za-z\\d]{23,}\\.[\\w-]{6}\\.[\\w-]{27}/g },\n { name: \"grafana-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /eyJrIjoi[A-Za-z0-9_-]{40,}/g },\n { name: \"confluent-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /CONFLUENT[A-Z_]*\\s*[=:]\\s*['\"]?[A-Za-z0-9/+=]{16,}['\"]?/g },\n { name: \"digitalocean-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /dop_v1_[a-f0-9]{64}/g },\n { name: \"doppler-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /dp\\.st\\.[a-z0-9_-]{2,}\\.[A-Za-z0-9]{40,}/g },\n { name: \"planetscale-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /pscale_tkn_[A-Za-z0-9_-]{32,}/g },\n { name: \"hashicorp-vault-token\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /hvs\\.[A-Za-z0-9_-]{24,}/g },\n { name: \"fastly-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /fastly_[A-Za-z0-9]{32}/g },\n { name: \"algolia-api-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /[a-f0-9]{32}/g, validate: (m) => /ALGOLIA|algolia/.test(m) },\n { name: \"pulumi-token\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /pul-[a-f0-9]{40}/g },\n // ─── Extended patterns (v0.6 unit 8) ─────────────────────────────────────────\n { name: \"google-oauth-refresh\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bGOCSPX-[A-Za-z0-9_-]{20,}\\b/g },\n { name: \"slack-webhook-url\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /https:\\/\\/hooks\\.slack\\.com\\/services\\/T[A-Z0-9]+\\/B[A-Z0-9]+\\/[A-Za-z0-9]{20,}/g },\n { name: \"sentry-dsn\", category: \"secret\", severity: \"high\", defaultAction: \"redact\", pattern: /https:\\/\\/[a-f0-9]{32}@o\\d+\\.ingest\\.sentry\\.io\\/\\d+/g },\n { name: \"x509-certificate\", category: \"secret\", severity: \"high\", defaultAction: \"redact\", pattern: /-----BEGIN CERTIFICATE-----/g },\n { name: \"launchdarkly-sdk-key\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bsdk-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g },\n { name: \"launchdarkly-mobile-key\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /\\bmob-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g },\n /** Stripe signing secrets are often 32+ chars; allow shorter synthetic/test tails so redaction still applies. */\n { name: \"stripe-webhook-secret\", category: \"secret\", severity: \"critical\", defaultAction: \"block\", pattern: /\\bwhsec_[A-Za-z0-9]{16,}\\b/g },\n /** Stripe Price / product IDs (`price_…`) — identifiers, not card data, but leak billing context. */\n { name: \"stripe-price-id\", category: \"secret\", severity: \"high\", defaultAction: \"block\", pattern: /\\bprice_[A-Za-z0-9_]{14,}\\b/g },\n /** `FOO_PASSWORD = '…'` / `NEXT_PUBLIC_*_PASSWORD` — generic-password skips when `password` is preceded by `_`. */\n {\n name: \"env-password-assignment\",\n category: \"credential\",\n severity: \"high\",\n defaultAction: \"block\",\n pattern: /\\b[A-Z][A-Z0-9_]*PASSWORD\\s*=\\s*['\"]([^'\"]{6,})['\"]/gd,\n valueGroup: 1,\n },\n /** Quoted common DB dialect names — stack hints when mutating env-style config. */\n {\n name: \"quoted-db-dialect\",\n category: \"credential\",\n severity: \"medium\",\n defaultAction: \"block\",\n pattern: /(['\"])(postgres|mysql|redis)\\1/gd,\n valueGroup: 2,\n },\n];\n\nconst PII_PATTERNS: PatternDef[] = [\n { name: \"ssn\", category: \"pii\", severity: \"critical\", defaultAction: \"redact\", pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g },\n { name: \"credit-card\", category: \"pii\", severity: \"critical\", defaultAction: \"redact\", pattern: /\\b(?:\\d[ -]*?){13,19}\\b/g, validate: luhnCheck },\n { name: \"email\", category: \"pii\", severity: \"medium\", defaultAction: \"warn\", pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g },\n { name: \"phone-us\", category: \"pii\", severity: \"medium\", defaultAction: \"warn\", pattern: /\\b(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b/g },\n { name: \"ip-address\", category: \"pii\", severity: \"low\", defaultAction: \"warn\", pattern: /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g, validate: (ip) => !ip.startsWith(\"127.\") && !ip.startsWith(\"0.\") && ip !== \"255.255.255.255\" },\n];\n\nconst ENV_PATTERNS: PatternDef[] = [\n { name: \"env-secret\", category: \"credential\", severity: \"high\", defaultAction: \"block\", pattern: /(?:process\\.env\\.|os\\.environ\\[|ENV\\[|getenv\\()['\"]?((?:SECRET|TOKEN|PASSWORD|API_KEY|PRIVATE|AUTH)[A-Z_0-9]*)['\"]?\\]?\\)?/gi },\n];\n\nfunction luhnCheck(num: string): boolean {\n const digits = num.replace(/\\D/g, \"\");\n if (digits.length < 13 || digits.length > 19) return false;\n let sum = 0;\n let alternate = false;\n for (let i = digits.length - 1; i >= 0; i--) {\n let n = parseInt(digits[i]!, 10);\n if (alternate) { n *= 2; if (n > 9) n -= 9; }\n sum += n;\n alternate = !alternate;\n }\n return sum % 10 === 0;\n}\n\n// ─── Shannon entropy check ────────────────────────────────────────────────────\n\n/**\n * Calculate Shannon entropy of a string. Higher values indicate more randomness.\n * Useful for detecting high-entropy strings that may be secrets/tokens.\n */\nexport function shannonEntropy(str: string): number {\n if (str.length === 0) return 0;\n const freq = new Map<string, number>();\n for (const ch of str) {\n freq.set(ch, (freq.get(ch) ?? 0) + 1);\n }\n let entropy = 0;\n const len = str.length;\n for (const count of freq.values()) {\n const p = count / len;\n if (p > 0) entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\n/**\n * Check if a string is likely a high-entropy secret.\n * Returns true if the string is > 20 chars and has entropy > 4.5.\n */\nexport function isHighEntropy(str: string, minLength = 20, threshold = 4.5): boolean {\n if (str.length <= minLength) return false;\n return shannonEntropy(str) > threshold;\n}\n\nfunction maskValue(value: string, type: string): string {\n if (type.includes(\"key\") || type.includes(\"token\") || type.includes(\"secret\")) return value.slice(0, 6) + \"...\" + value.slice(-4);\n if (type === \"ssn\") return \"***-**-\" + value.slice(-4);\n if (type === \"credit-card\") return \"****-****-****-\" + value.replace(/\\D/g, \"\").slice(-4);\n if (type === \"email\") { const [local, domain] = value.split(\"@\"); return (local?.[0] ?? \"*\") + \"***@\" + (domain ?? \"\"); }\n if (value.length > 12) return value.slice(0, 4) + \"...\" + value.slice(-4);\n return \"***\";\n}\n\nlet matchCounter = 0;\n\n// Files larger than this byte budget skip the expensive entropy sweep.\n// Big generated/minified files trigger millions of high-entropy candidates\n// and produce no useful signal — the regex-pattern pass still runs.\nconst ENTROPY_SCAN_MAX_BYTES = 512 * 1024; // 512 KB\n\nexport function scan(text: string, actionOverrides?: Partial<Record<string, ScanAction>>): SecretScanResult {\n const start = performance.now();\n const matches: ScanMatch[] = [];\n const allPatterns = [...SECRET_PATTERNS, ...PII_PATTERNS, ...ENV_PATTERNS];\n\n for (const def of allPatterns) {\n def.pattern.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = def.pattern.exec(text)) !== null) {\n let value = m[0];\n let start = m.index;\n let end = start + value.length;\n\n if (def.valueGroup !== undefined) {\n const span = m.indices?.[def.valueGroup];\n if (!span) continue;\n const [gs, ge] = span;\n value = text.slice(gs, ge);\n start = gs;\n end = ge;\n }\n\n if (def.validate && !def.validate(value)) continue;\n const action = actionOverrides?.[def.name] ?? def.defaultAction;\n matchCounter++;\n matches.push({\n id: `scan_${matchCounter}`,\n category: def.category,\n type: def.name,\n value,\n masked: maskValue(value, def.name),\n start,\n end,\n severity: def.severity,\n action,\n });\n }\n }\n\n // Shannon entropy check for unquoted high-entropy strings.\n // Skipped for very large inputs to avoid pathological O(N) regex sweeps\n // and the O(N) covered-range check below.\n if (text.length <= ENTROPY_SCAN_MAX_BYTES) {\n // Pre-sort regex matches by start index so we can skip already-covered\n // regions in O(log N) instead of O(N) per entropy candidate. Without this\n // the entropy pass becomes catastrophic on large files.\n const sortedByStart = [...matches].sort((a, b) => a.start - b.start);\n const coveredEnd = (idx: number): number => {\n // Returns the largest end-index of any match whose start <= idx.\n let lo = 0;\n let hi = sortedByStart.length - 1;\n let best = -1;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n if (sortedByStart[mid]!.start <= idx) {\n best = mid;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n return best >= 0 ? sortedByStart[best]!.end : -1;\n };\n\n const highEntropyPattern = /\\b[A-Za-z0-9_\\-/.+=$]{21,}\\b/g;\n highEntropyPattern.lastIndex = 0;\n let hem: RegExpExecArray | null;\n while ((hem = highEntropyPattern.exec(text)) !== null) {\n const value = hem[0];\n const end = hem.index + value.length;\n // Skip if already matched by a pattern (covered-region check via binary search)\n if (coveredEnd(hem.index) >= end) continue;\n if (isHighEntropy(value)) {\n matchCounter++;\n matches.push({\n id: `scan_${matchCounter}`,\n category: \"secret\",\n type: \"high-entropy-string\",\n value,\n masked: value.slice(0, 6) + \"...\" + value.slice(-4),\n start: hem.index,\n end,\n severity: \"medium\",\n action: actionOverrides?.[\"high-entropy-string\"] ?? \"warn\",\n });\n }\n }\n }\n\n const severityRank: Record<ScanSeverity, number> = { critical: 4, high: 3, medium: 2, low: 1 };\n matches.sort((a, b) => a.start - b.start || severityRank[b.severity] - severityRank[a.severity]);\n\n const deduped: ScanMatch[] = [];\n let lastEnd = -1;\n for (const match of matches) {\n if (match.start >= lastEnd) {\n deduped.push(match);\n lastEnd = match.end;\n }\n }\n\n return {\n clean: deduped.filter((m) => m.action === \"block\" || m.action === \"redact\").length === 0,\n matches: deduped,\n scannedAt: Date.now(),\n durationMs: Math.round((performance.now() - start) * 100) / 100,\n };\n}\n\nexport function applyRedactions(text: string, matches: ScanMatch[]): string {\n return applyRedactionsTracked(text, matches).redactedCode;\n}\n\nexport interface RedactionResult {\n redactedCode: string;\n /** Maps each synthetic placeholder token (e.g. `_slx3k7`) to its original value. */\n secretsMap: Map<string, string>;\n}\n\n/** Prefix for secret-span placeholders — matches mutator-style `_v` / `_fn` tokens (not vendor-specific). */\nconst SECRET_LITERAL_PREFIX = \"_sl\";\n\n/**\n * Replace secret/PII values with deterministic synthetic tokens and return a\n * map for exact reversal. Placeholders use the same seeded hash scheme as\n * identifier mutation (`_sl` + 4 alphanumeric chars) so nothing leaks vendor or pattern names.\n */\nexport function applyRedactionsTracked(\n text: string,\n matches: ScanMatch[],\n mutationSeed: string = buildSaltedSeed(\"pretense\"),\n): RedactionResult {\n const actionable = matches.filter((m) => m.action === \"block\" || m.action === \"redact\");\n const sorted = [...actionable].sort((a, b) => b.start - a.start);\n\n const secretsMap = new Map<string, string>();\n\n const placeholders = new Map<string, string>();\n const forward = [...actionable].sort((a, b) => a.start - b.start);\n for (const match of forward) {\n const tag = deterministicSyntheticId(`${match.id}:${match.start}`, mutationSeed, SECRET_LITERAL_PREFIX);\n placeholders.set(match.id, tag);\n secretsMap.set(tag, match.value);\n }\n\n // Second pass (reverse order) to splice placeholders into the text\n let result = text;\n for (const match of sorted) {\n const tag = placeholders.get(match.id)!;\n result = result.slice(0, match.start) + tag + result.slice(match.end);\n }\n\n return { redactedCode: result, secretsMap };\n}\n\nexport function getPatternCount(): number {\n return SECRET_PATTERNS.length + PII_PATTERNS.length + ENV_PATTERNS.length;\n}\n","/**\n * Pretest Core — Mutation Store\n *\n * In-memory store with JSON file persistence for MutationMap entries.\n * SQLite replaces this in v0.2. For now: simple, zero-dependency, works.\n *\n * File: ~/.pretest/store.json (configurable)\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from \"fs\";\nimport { dirname } from \"path\";\nimport type { StoreEntry, MutationMap } from \"./types.js\";\n\nexport class MutationStore {\n private entries: Map<string, StoreEntry> = new Map();\n private readonly filePath: string;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n }\n\n /**\n * Persist a mutation map with associated metadata.\n *\n * @example\n * store.save({ id: \"req-1\", originalHash: \"abc\", mapEntries: [...], timestamp: Date.now(), language: \"typescript\" });\n */\n save(entry: StoreEntry): void {\n this.entries.set(entry.id, { ...entry });\n }\n\n /**\n * Retrieve a stored entry by request ID.\n *\n * @example\n * const entry = store.get(\"req-1\");\n */\n get(id: string): StoreEntry | null {\n return this.entries.get(id) ?? null;\n }\n\n /**\n * Find the most recent entry whose originalHash matches.\n *\n * @example\n * const entry = store.getByHash(\"sha256-abc123\");\n */\n getByHash(hash: string): StoreEntry | null {\n for (const entry of [...this.entries.values()].reverse()) {\n if (entry.originalHash === hash) return entry;\n }\n return null;\n }\n\n /**\n * Return all stored entries, newest first, up to `limit`.\n *\n * @example\n * store.list(10) // last 10 entries\n */\n list(limit = 50): StoreEntry[] {\n const all = [...this.entries.values()].reverse();\n return all.slice(0, limit);\n }\n\n /**\n * Delete an entry by ID. Returns true if it existed.\n */\n delete(id: string): boolean {\n return this.entries.delete(id);\n }\n\n /**\n * Remove all entries from memory.\n */\n clear(): void {\n this.entries.clear();\n }\n\n /**\n * Write current in-memory state to the JSON file.\n */\n persist(): void {\n const dir = dirname(this.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n const data = JSON.stringify([...this.entries.values()], null, 2);\n writeFileSync(this.filePath, data, \"utf-8\");\n }\n\n /**\n * Load entries from the JSON file into memory.\n * No-ops if the file doesn't exist.\n */\n load(): void {\n if (!existsSync(this.filePath)) return;\n try {\n const raw = readFileSync(this.filePath, \"utf-8\");\n const parsed = JSON.parse(raw) as StoreEntry[];\n this.entries.clear();\n for (const entry of parsed) {\n this.entries.set(entry.id, entry);\n }\n } catch {\n // Corrupted or empty file — start fresh\n this.entries.clear();\n }\n }\n\n /** Total entries in memory */\n get size(): number {\n return this.entries.size;\n }\n\n /**\n * Reconstruct a MutationMap from a stored entry.\n *\n * @example\n * const map = store.toMap(entry);\n * reverse(mutatedCode, map);\n */\n static toMap(entry: StoreEntry): MutationMap {\n return new Map(entry.mapEntries);\n }\n\n /**\n * Serialize a MutationMap to the format stored in StoreEntry.\n */\n static fromMap(map: MutationMap): [string, string][] {\n return [...map.entries()];\n }\n}\n","/**\n * Pretest CLI — Configuration Manager\n *\n * Reads/writes the .pretest/ directory for project-level config,\n * mutation maps, and audit logs.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { createHmac } from \"node:crypto\";\nimport type { PretenseConfig } from \"./types.js\";\nimport { DEFAULT_CONFIG } from \"./types.js\";\nimport { migrateLegacyProjectConfigDir, PROJECT_CONFIG_DIR_NAME } from \"./config-dir.js\";\n\nconst CONFIG_DIR_NAME = PROJECT_CONFIG_DIR_NAME;\nconst CONFIG_FILE = \"config.json\";\nconst MUTATION_MAP_FILE = \"mutation-map.json\";\nconst AUDIT_LOG_FILE = \"audit.log\";\nconst USAGE_FILE = \"usage.json\";\n\n/**\n * Get the .pretest/ config directory path for a given base directory.\n */\nexport function getConfigDir(baseDir?: string): string {\n const base = baseDir ?? process.cwd();\n migrateLegacyProjectConfigDir(base);\n return resolve(base, CONFIG_DIR_NAME);\n}\n\n/**\n * Initialize the .pretest/ directory with default config files.\n * Creates config.json, empty mutation-map.json, and empty audit.log.\n *\n * @returns The path to the created .pretest/ directory\n */\nexport function initConfig(dir?: string): string {\n const configDir = getConfigDir(dir);\n\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n // config.json\n const configPath = join(configDir, CONFIG_FILE);\n if (!existsSync(configPath)) {\n const config: PretenseConfig = {\n ...DEFAULT_CONFIG,\n storePath: configDir,\n };\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n }\n\n // mutation-map.json\n const mapPath = join(configDir, MUTATION_MAP_FILE);\n if (!existsSync(mapPath)) {\n writeFileSync(mapPath, \"[]\", \"utf-8\");\n }\n\n // audit.log\n const auditPath = join(configDir, AUDIT_LOG_FILE);\n if (!existsSync(auditPath)) {\n writeFileSync(auditPath, \"\", \"utf-8\");\n }\n\n // usage.json\n const usagePath = join(configDir, USAGE_FILE);\n if (!existsSync(usagePath)) {\n const today = new Date().toISOString().slice(0, 10);\n const month = today.slice(0, 7);\n const usageData: UsageData = { month, mutations: 0, firstUseDate: today };\n writeFileSync(\n usagePath,\n JSON.stringify({ ...usageData, date: today, checksum: computeUsageChecksum(usageData) }, null, 2),\n \"utf-8\",\n );\n }\n\n return configDir;\n}\n\n/**\n * Load config from .pretest/config.json.\n * Returns DEFAULT_CONFIG if the file doesn't exist or is corrupted.\n */\nexport function loadConfig(dir?: string): PretenseConfig {\n const configDir = getConfigDir(dir);\n const configPath = join(configDir, CONFIG_FILE);\n\n if (!existsSync(configPath)) {\n return { ...DEFAULT_CONFIG };\n }\n\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<PretenseConfig>;\n return { ...DEFAULT_CONFIG, ...parsed };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\n/**\n * Save config to .pretest/config.json.\n */\nexport function saveConfig(config: PretenseConfig, dir?: string): void {\n const configDir = getConfigDir(dir);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n const configPath = join(configDir, CONFIG_FILE);\n writeFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\n// ─── Usage integrity ─────────────────────────────────────────────────────────\n\n/** App-level secret used for usage.json HMAC when no external secret is set */\nconst USAGE_HMAC_SECRET = \"pretense_usage_integrity_v1\";\n\nfunction getUsageSecret(): string {\n return (\n process.env[\"PRETEST_USAGE_SECRET\"]?.trim() ||\n process.env[\"PRETENSE_USAGE_SECRET\"]?.trim() ||\n USAGE_HMAC_SECRET\n );\n}\n\nfunction computeUsageChecksum(data: { month: string; mutations: number; firstUseDate: string }): string {\n const payload = JSON.stringify({ month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate });\n return createHmac(\"sha256\", getUsageSecret()).update(payload).digest(\"hex\");\n}\n\nfunction verifyUsageChecksum(data: { month: string; mutations: number; firstUseDate: string; checksum?: string }): boolean {\n if (!data.checksum) return false;\n return data.checksum === computeUsageChecksum(data);\n}\n\n// ─── Usage tracking ──────────────────────────────────────────────────────────\n\nexport interface UsageData {\n month: string;\n mutations: number;\n firstUseDate: string;\n}\n\nexport function loadUsage(dir?: string): UsageData {\n const configDir = getConfigDir(dir);\n const usagePath = join(configDir, USAGE_FILE);\n\n const today = new Date().toISOString().slice(0, 10);\n const currentMonth = today.slice(0, 7); // YYYY-MM\n\n if (!existsSync(usagePath)) {\n return { month: currentMonth, mutations: 0, firstUseDate: today };\n }\n\n try {\n const raw = readFileSync(usagePath, \"utf-8\");\n const data = JSON.parse(raw) as UsageData & { checksum?: string; date?: string };\n\n // Migrate legacy daily format: if 'date' field exists but not 'month'\n if (data.date && !data.month) {\n const legacyDate = data.date as string;\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? legacyDate };\n }\n\n // Verify integrity checksum\n if (!verifyUsageChecksum({ month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate, checksum: data.checksum })) {\n process.stderr.write(\"[PRETEST] Warning: usage.json integrity check failed. Resetting usage counter.\\n\");\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? today };\n }\n\n // Reset counter if it's a new month\n if (data.month !== currentMonth) {\n return { month: currentMonth, mutations: 0, firstUseDate: data.firstUseDate ?? today };\n }\n return { month: data.month, mutations: data.mutations, firstUseDate: data.firstUseDate };\n } catch {\n return { month: currentMonth, mutations: 0, firstUseDate: today };\n }\n}\n\nexport function saveUsage(usage: UsageData, dir?: string): void {\n const configDir = getConfigDir(dir);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n const usagePath = join(configDir, USAGE_FILE);\n const checksum = computeUsageChecksum(usage);\n writeFileSync(usagePath, JSON.stringify({ ...usage, checksum }, null, 2), \"utf-8\");\n}\n\n// ─── License tier detection ───────────────────────────────────────────────────\n\nexport type LicenseTier = \"free\" | \"pro\" | \"enterprise\";\n\n/** Minimum key length: 8-char prefix + 32-char alphanumeric payload */\nconst MIN_LICENSE_KEY_LENGTH = 40;\nconst LICENSE_PAYLOAD_REGEX = /^[a-zA-Z0-9]+$/;\n\n/**\n * Validate license key format:\n * 1. Must be at least MIN_LICENSE_KEY_LENGTH chars\n * 2. Payload (after prefix) must be alphanumeric\n * 3. If PRETEST_LICENSE_SECRET or PRETENSE_LICENSE_SECRET is set, validate HMAC:\n * key format = `pre_pro_<payload>_<hmac>` where hmac = HMAC-SHA256(payload, secret) truncated to 16 hex chars\n */\nfunction isValidLicenseKey(key: string, prefix: string): boolean {\n if (key.length < MIN_LICENSE_KEY_LENGTH) return false;\n\n const afterPrefix = key.slice(prefix.length);\n\n const hmacSecret =\n process.env[\"PRETEST_LICENSE_SECRET\"]?.trim() ||\n process.env[\"PRETENSE_LICENSE_SECRET\"]?.trim();\n if (hmacSecret) {\n // HMAC mode: expect format `<payload>_<hmac16hex>`\n const lastUnderscore = afterPrefix.lastIndexOf(\"_\");\n if (lastUnderscore === -1) return false;\n const payload = afterPrefix.slice(0, lastUnderscore);\n const providedHmac = afterPrefix.slice(lastUnderscore + 1);\n if (!payload || !providedHmac) return false;\n if (!LICENSE_PAYLOAD_REGEX.test(payload)) return false;\n const expectedHmac = createHmac(\"sha256\", hmacSecret).update(payload).digest(\"hex\").slice(0, 16);\n return providedHmac === expectedHmac;\n }\n\n // Offline mode: length + alphanumeric validation only\n return LICENSE_PAYLOAD_REGEX.test(afterPrefix);\n}\n\nexport function detectTier(): LicenseTier {\n const key =\n process.env[\"PRETEST_LICENSE_KEY\"]?.trim() ||\n process.env[\"PRETENSE_LICENSE_KEY\"]?.trim() ||\n \"\";\n if (key.startsWith(\"pre_ent_\") && isValidLicenseKey(key, \"pre_ent_\")) return \"enterprise\";\n if (key.startsWith(\"pre_pro_\") && isValidLicenseKey(key, \"pre_pro_\")) return \"pro\";\n return \"free\";\n}\n\n/** Map dashboard `/auth/validate` plan to local tier for limits/UI. API keys (`prtns_live_*`) do not set license env vars, so paid users must use this when validation is cached. */\nexport function tierFromDashboardPlan(\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\" | undefined,\n fallback: LicenseTier,\n): LicenseTier {\n if (plan === \"ENTERPRISE\") return \"enterprise\";\n if (plan === \"PRO\") return \"pro\";\n return fallback;\n}\n\nexport function getTierLimits(tier: LicenseTier): { monthlyMutations: number; auditRetentionDays: number } {\n switch (tier) {\n case \"enterprise\":\n return { monthlyMutations: Infinity, auditRetentionDays: Infinity };\n case \"pro\":\n return { monthlyMutations: Infinity, auditRetentionDays: 90 };\n case \"free\":\n default:\n return { monthlyMutations: 1000, auditRetentionDays: 30 };\n }\n}\n","/**\n * Pretest CLI — Audit Logger\n *\n * Writes JSON lines to .pretest/audit.log for compliance and debugging.\n * Supports JSON and CSV output formats. Tier-gated retention.\n */\n\nimport { appendFileSync, existsSync, readFileSync, mkdirSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { getConfigDir, detectTier, getTierLimits } from \"./config.js\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface AuditEntry {\n timestamp: string;\n sessionId: string;\n file: string;\n identifiersMutated: number;\n secretsBlocked: number;\n llmProvider: string;\n latencyMs: number;\n}\n\nexport interface AuditReadOptions {\n limit?: number;\n format?: \"json\" | \"csv\" | \"text\";\n dir?: string;\n}\n\n// ─── Write ───────────────────────────────────────────────────────────────────\n\n/**\n * Append an audit entry as a JSON line to .pretest/audit.log.\n */\nexport function writeAuditEntry(entry: AuditEntry, dir?: string): void {\n const configDir = getConfigDir(dir);\n const auditPath = join(configDir, \"audit.log\");\n\n const logDir = dirname(auditPath);\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true });\n }\n\n const line = JSON.stringify(entry) + \"\\n\";\n appendFileSync(auditPath, line, \"utf-8\");\n}\n\n/**\n * Create a new audit entry with current timestamp.\n */\nexport function createAuditEntry(\n sessionId: string,\n file: string,\n identifiersMutated: number,\n secretsBlocked: number,\n llmProvider: string,\n latencyMs: number,\n): AuditEntry {\n return {\n timestamp: new Date().toISOString(),\n sessionId,\n file,\n identifiersMutated,\n secretsBlocked,\n llmProvider,\n latencyMs,\n };\n}\n\n// ─── Read ────────────────────────────────────────────────────────────────────\n\n/**\n * Read and parse the audit log. Applies tier-based retention filtering.\n */\nexport function readAuditLog(options: AuditReadOptions = {}): AuditEntry[] {\n const { limit, dir } = options;\n const configDir = getConfigDir(dir);\n const auditPath = join(configDir, \"audit.log\");\n\n if (!existsSync(auditPath)) {\n return [];\n }\n\n const raw = readFileSync(auditPath, \"utf-8\");\n const lines = raw.trim().split(\"\\n\").filter(Boolean);\n\n let entries: AuditEntry[] = [];\n for (const line of lines) {\n try {\n entries.push(JSON.parse(line) as AuditEntry);\n } catch {\n // Skip malformed lines\n }\n }\n\n // Apply tier-based retention filter\n const tier = detectTier();\n const { auditRetentionDays } = getTierLimits(tier);\n\n if (auditRetentionDays !== Infinity) {\n const cutoff = Date.now() - auditRetentionDays * 24 * 60 * 60 * 1000;\n entries = entries.filter((e) => new Date(e.timestamp).getTime() >= cutoff);\n }\n\n // Sort newest first\n entries.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n // Apply limit\n if (limit && limit > 0) {\n entries = entries.slice(0, limit);\n }\n\n return entries;\n}\n\n// ─── Formatters ──────────────────────────────────────────────────────────────\n\n/**\n * Format audit entries as JSON string.\n */\nexport function formatJson(entries: AuditEntry[]): string {\n return JSON.stringify(entries, null, 2);\n}\n\n/**\n * Format audit entries as CSV string.\n */\nexport function formatCsv(entries: AuditEntry[]): string {\n const headers = \"timestamp,sessionId,file,identifiersMutated,secretsBlocked,llmProvider,latencyMs\";\n const rows = entries.map((e) =>\n [\n e.timestamp,\n e.sessionId,\n `\"${e.file.replace(/\"/g, '\"\"')}\"`,\n e.identifiersMutated,\n e.secretsBlocked,\n e.llmProvider,\n e.latencyMs,\n ].join(\",\"),\n );\n return [headers, ...rows].join(\"\\n\");\n}\n\n/**\n * Format audit entries as human-readable text.\n */\nexport function formatText(entries: AuditEntry[]): string {\n if (entries.length === 0) return \"No audit entries found.\";\n\n const lines = entries.map((e) => {\n const date = new Date(e.timestamp).toLocaleString();\n return `[${date}] ${e.file} | ${e.identifiersMutated} mutated | ${e.secretsBlocked} secrets blocked | ${e.llmProvider} | ${e.latencyMs}ms`;\n });\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format entries using the specified format.\n */\nexport function formatAudit(entries: AuditEntry[], format: \"json\" | \"csv\" | \"text\" = \"text\"): string {\n switch (format) {\n case \"json\":\n return formatJson(entries);\n case \"csv\":\n return formatCsv(entries);\n case \"text\":\n default:\n return formatText(entries);\n }\n}\n","/**\r\n * Pretest CLI — Proxy Server\r\n *\r\n * Hono HTTP proxy that intercepts LLM API calls, scans + mutates\r\n * proprietary code, forwards to the real provider, then reverse-mutates\r\n * the response. Supports Anthropic, OpenAI, and Google Gemini.\r\n *\r\n * Includes free-tier enforcement, usage tracking, and upgrade nudges.\r\n * Drop-in replacement: set *_BASE_URL=http://localhost:9339 and done.\r\n */\r\n\r\nimport { Hono } from \"hono\";\r\nimport { serve } from \"@hono/node-server\";\r\nimport { nanoid } from \"nanoid\";\r\nimport { createServer } from \"node:net\";\r\nimport { existsSync, watch } from \"node:fs\";\r\nimport { mutate } from \"./mutator.js\";\r\nimport { reverse } from \"./reverser.js\";\r\nimport { detectLanguage } from \"./scanner.js\";\r\nimport { MutationStore } from \"./store.js\";\r\nimport { scan as scanSecrets, applyRedactions } from \"./secrets.js\";\r\nimport { writeAuditEntry, createAuditEntry } from \"./audit.js\";\r\nimport {\r\n loadUsage,\r\n saveUsage,\r\n detectTier,\r\n getTierLimits,\r\n getConfigDir,\r\n tierFromDashboardPlan,\r\n type LicenseTier,\r\n} from \"./config.js\";\r\nimport type { StoreEntry, PretenseConfig } from \"./types.js\";\r\nimport { DEFAULT_CONFIG } from \"./types.js\";\r\nimport { requireApiKey } from \"./auth.js\";\r\nimport { getSession, sessionCount } from \"./session-store.js\";\r\nimport { uploadLog } from \"./log-uploader.js\";\r\nimport {\r\n validateKey,\r\n getCachedValidation,\r\n isWithinLimits,\r\n getDashboardApiKey,\r\n bumpCachedUsageAfterLog,\r\n clearValidationCache,\r\n} from \"./backend-client.js\";\r\nimport {\r\n installDashboardKeyForCurrentProcess,\r\n promptDashboardApiKeyAfterFailure,\r\n isValidKeyShape,\r\n loadApiKey,\r\n getUserDashboardConfigDir,\r\n} from \"./commands/login.js\";\r\nimport { printStartClientInstructions } from \"./start-client-instructions.js\";\r\nimport { clearDashboardApiKeyFromProcess, hasDashboardApiKeyInEnv } from \"./dashboard-env.js\";\r\nimport { PUBLISH_PACKAGE_URL } from \"./publish-info.js\";\r\nimport { getCliSemver } from \"./version.js\";\r\n\r\n/**\r\n * When `pretest logout` clears ~/.pretest/config.json while this proxy runs,\r\n * we flip this flag (via fs.watch) so POST mutation stops without restarting.\r\n * Only active when the process did not start with a dashboard API key in the environment (env overrides file).\r\n */\r\nlet dashboardSavedCredentialsRevoked = false;\r\n\r\nfunction attachDashboardLogoutWatcher(enabled: boolean): void {\r\n if (!enabled) return;\r\n\r\n const dir = getUserDashboardConfigDir();\r\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n const applyFilesystemCredentialState = (): void => {\r\n const fk = loadApiKey();\r\n if (!fk) {\r\n if (dashboardSavedCredentialsRevoked) return;\r\n dashboardSavedCredentialsRevoked = true;\r\n clearDashboardApiKeyFromProcess();\r\n clearValidationCache();\r\n try {\r\n process.stderr.write(\r\n `\\x1b[33m[PRETEST] Saved dashboard API key removed (~/.pretest/config.json, e.g. pretest logout). ` +\r\n `LLM proxy POST requests are disabled until you run pretest login and restart pretest start.\\x1b[0m\\n`,\r\n );\r\n } catch {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n if (dashboardSavedCredentialsRevoked) {\r\n dashboardSavedCredentialsRevoked = false;\r\n clearValidationCache();\r\n }\r\n };\r\n\r\n const schedule = (): void => {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(applyFilesystemCredentialState, 120);\r\n };\r\n\r\n try {\r\n if (!existsSync(dir)) return;\r\n watch(dir, () => {\r\n schedule();\r\n });\r\n } catch {\r\n /* fs.watch unavailable */\r\n }\r\n}\r\n\r\n// ─── Provider detection ───────────────────────────────────────────────────────\r\n\r\nfunction anthropicUpstream(): string { return process.env[\"ANTHROPIC_UPSTREAM_URL\"] ?? \"https://api.anthropic.com\"; }\r\nfunction openaiUpstream(): string { return process.env[\"OPENAI_UPSTREAM_URL\"] ?? \"https://api.openai.com\"; }\r\nfunction geminiUpstream(): string { return process.env[\"GEMINI_UPSTREAM_URL\"] ?? \"https://generativelanguage.googleapis.com\"; }\r\nfunction ollamaUpstream(): string { return process.env[\"OLLAMA_UPSTREAM_URL\"] ?? \"http://localhost:11434\"; }\r\n\r\nfunction detectUpstream(path: string): string {\r\n // Anthropic — Claude Code / Anthropic SDK\r\n if (path.startsWith(\"/v1/messages\")) return anthropicUpstream();\r\n // OpenAI — Chat Completions, Completions, Responses (Codex CLI)\r\n if (\r\n path.startsWith(\"/v1/chat/completions\") ||\r\n path.startsWith(\"/v1/completions\") ||\r\n path.startsWith(\"/v1/responses\")\r\n ) {\r\n return openaiUpstream();\r\n }\r\n // Google Gemini\r\n if (path.startsWith(\"/v1beta/\") || path.startsWith(\"/v1/models\")) return geminiUpstream();\r\n // Ollama (local LLM) — chat + generate endpoints\r\n if (path.startsWith(\"/api/chat\") || path.startsWith(\"/api/generate\")) return ollamaUpstream();\r\n // Default to Anthropic (Claude Code is the most common consumer)\r\n return anthropicUpstream();\r\n}\r\n\r\nfunction detectProvider(path: string): string {\r\n if (path.startsWith(\"/v1/messages\")) return \"anthropic\";\r\n if (\r\n path.startsWith(\"/v1/chat/completions\") ||\r\n path.startsWith(\"/v1/completions\") ||\r\n path.startsWith(\"/v1/responses\")\r\n ) {\r\n return \"openai\";\r\n }\r\n if (path.startsWith(\"/v1beta/\") || path.startsWith(\"/v1/models\")) return \"google\";\r\n if (path.startsWith(\"/api/chat\") || path.startsWith(\"/api/generate\")) return \"ollama\";\r\n return \"anthropic\";\r\n}\r\n\r\n/** Strip internal proxy headers before forwarding; they must never reach the LLM vendor. */\r\nfunction stripPretenseOnlyForwardingHeaders(headers: Record<string, string>): void {\r\n const drop = new Set([\"x-pretense-api-key\", \"x-pretense-key\"]);\r\n for (const k of [...Object.keys(headers)]) {\r\n if (drop.has(k.toLowerCase())) delete headers[k];\r\n }\r\n}\r\n\r\n// ─── Message text extraction ──────────────────────────────────────────────────\r\n\r\nfunction extractText(body: Record<string, unknown>): string {\r\n const parts: string[] = [];\r\n if (typeof body[\"system\"] === \"string\") parts.push(body[\"system\"]);\r\n if (Array.isArray(body[\"messages\"])) {\r\n for (const msg of body[\"messages\"] as Record<string, unknown>[]) {\r\n if (typeof msg[\"content\"] === \"string\") parts.push(msg[\"content\"]);\r\n else if (Array.isArray(msg[\"content\"])) {\r\n for (const block of msg[\"content\"] as Record<string, unknown>[]) {\r\n if (block[\"type\"] === \"text\" && typeof block[\"text\"] === \"string\") parts.push(block[\"text\"]);\r\n }\r\n }\r\n }\r\n }\r\n return parts.join(\"\\n\");\r\n}\r\n\r\n// ─── Code block extraction (inline — no external dep) ────────────────────────\r\n\r\ninterface CodeBlock {\r\n code: string;\r\n language: string;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nfunction extractCodeBlocks(text: string): CodeBlock[] {\r\n const blocks: CodeBlock[] = [];\r\n const re = /```(\\w*)\\n([\\s\\S]*?)```/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(text)) !== null) {\r\n blocks.push({\r\n code: m[2] ?? \"\",\r\n language: m[1] ?? \"typescript\",\r\n start: m.index,\r\n end: m.index + m[0].length,\r\n });\r\n }\r\n return blocks;\r\n}\r\n\r\nfunction replaceCodeBlocks(text: string, blocks: CodeBlock[], replacements: string[]): string {\r\n let result = text;\r\n // Replace in reverse order to preserve indices\r\n for (let i = blocks.length - 1; i >= 0; i--) {\r\n const block = blocks[i]!;\r\n const replacement = replacements[i] ?? block.code;\r\n const lang = block.language ?? \"typescript\";\r\n result = result.slice(0, block.start) + \"```\" + lang + \"\\n\" + replacement + \"```\" + result.slice(block.end);\r\n }\r\n return result;\r\n}\r\n\r\n// ─── Apply text mutations to message body ────────────────────────────────────\r\n\r\nfunction applyToBody(\r\n body: Record<string, unknown>,\r\n transform: (text: string) => string,\r\n): Record<string, unknown> {\r\n const mutateField = (val: unknown): unknown => {\r\n if (typeof val === \"string\") return transform(val);\r\n if (Array.isArray(val)) return val.map(mutateField);\r\n if (val && typeof val === \"object\") {\r\n const obj = val as Record<string, unknown>;\r\n return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, mutateField(v)]));\r\n }\r\n return val;\r\n };\r\n\r\n return mutateField(body) as Record<string, unknown>;\r\n}\r\n\r\n// ─── Stats tracking ───────────────────────────────────────────────────────────\r\n\r\ninterface ProxyStats {\r\n requestsProcessed: number;\r\n totalTokensMutated: number;\r\n totalSecretsBlocked: number;\r\n startedAt: number;\r\n}\r\n\r\nconst stats: ProxyStats = {\r\n requestsProcessed: 0,\r\n totalTokensMutated: 0,\r\n totalSecretsBlocked: 0,\r\n startedAt: Date.now(),\r\n};\r\n\r\n// ─── Upgrade nudge helpers ───────────────────────────────────────────────────\r\n\r\nfunction daysSinceFirstUse(): number {\r\n const usage = loadUsage();\r\n if (!usage.firstUseDate) return 0;\r\n const first = new Date(usage.firstUseDate).getTime();\r\n return Math.floor((Date.now() - first) / (24 * 60 * 60 * 1000));\r\n}\r\n\r\nfunction printUpgradeNudge(reason: string): void {\r\n process.stdout.write(\r\n `\\n\\x1b[33m[PRETEST] ${reason}\\x1b[0m\\n` +\r\n `\\x1b[33m[PRETEST] Upgrade to Pro: ${PUBLISH_PACKAGE_URL}\\x1b[0m\\n\\n`,\r\n );\r\n}\r\n\r\n// ─── Proxy factory ────────────────────────────────────────────────────────────\r\n\r\nexport interface ProxyOptions {\r\n config?: Partial<PretenseConfig>;\r\n store?: MutationStore;\r\n verbose?: boolean;\r\n}\r\n\r\ntype ProxyEnv = { Variables: { sessionHash: string } };\r\n\r\nexport function createProxy(opts: ProxyOptions = {}): Hono<ProxyEnv> {\r\n const config: PretenseConfig = { ...DEFAULT_CONFIG, ...opts.config };\r\n const store = opts.store ?? new MutationStore(`${config.storePath}/proxy-store.json`);\r\n const verbose = opts.verbose ?? false;\r\n\r\n const app = new Hono<ProxyEnv>();\r\n\r\n // ── Auth middleware ────────────────────────────────────────────────────────\r\n // Short-circuits public paths (/, /health, /stats, /audit, /tokens) and\r\n // rejects everything else lacking an API key with HTTP 401.\r\n app.use(\"*\", requireApiKey);\r\n\r\n // ── Root welcome ───────────────────────────────────────────────────────────\r\n app.get(\"/\", (c) =>\r\n c.json({\r\n name: \"pretest\",\r\n version: getCliSemver(),\r\n status: \"running\",\r\n routes: {\r\n \"GET /\": \"This welcome page\",\r\n \"GET /health\": \"Health check with uptime\",\r\n \"GET /stats\": \"Mutation statistics\",\r\n \"GET /audit\": \"Audit log (?limit=50)\",\r\n \"POST /*\": \"Proxy to upstream LLM API (Anthropic, OpenAI, Google auto-detected)\",\r\n },\r\n languages: [\"TypeScript\", \"JavaScript\", \"Python\", \"Go\", \"Java\", \"C#\", \"Ruby\", \"Rust\"],\r\n docs: PUBLISH_PACKAGE_URL,\r\n }),\r\n );\r\n\r\n // ── Health ─────────────────────────────────────────────────────────────────\r\n app.get(\"/health\", (c) =>\r\n c.json({\r\n status: \"ok\",\r\n version: getCliSemver(),\r\n uptime: Math.floor((Date.now() - stats.startedAt) / 1000),\r\n stats: {\r\n requestsProcessed: stats.requestsProcessed,\r\n totalTokensMutated: stats.totalTokensMutated,\r\n },\r\n }),\r\n );\r\n\r\n // ── Stats ──────────────────────────────────────────────────────────────────\r\n app.get(\"/stats\", (c) =>\r\n c.json({\r\n ...stats,\r\n storeSize: store.size,\r\n activeSessions: sessionCount(),\r\n }),\r\n );\r\n\r\n // ── Audit ──────────────────────────────────────────────────────────────────\r\n app.get(\"/audit\", (c) => {\r\n const limit = parseInt(c.req.query(\"limit\") ?? \"50\");\r\n return c.json(store.list(limit));\r\n });\r\n\r\n // ── Main proxy handler ─────────────────────────────────────────────────────\r\n app.all(\"/*\", async (c) => {\r\n if (c.req.method !== \"POST\") {\r\n // Pass-through non-POST (GET model lists, etc.)\r\n const upstream = c.req.header(\"x-pretense-upstream\") ?? detectUpstream(c.req.path);\r\n const url = upstream + c.req.path;\r\n const headers: Record<string, string> = {};\r\n c.req.raw.headers.forEach((v, k) => { headers[k] = v; });\r\n delete headers[\"host\"];\r\n headers[\"host\"] = new URL(upstream).host;\r\n stripPretenseOnlyForwardingHeaders(headers);\r\n const resp = await fetch(url, { method: c.req.method, headers });\r\n return new Response(resp.body, { status: resp.status, headers: Object.fromEntries(resp.headers.entries()) });\r\n }\r\n\r\n const requestStart = performance.now();\r\n\r\n // ── Parse body ────────────────────────────────────────────────────────\r\n let body: Record<string, unknown>;\r\n try {\r\n body = await c.req.json<Record<string, unknown>>();\r\n } catch {\r\n return c.json({ error: { type: \"invalid_request\", message: \"Invalid JSON body\" } }, 400);\r\n }\r\n\r\n if (!body || Object.keys(body).length === 0) {\r\n return c.json({ error: { type: \"invalid_request\", message: \"Empty request body\" } }, 400);\r\n }\r\n\r\n const requestId = nanoid(12);\r\n const upstream = c.req.header(\"x-pretense-upstream\") ?? detectUpstream(c.req.path);\r\n const provider = detectProvider(c.req.path);\r\n\r\n if (dashboardSavedCredentialsRevoked) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_session_logged_out\",\r\n message:\r\n \"Saved dashboard credentials were removed (for example pretest logout). Run pretest login, then restart pretest start. If you started the proxy with a dashboard API key in this shell, stop it (Ctrl+C) and start again after logout.\",\r\n },\r\n },\r\n 401,\r\n );\r\n }\r\n\r\n const dashboardApiKey = getDashboardApiKey();\r\n if (!dashboardApiKey) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_dashboard_key_required\",\r\n message:\r\n \"Configure your dashboard API key: run `pretest login --key prtns_live_...` or set PRETEST_API_KEY.\",\r\n },\r\n },\r\n 401,\r\n );\r\n }\r\n\r\n try {\r\n await validateKey({ verbose, force: false, enforceReachability: true });\r\n } catch (err) {\r\n const code = (err as Error & { code?: string }).code ?? \"\";\r\n const msg = (err as Error).message;\r\n const knownAuthCodes = new Set([\r\n \"KEY_REVOKED\",\r\n \"KEY_EXPIRED\",\r\n \"INVALID_API_KEY\",\r\n \"MISSING_API_KEY\",\r\n ]);\r\n if (knownAuthCodes.has(code)) {\r\n return c.json(\r\n { error: { type: \"pretense_auth_error\", code, message: msg } },\r\n 401,\r\n );\r\n }\r\n if (code === \"BACKEND_UNAVAILABLE\" || code === \"AUTH_BACKEND_REJECTED\") {\r\n return c.json(\r\n { error: { type: \"pretense_auth_backend_error\", code, message: msg } },\r\n 503,\r\n );\r\n }\r\n if (code === \"ORG_INACTIVE\") {\r\n return c.json(\r\n { error: { type: \"pretense_org_inactive\", code, message: msg } },\r\n 403,\r\n );\r\n }\r\n return c.json(\r\n { error: { type: \"pretense_auth_error\", message: msg } },\r\n 401,\r\n );\r\n }\r\n\r\n // ── Session isolation ─────────────────────────────────────────────────\r\n // Two different API keys MUST NOT share mutation map state. The\r\n // requireApiKey middleware already validated the key and stashed\r\n // sha256(key) under \"sessionHash\"; if we get here it's set.\r\n const sessHash = c.get(\"sessionHash\");\r\n const session = getSession(sessHash);\r\n\r\n // ── Free tier enforcement ─────────────────────────────────────────────\r\n // `detectTier()` reads offline license keys (pre_pro_* / pre_ent_*). Dashboard\r\n // keys (prtns_live_*) get PRO/ENTERPRISE from validate — use cached plan.\r\n const tier: LicenseTier = tierFromDashboardPlan(\r\n getCachedValidation()?.plan,\r\n detectTier(),\r\n );\r\n const { monthlyMutations } = getTierLimits(tier);\r\n const usage = loadUsage();\r\n\r\n if (!dashboardApiKey && tier === \"free\" && usage.mutations >= monthlyMutations) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_rate_limit\",\r\n message: `Monthly mutation limit reached (${monthlyMutations}/month). Upgrade to Pro for unlimited: ${PUBLISH_PACKAGE_URL}`,\r\n },\r\n },\r\n 429,\r\n );\r\n }\r\n\r\n // ── Backend limit enforcement (authoritative when reachable) ──────\r\n const backendLimits = await isWithinLimits();\r\n if (!backendLimits.allowed) {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_rate_limit\",\r\n message: backendLimits.reason ?? \"Mutation limit exceeded.\",\r\n },\r\n },\r\n 429,\r\n );\r\n }\r\n\r\n // ── Dashboard key permission: read-only cannot run the mutating proxy ──\r\n const cliAuth = getCachedValidation();\r\n if (cliAuth?.permission === \"read_only\") {\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_forbidden\",\r\n message:\r\n \"This API key is read-only. Create a read_write key in the dashboard to use the Pretest proxy.\",\r\n },\r\n },\r\n 403,\r\n );\r\n }\r\n\r\n // ── Secret scan ───────────────────────────────────────────────────────\r\n const fullText = extractText(body);\r\n const secretScan = scanSecrets(fullText);\r\n const blockedSecrets = secretScan.matches.filter((m) => m.action === \"block\");\r\n\r\n if (blockedSecrets.length > 0) {\r\n stats.totalSecretsBlocked += blockedSecrets.length;\r\n\r\n // Pro alert suggestion for secrets\r\n if (tier === \"free\") {\r\n printUpgradeNudge(`${blockedSecrets.length} secret(s) blocked. Pro tier includes real-time secret alerts via Slack/PagerDuty.`);\r\n }\r\n\r\n return c.json(\r\n {\r\n error: {\r\n type: \"pretense_blocked\",\r\n message: `Request blocked: ${blockedSecrets.length} secret(s) detected. Types: ${[...new Set(blockedSecrets.map((m) => m.type))].join(\", \")}`,\r\n },\r\n },\r\n 400,\r\n );\r\n }\r\n\r\n // Apply redactions (PII, warnings)\r\n const processedBody = applyToBody(body, (text) => applyRedactions(text, secretScan.matches));\r\n\r\n // ── Code mutation ─────────────────────────────────────────────────────\r\n // The mutation map is scoped to the session (per-API-key) so two\r\n // different callers never see each other's tokens. We still track a\r\n // per-request local map for logging + the audit StoreEntry below.\r\n const mutationMap = new Map<string, string>();\r\n let tokensMutated = 0;\r\n\r\n const mutatedBody = applyToBody(processedBody, (text) => {\r\n const blocks = extractCodeBlocks(text);\r\n // No markdown fences — still mutate (raw paste is the common case).\r\n if (blocks.length === 0) {\r\n const lang = detectLanguage(text);\r\n const result = mutate(text, lang);\r\n for (const [k, v] of result.map) {\r\n mutationMap.set(k, v);\r\n session.mutationMap.set(k, v);\r\n session.reverseMap.set(v, k);\r\n }\r\n tokensMutated += result.stats.tokensMutated;\r\n return result.mutatedCode;\r\n }\r\n\r\n const mutatedBlocks: string[] = [];\r\n for (const block of blocks) {\r\n const result = mutate(block.code, block.language);\r\n for (const [k, v] of result.map) {\r\n mutationMap.set(k, v);\r\n session.mutationMap.set(k, v);\r\n session.reverseMap.set(v, k);\r\n }\r\n tokensMutated += result.stats.tokensMutated;\r\n mutatedBlocks.push(result.mutatedCode);\r\n }\r\n\r\n return replaceCodeBlocks(text, blocks, mutatedBlocks);\r\n });\r\n\r\n // Update usage tracking\r\n usage.mutations += tokensMutated;\r\n saveUsage(usage);\r\n\r\n // ── Server-side attribution (fire-and-forget) ─────────────────────────\r\n // Upload this event to /api/cli/log with git context. Runs in the\r\n // background so we never add latency to the LLM proxy path. Opt out\r\n // with PRETENSE_DISABLE_REMOTE_LOG=1.\r\n const remoteLogDisabled = process.env[\"PRETENSE_DISABLE_REMOTE_LOG\"] === \"1\";\r\n if (dashboardApiKey && !remoteLogDisabled) {\r\n void uploadLog(\r\n {\r\n file_count: 0,\r\n identifiers_mutated: tokensMutated,\r\n secrets_blocked: blockedSecrets.length,\r\n llm_provider: provider,\r\n cli_version: getCliSemver(),\r\n },\r\n { apiKey: dashboardApiKey, verbose },\r\n );\r\n bumpCachedUsageAfterLog(tokensMutated);\r\n }\r\n\r\n // Warning at 80% of monthly limit (free tier)\r\n const warningThreshold = Math.floor(monthlyMutations * 0.8);\r\n if (tier === \"free\" && usage.mutations >= warningThreshold && usage.mutations - tokensMutated < warningThreshold) {\r\n printUpgradeNudge(`${usage.mutations}/${monthlyMutations} monthly mutations used. Running low!`);\r\n }\r\n\r\n // 7-day upgrade nudge\r\n if (tier === \"free\" && daysSinceFirstUse() >= 7) {\r\n printUpgradeNudge(\"You've been using Pretest for 7+ days. Unlock Pro features: unlimited mutations, 90-day audit, Slack alerts.\");\r\n }\r\n\r\n // Store mutation map for response reversal\r\n const entry: StoreEntry = {\r\n id: requestId,\r\n originalHash: requestId,\r\n mapEntries: [...mutationMap.entries()],\r\n timestamp: Date.now(),\r\n language: \"mixed\",\r\n };\r\n store.save(entry);\r\n stats.requestsProcessed++;\r\n stats.totalTokensMutated += tokensMutated;\r\n\r\n // Write audit entry\r\n const latencyMs = Math.round((performance.now() - requestStart) * 100) / 100;\r\n writeAuditEntry(\r\n createAuditEntry(requestId, \"proxy-request\", tokensMutated, blockedSecrets.length, provider, latencyMs),\r\n );\r\n\r\n if (verbose && tokensMutated > 0) {\r\n process.stdout.write(`[PRETEST] ${tokensMutated} tokens mutated for request ${requestId}\\n`);\r\n }\r\n\r\n // ── Forward to upstream ───────────────────────────────────────────────\r\n const headers: Record<string, string> = {};\r\n c.req.raw.headers.forEach((v, k) => { headers[k] = v; });\r\n delete headers[\"host\"];\r\n delete headers[\"content-length\"];\r\n headers[\"host\"] = new URL(upstream).host;\r\n headers[\"x-pretense-request-id\"] = requestId;\r\n stripPretenseOnlyForwardingHeaders(headers);\r\n\r\n const forwardBody = JSON.stringify(mutatedBody);\r\n\r\n let upstreamResp: Response;\r\n try {\r\n upstreamResp = await fetch(upstream + c.req.path, {\r\n method: \"POST\",\r\n headers: { ...headers, \"content-type\": \"application/json\", \"content-length\": String(Buffer.byteLength(forwardBody)) },\r\n body: forwardBody,\r\n });\r\n } catch {\r\n return c.json({ error: { type: \"pretense_upstream_error\", message: \"Failed to reach upstream provider\" } }, 502);\r\n }\r\n\r\n // ── Streaming with reverse-mutation ────────────────────────────────────\r\n if (body[\"stream\"] === true) {\r\n const streamReverseMap = new Map(mutationMap);\r\n const upstream = upstreamResp.body;\r\n if (!upstream || tokensMutated === 0) {\r\n // No mutations to reverse -- pass through as-is.\r\n return new Response(upstream, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"content-type\": upstreamResp.headers.get(\"content-type\") ?? \"text/event-stream\",\r\n \"cache-control\": \"no-cache\",\r\n \"x-pretense-request-id\": requestId,\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n },\r\n });\r\n }\r\n\r\n // Build a TransformStream that reverse-mutates each SSE data line.\r\n const decoder = new TextDecoder();\r\n const encoder = new TextEncoder();\r\n let buffer = \"\";\r\n\r\n const transform = new TransformStream<Uint8Array, Uint8Array>({\r\n transform(chunk, controller) {\r\n buffer += decoder.decode(chunk, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n // Keep the last partial line in the buffer\r\n buffer = lines.pop() ?? \"\";\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(\"data: \") && line !== \"data: [DONE]\") {\r\n try {\r\n const json = JSON.parse(line.slice(6)) as Record<string, unknown>;\r\n // Reverse-mutate text content in the SSE payload\r\n const reversed = applyToBody(json, (text) => reverse(text, streamReverseMap));\r\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(reversed)}\\n`));\r\n } catch {\r\n // If JSON parsing fails, pass line through unchanged.\r\n controller.enqueue(encoder.encode(line + \"\\n\"));\r\n }\r\n } else {\r\n controller.enqueue(encoder.encode(line + \"\\n\"));\r\n }\r\n }\r\n },\r\n flush(controller) {\r\n if (buffer.length > 0) {\r\n controller.enqueue(encoder.encode(buffer));\r\n }\r\n },\r\n });\r\n\r\n const reversedStream = upstream.pipeThrough(transform);\r\n return new Response(reversedStream, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"content-type\": upstreamResp.headers.get(\"content-type\") ?? \"text/event-stream\",\r\n \"cache-control\": \"no-cache\",\r\n \"x-pretense-request-id\": requestId,\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n \"x-pretense-stream-reversal\": \"active\",\r\n },\r\n });\r\n }\r\n\r\n // ── Reverse-mutate response ──────────────────────────────────────────\r\n const reverseMap = new Map(mutationMap);\r\n let respBody: Record<string, unknown>;\r\n try {\r\n respBody = (await upstreamResp.json()) as Record<string, unknown>;\r\n } catch {\r\n return new Response(null, {\r\n status: upstreamResp.status,\r\n headers: {\r\n \"x-pretense-protected\": \"true\",\r\n \"x-pretense-mutations\": String(tokensMutated),\r\n },\r\n });\r\n }\r\n\r\n const reversedBody = applyToBody(respBody, (text) => {\r\n const blocks = extractCodeBlocks(text);\r\n if (blocks.length === 0) return reverse(text, reverseMap);\r\n const reversedBlocks = blocks.map((b) => reverse(b.code, reverseMap));\r\n return replaceCodeBlocks(text, blocks, reversedBlocks);\r\n });\r\n\r\n c.header(\"x-pretense-request-id\", requestId);\r\n c.header(\"x-pretense-protected\", \"true\");\r\n c.header(\"x-pretense-mutations\", String(tokensMutated));\r\n return c.json(reversedBody, upstreamResp.status as 200);\r\n });\r\n\r\n return app;\r\n}\r\n\r\n// ─── Port helpers ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether a port is currently free on 127.0.0.1.\r\n */\r\nfunction isPortAvailable(port: number): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const tester = createServer()\r\n .once(\"error\", () => resolve(false))\r\n .once(\"listening\", () => {\r\n tester.once(\"close\", () => resolve(true)).close();\r\n })\r\n .listen(port, \"127.0.0.1\");\r\n });\r\n}\r\n\r\n/**\r\n * Try the requested port; if it is busy, walk forward up to `maxAttempts`\r\n * times until a free port is found. Returns the chosen port number.\r\n */\r\nexport async function findAvailablePort(startPort: number, maxAttempts = 10): Promise<number> {\r\n for (let i = 0; i < maxAttempts; i++) {\r\n const candidate = startPort + i;\r\n if (candidate < 1 || candidate > 65535) break;\r\n // eslint-disable-next-line no-await-in-loop\r\n if (await isPortAvailable(candidate)) return candidate;\r\n }\r\n throw new Error(\r\n `No available port found in range ${startPort}-${startPort + maxAttempts - 1}. ` +\r\n `Free a port or pass --port <number>.`,\r\n );\r\n}\r\n\r\n// ─── Start server ─────────────────────────────────────────────────────────────\r\n\r\nexport function startProxy(opts: ProxyOptions & { port?: number } = {}): void {\r\n const requestedPort = opts.port ?? opts.config?.port ?? DEFAULT_CONFIG.port;\r\n const app = createProxy(opts);\r\n\r\n void (async () => {\r\n const dashboardKeyFromEnvAtLaunch = hasDashboardApiKeyInEnv();\r\n\r\n const dashboardKey = getDashboardApiKey();\r\n\r\n if (!dashboardKey || !isValidKeyShape(dashboardKey)) {\r\n process.stderr.write(\r\n `\\x1b[31m[PRETEST] API key required or invalid shape. Run \\`pretest login --key prtns_live_...\\`\\x1b[0m\\n` +\r\n `\\x1b[31m[PRETEST] or set PRETEST_API_KEY. See ${PUBLISH_PACKAGE_URL}\\x1b[0m\\n`,\r\n );\r\n process.exit(1);\r\n }\r\n\r\n const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\r\n\r\n // ── Backend key validation on startup ────────────────────────────────\r\n for (;;) {\r\n try {\r\n const validation = await validateKey({\r\n force: true,\r\n verbose: opts.verbose,\r\n enforceReachability: true,\r\n });\r\n if (!validation) {\r\n process.stderr.write(\r\n `\\x1b[31m[PRETEST] Startup validation failed (no API key or unreachable backend). Cannot start proxy.\\x1b[0m\\n`,\r\n );\r\n process.exit(1);\r\n }\r\n const plan = validation.plan ?? \"FREE\";\r\n const remaining =\r\n validation.mutationsRemaining === -1 ? \"unlimited\" : String(validation.mutationsRemaining);\r\n process.stdout.write(\r\n `\\x1b[32m[PRETEST] Key validated: ${plan} plan` +\r\n (validation.organizationName ? ` (${validation.organizationName})` : \"\") +\r\n ` — ${remaining} mutations remaining\\x1b[0m\\n`,\r\n );\r\n break;\r\n } catch (err) {\r\n const code = (err as Error & { code?: string }).code;\r\n const msg = (err as Error).message;\r\n\r\n if (code === \"BACKEND_UNAVAILABLE\" || code === \"AUTH_BACKEND_REJECTED\") {\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETEST] Fix network or set PRETEST_API_URL (or PRETENSE_API_URL) if using a custom API.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n if (code === \"ORG_INACTIVE\") {\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETEST] Your organization is inactive; contact support.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n const authRetryable =\r\n code === \"INVALID_API_KEY\" ||\r\n code === \"KEY_REVOKED\" ||\r\n code === \"KEY_EXPIRED\" ||\r\n code === \"AUTH_ERROR\" ||\r\n code === \"MISSING_API_KEY\";\r\n\r\n if (authRetryable && interactive) {\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(\r\n `\\x1b[33m[PRETEST] Enter your dashboard API key and press Enter (Ctrl+C to quit).\\x1b[0m\\n`,\r\n );\r\n let entered: string | null = null;\r\n for (;;) {\r\n entered = await promptDashboardApiKeyAfterFailure();\r\n if (!entered) {\r\n process.stderr.write(`\\x1b[31m[PRETEST] No key entered; exiting.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n if (isValidKeyShape(entered)) break;\r\n process.stderr.write(\r\n `\\x1b[31m[PRETEST] That does not look like a dashboard key (expect prtns_live_… or pk_live_…).\\x1b[0m\\n`,\r\n );\r\n }\r\n const savedPath = installDashboardKeyForCurrentProcess(entered);\r\n process.stdout.write(`\\x1b[32m[PRETEST] Saved API key to ${savedPath}\\x1b[0m\\n`);\r\n clearValidationCache();\r\n continue;\r\n }\r\n\r\n if (\r\n code === \"KEY_REVOKED\" ||\r\n code === \"KEY_EXPIRED\" ||\r\n code === \"INVALID_API_KEY\" ||\r\n code === \"AUTH_ERROR\" ||\r\n code === \"MISSING_API_KEY\"\r\n ) {\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETEST] Run 'pretest login --key <new-key>' to fix.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${msg}\\x1b[0m\\n`);\r\n process.stderr.write(`\\x1b[31m[PRETEST] Run 'pretest login --key <new-key>' or check connectivity.\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n attachDashboardLogoutWatcher(!dashboardKeyFromEnvAtLaunch);\r\n\r\n const bannerTier: LicenseTier = tierFromDashboardPlan(\r\n getCachedValidation()?.plan,\r\n detectTier(),\r\n );\r\n\r\n let port: number;\r\n try {\r\n port = await findAvailablePort(requestedPort, 10);\r\n } catch (err) {\r\n process.stderr.write(`\\x1b[31m[PRETEST] ${(err as Error).message}\\x1b[0m\\n`);\r\n process.exit(1);\r\n }\r\n\r\n if (port !== requestedPort) {\r\n process.stderr.write(\r\n `\\x1b[33m[PRETEST] Port ${requestedPort} in use, falling back to ${port}.\\x1b[0m\\n`,\r\n );\r\n }\r\n\r\n printStartClientInstructions(port);\r\n\r\n serve({ fetch: app.fetch, port }, () => {\r\n const portStr = String(port);\r\n process.stdout.write(`\r\n\\x1b[36mPretest v${getCliSemver()} [${bannerTier.toUpperCase()}]\\x1b[0m\r\n Your code hits AI naked. We fix that.\r\n\r\n Proxy: http://localhost:${portStr}\r\n Health: http://localhost:${portStr}/health\r\n Stats: http://localhost:${portStr}/stats\r\n\r\n Drop-in env vars:\r\n ANTHROPIC_BASE_URL=http://localhost:${portStr}\r\n OPENAI_BASE_URL=http://localhost:${portStr}/v1\r\n GEMINI_BASE_URL=http://localhost:${portStr}/v1beta\r\n OLLAMA_HOST=http://localhost:${portStr}\r\n\r\n Routes intercepted:\r\n /v1/messages -> Anthropic (Claude Code, SDK)\r\n /v1/chat/completions -> OpenAI (ChatGPT, Cursor)\r\n /v1/responses -> OpenAI (Codex CLI)\r\n /v1beta/... -> Google Gemini\r\n /api/chat, /api/generate -> Ollama (local)\r\n`);\r\n // Periodic revalidation every 60s to catch revocation/limit changes.\r\n setInterval(() => {\r\n if (dashboardSavedCredentialsRevoked) return;\r\n if (!getDashboardApiKey()) return;\r\n void validateKey({\r\n force: true,\r\n verbose: opts.verbose,\r\n enforceReachability: true,\r\n }).catch(() => {});\r\n }, 60_000);\r\n });\r\n })();\r\n}\r\n","/**\n * Pretest CLI — Proxy Authentication\n *\n * Extracts API keys from incoming requests and enforces presence on all\n * non-public routes. The hash of each API key is used as an isolation\n * key for per-session mutation maps (see session-store.ts), so two\n * different API keys can never read or write each other's token map.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Context, MiddlewareHandler } from \"hono\";\n\nconst AUTH_HEADERS = [\"authorization\", \"x-api-key\", \"x-goog-api-key\"] as const;\n\n/**\n * Public routes that do NOT require an API key. Used for health checks,\n * welcome page, stats/audit dashboards, and any local introspection routes.\n */\nconst PUBLIC_PATHS = new Set<string>([\n \"/\",\n \"/health\",\n \"/stats\",\n \"/audit\",\n \"/tokens\",\n]);\n\n/**\n * Pull the API key out of the first matching auth header.\n * Strips optional \"Bearer \" prefix for Authorization headers.\n */\nexport function extractApiKey(c: Context): string | null {\n for (const h of AUTH_HEADERS) {\n const v = c.req.header(h);\n if (v && v.length > 0) {\n return v.replace(/^Bearer\\s+/i, \"\").trim();\n }\n }\n return null;\n}\n\n/**\n * Deterministic short hash of an API key, safe to use as a map key.\n * Uses sha256 truncated to 16 hex chars (64 bits) — plenty for isolation\n * without leaking the full key.\n */\nexport function sessionHash(apiKey: string): string {\n return createHash(\"sha256\").update(apiKey).digest(\"hex\").slice(0, 16);\n}\n\n/**\n * Hono middleware that:\n * 1. Lets public routes through untouched.\n * 2. Rejects protected routes missing an API key with HTTP 401 + JSON.\n * 3. Stores the session hash in the request context for downstream handlers.\n */\nexport const requireApiKey: MiddlewareHandler = async (c, next) => {\n if (PUBLIC_PATHS.has(c.req.path)) {\n return next();\n }\n const key = extractApiKey(c);\n if (!key) {\n return c.json(\n {\n error: {\n type: \"missing_api_key\",\n message:\n \"Authorization header required (Authorization, x-api-key, or x-goog-api-key)\",\n },\n },\n 401,\n );\n }\n c.set(\"sessionHash\", sessionHash(key));\n return next();\n};\n","/**\n * Pretest CLI — Per-Session Token Maps\n *\n * Keyed by sha256(API key) so two different API keys can never share\n * mutation map state. Each SessionState holds the forward + reverse\n * mutation maps used by the proxy to translate identifiers into\n * synthetic tokens (PretestMut markers) before the\n * request is forwarded upstream, and to reverse them on the response.\n */\n\nexport interface SessionState {\n /** original identifier -> transformed synthetic */\n mutationMap: Map<string, string>;\n /** transformed synthetic -> original identifier (used on response) */\n reverseMap: Map<string, string>;\n /** unix epoch ms the session was first created */\n createdAt: number;\n /** unix epoch ms of most recent activity (used for sweeping) */\n lastUsed: number;\n}\n\nconst sessions = new Map<string, SessionState>();\n\n/**\n * Fetch (or lazily create) the session associated with an API key hash.\n * Updates lastUsed on every access so idle sessions can be swept later.\n */\nexport function getSession(hash: string): SessionState {\n let s = sessions.get(hash);\n if (!s) {\n s = {\n mutationMap: new Map(),\n reverseMap: new Map(),\n createdAt: Date.now(),\n lastUsed: Date.now(),\n };\n sessions.set(hash, s);\n }\n s.lastUsed = Date.now();\n return s;\n}\n\n/** Number of active sessions. Exposed for /stats + tests. */\nexport function sessionCount(): number {\n return sessions.size;\n}\n\n/**\n * Clear every tracked session. Only used by tests so state does not\n * bleed between test cases.\n */\nexport function clearSessions(): void {\n sessions.clear();\n}\n\n/**\n * Remove sessions whose lastUsed is older than `maxAgeMs`. Returns the\n * number of sessions removed. Called on a timer by the long-lived proxy\n * process to bound memory growth.\n */\nexport function sweepSessions(maxAgeMs: number): number {\n const cutoff = Date.now() - maxAgeMs;\n let removed = 0;\n for (const [hash, s] of sessions.entries()) {\n if (s.lastUsed < cutoff) {\n sessions.delete(hash);\n removed++;\n }\n }\n return removed;\n}\n","/**\n * Pretest CLI — Git Context Collector\n *\n * Shells out to `git` to collect repo attribution metadata (remote URL,\n * branch, commit SHA) for POST to `/api/cli/log`. Every field is\n * optional: outside a git repo — or if `git` isn't installed — every\n * call returns an empty object and NEVER throws.\n *\n * The API side tolerates missing fields (see\n * `apps/web/src/app/api/cli/log/route.ts` — all three default to null),\n * so the CLI is free to skip collection without breaking logging.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Attribution metadata posted alongside every mutation log. All fields\n * optional — absent when the CLI is run outside a git repo or when\n * individual git commands fail (detached HEAD, no origin remote, etc.).\n */\nexport interface GitContext {\n git_remote?: string;\n git_branch?: string;\n git_commit_sha?: string;\n}\n\n/** Per-git-invocation timeout. Git should answer in milliseconds; 2s\n * is a generous upper bound that also caps worst-case hangs on\n * misconfigured remotes / filesystem stalls. */\nconst GIT_TIMEOUT_MS = 2000;\n\nasync function runGit(args: string[], cwd: string): Promise<string | undefined> {\n try {\n const { stdout } = await execFileAsync(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n windowsHide: true,\n });\n const trimmed = stdout.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Strip credentials from a remote URL so we never upload a PAT embedded\n * in `https://<token>@github.com/...`. Returns the input unchanged if it\n * doesn't parse as a URL — git also accepts scp-style `git@host:repo`,\n * which is safe to pass through verbatim.\n */\nexport function sanitizeRemote(raw: string): string {\n // scp-style SSH: `git@github.com:owner/repo.git`. No credentials\n // possible in that form.\n if (/^[\\w.-]+@[^:]+:/.test(raw) && !raw.includes(\"://\")) {\n return raw;\n }\n try {\n const url = new URL(raw);\n url.username = \"\";\n url.password = \"\";\n return url.toString();\n } catch {\n return raw;\n }\n}\n\n/**\n * Collect git repo metadata for attribution on `/api/cli/log`.\n *\n * Guarantees:\n * - Never throws. Failures return `{}` or partial context.\n * - Never blocks longer than ~3×GIT_TIMEOUT_MS.\n * - Strips credentials from HTTPS remote URLs.\n *\n * @param cwd working directory (defaults to process.cwd())\n */\nexport async function collectGitContext(cwd: string = process.cwd()): Promise<GitContext> {\n // Fast-fail when we're not inside a git worktree. This avoids three\n // stderr-spamming invocations on every proxy request in a non-repo\n // scratch dir.\n const insideRepo = await runGit([\"rev-parse\", \"--is-inside-work-tree\"], cwd);\n if (insideRepo !== \"true\") return {};\n\n const [remote, branch, sha] = await Promise.all([\n runGit([\"remote\", \"get-url\", \"origin\"], cwd),\n runGit([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], cwd),\n runGit([\"rev-parse\", \"HEAD\"], cwd),\n ]);\n\n const ctx: GitContext = {};\n if (remote) ctx.git_remote = sanitizeRemote(remote);\n // `rev-parse --abbrev-ref HEAD` returns `HEAD` in detached mode —\n // not useful, skip it.\n if (branch && branch !== \"HEAD\") ctx.git_branch = branch;\n if (sha) ctx.git_commit_sha = sha;\n return ctx;\n}\n\n// ─── Cache ───────────────────────────────────────────────────────────────────\n// The proxy calls uploadLog on every LLM request; shelling out to git\n// three times per request is wasted I/O. 30s TTL is short enough to\n// pick up a branch switch / new commit mid-session, long enough to\n// collapse a burst of requests to a single git read.\n\ninterface CacheEntry {\n value: GitContext;\n expiresAt: number;\n}\n\nconst CACHE_TTL_MS = 30_000;\nconst cache = new Map<string, CacheEntry>();\n\nexport async function collectGitContextCached(\n cwd: string = process.cwd(),\n now: number = Date.now(),\n): Promise<GitContext> {\n const hit = cache.get(cwd);\n if (hit && hit.expiresAt > now) return hit.value;\n const value = await collectGitContext(cwd);\n cache.set(cwd, { value, expiresAt: now + CACHE_TTL_MS });\n return value;\n}\n\n/** Test hook — clear the git-context cache. */\nexport function _resetGitContextCache(): void {\n cache.clear();\n}\n","/**\n * `pretest login` — store an API key in the user-level config so future\n * CLI runs can authenticate without re-entering it.\n *\n * Inputs (in priority order):\n * 1. --key <plaintext> explicit flag\n * 2. PRETEST_API_KEY (or legacy PRETENSE_API_KEY) env var one-shot use\n * 3. stdin (if piped) scripted use, e.g. `echo $KEY | pretest login`\n *\n * Storage: ~/.pretest/config.json with `{ api_key, saved_at }`. File is\n * created with mode 0o600 so other users on the host cannot read it.\n *\n * Validation: prefix must be `pk_live_` or `ptns_live_` (legacy). The\n * payload must be 16 chars or longer. We never call the network here —\n * a wrong key just fails on the next CLI run with a clear error message.\n */\n\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, chmodSync, readSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport readline from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport { migrateLegacyProjectConfigDir, PROJECT_CONFIG_DIR_NAME } from \"../config-dir.js\";\nimport {\n assignDashboardApiKeyToProcess,\n activeDashboardApiKeyEnvName,\n DASHBOARD_API_KEY_ENVS,\n firstNonEmptyEnv,\n} from \"../dashboard-env.js\";\nimport { PUBLISH_PACKAGE_URL } from \"../publish-info.js\";\n\nconst CONFIG_DIR_NAME = PROJECT_CONFIG_DIR_NAME;\nconst CONFIG_FILE = \"config.json\";\n\ninterface LoginConfig {\n api_key: string;\n saved_at: string;\n}\n\nexport function getUserDashboardConfigDir(): string {\n const home = homedir();\n migrateLegacyProjectConfigDir(home);\n return join(home, CONFIG_DIR_NAME);\n}\n\nexport function getUserDashboardConfigPath(): string {\n return join(getUserDashboardConfigDir(), CONFIG_FILE);\n}\n\n/** Validate the visible shape of a key. Network call happens later. */\nexport function isValidKeyShape(key: string): boolean {\n const trimmed = key.trim();\n if (trimmed.length < 24) return false;\n if (!/^[A-Za-z0-9_]+$/.test(trimmed)) return false;\n return (\n trimmed.startsWith(\"pk_live_\") ||\n trimmed.startsWith(\"ptns_live_\") ||\n trimmed.startsWith(\"prtns_live_\")\n );\n}\n\n/**\n * Read up to 4KB of stdin synchronously. Returns \"\" if stdin is a TTY\n * (i.e. nothing was piped in). Used so `echo $KEY | pretest login` works.\n */\nfunction readStdinIfPiped(): string {\n if (process.stdin.isTTY) return \"\";\n try {\n const chunks: Buffer[] = [];\n const buf = Buffer.alloc(4096);\n let bytesRead = 0;\n do {\n try {\n bytesRead = readSync(0, buf, 0, buf.length, null);\n } catch {\n // EAGAIN on some platforms — bail cleanly\n bytesRead = 0;\n }\n if (bytesRead > 0) chunks.push(Buffer.from(buf.subarray(0, bytesRead)));\n } while (bytesRead === buf.length);\n return Buffer.concat(chunks).toString(\"utf-8\").trim();\n } catch {\n return \"\";\n }\n}\n\nfunction maskKey(key: string): string {\n const trimmed = key.trim();\n if (trimmed.length <= 12) return trimmed;\n return `${trimmed.slice(0, 12)}${\"•\".repeat(8)}${trimmed.slice(-4)}`;\n}\n\n/** Helps explain logout/env vs ~/.pretest mismatches when troubleshooting start. */\nexport function logDashboardCredentialHint(): void {\n const envName = activeDashboardApiKeyEnvName();\n const env = envName ? (process.env[envName]?.trim() ?? \"\") : \"\";\n const envOk = env.length > 0 && isValidKeyShape(env);\n const abs = getUserDashboardConfigPath();\n const fk = loadApiKey();\n\n if (envOk && envName) {\n console.error(\n chalk.gray(\n `[pretest] Dashboard key source: ${envName} in environment (${maskKey(env)}) — ` +\n `unset this variable after logout if you expect no key.`,\n ),\n );\n } else if (fk && isValidKeyShape(fk)) {\n console.error(chalk.gray(`[pretest] Dashboard key source: ${abs} (${maskKey(fk)})`));\n } else {\n console.error(chalk.gray(\"[pretest] Dashboard key source: none configured.\"));\n }\n}\n\n/**\n * Persist the api key. Returns the path written.\n */\nexport function saveApiKey(key: string, configDir: string = getUserDashboardConfigDir()): string {\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n const path = join(configDir, CONFIG_FILE);\n\n // Merge with any existing config so we don't clobber unrelated fields.\n let existing: Record<string, unknown> = {};\n if (existsSync(path)) {\n try {\n existing = JSON.parse(readFileSync(path, \"utf-8\")) as Record<string, unknown>;\n } catch {\n existing = {};\n }\n }\n const next: Record<string, unknown> = {\n ...existing,\n api_key: key.trim(),\n saved_at: new Date().toISOString(),\n };\n writeFileSync(path, JSON.stringify(next, null, 2), { encoding: \"utf-8\", mode: 0o600 });\n try {\n chmodSync(path, 0o600);\n } catch {\n // Windows / sandboxed filesystems may reject — non-fatal.\n }\n return path;\n}\n\n/** Remove `api_key` and `saved_at` from user config; preserves other JSON fields. */\nexport function removeSavedDashboardCredentials(configDir: string = getUserDashboardConfigDir()): {\n removed: boolean;\n path: string;\n} {\n const path = join(configDir, CONFIG_FILE);\n if (!existsSync(path)) return { removed: false, path };\n let existing: Record<string, unknown> = {};\n try {\n existing = JSON.parse(readFileSync(path, \"utf-8\")) as Record<string, unknown>;\n } catch {\n return { removed: false, path };\n }\n const ak = existing.api_key;\n const hadKey = typeof ak === \"string\" && ak.trim().length > 0;\n if (!hadKey) return { removed: false, path };\n\n delete existing.api_key;\n delete existing.saved_at;\n writeFileSync(path, JSON.stringify(existing, null, 2), { encoding: \"utf-8\", mode: 0o600 });\n try {\n chmodSync(path, 0o600);\n } catch {\n /* ignore */\n }\n return { removed: true, path };\n}\n\n/**\n * Load the saved api key, if any. Used by other CLI commands that need to\n * authenticate against the dashboard API.\n */\nexport function loadApiKey(configDir: string = getUserDashboardConfigDir()): string | null {\n const path = join(configDir, CONFIG_FILE);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<LoginConfig>;\n if (typeof parsed.api_key === \"string\") {\n const t = parsed.api_key.trim();\n if (t.length > 0) return t;\n }\n } catch {\n /* ignore */\n }\n return null;\n}\n\ninterface RunLoginOptions {\n key?: string;\n configDir?: string;\n}\n\n/**\n * Resolve a dashboard API key from env (`PRETEST_API_KEY` or legacy `PRETENSE_API_KEY`) or `~/.pretest/config.json`.\n * Keys in the file that fail `isValidKeyShape` are ignored so the user can be re-prompted.\n */\nexport function resolveDashboardKeyCandidate(): {\n key: string | null;\n fromFile: boolean;\n /** An env var is non-empty but fails shape checks */\n badEnv: boolean;\n} {\n const env = firstNonEmptyEnv(DASHBOARD_API_KEY_ENVS);\n if (env.length > 0) {\n if (!isValidKeyShape(env)) {\n return { key: null, fromFile: false, badEnv: true };\n }\n return { key: env, fromFile: false, badEnv: false };\n }\n const fileKey = loadApiKey();\n if (fileKey && isValidKeyShape(fileKey)) {\n return { key: fileKey.trim(), fromFile: true, badEnv: false };\n }\n return { key: null, fromFile: Boolean(fileKey), badEnv: false };\n}\n\n/** Save key to ~/.pretest/config.json and make this process use it (overrides stale env). */\nexport function installDashboardKeyForCurrentProcess(key: string): string {\n const trimmed = key.trim();\n const path = saveApiKey(trimmed);\n assignDashboardApiKeyToProcess(trimmed);\n return path;\n}\n\n/**\n * Prompt for dashboard API key after validation failure (TTY only).\n * Returns null if stdin is not interactive or the user submits an empty line.\n */\nexport async function promptDashboardApiKeyAfterFailure(): Promise<string | null> {\n if (!process.stdin.isTTY || !process.stdout.isTTY) return null;\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const line = (await rl.question(chalk.bold(\"Dashboard API key: \"))).trim();\n return line.length > 0 ? line : null;\n } finally {\n rl.close();\n }\n}\n\n/**\n * Before `pretest start`: ensure a dashboard API key exists (env, saved config, or TTY prompt).\n * Does not call the network — `startProxy` validates with the backend.\n */\nexport async function ensureDashboardKeyForStart(): Promise<void> {\n const { key, fromFile, badEnv } = resolveDashboardKeyCandidate();\n if (badEnv) {\n console.error(\n chalk.red(\n \"Error: A dashboard API key is set in the environment but does not match the expected key shape.\",\n ),\n );\n console.error(\n chalk.gray(\n \"Keys look like prtns_live_… or pk_live_…. Fix the variable or unset it to use ~/.pretest/config.json.\",\n ),\n );\n process.exit(1);\n }\n if (key) {\n return;\n }\n\n if (fromFile) {\n console.warn(\n chalk.yellow(\n \"Ignoring invalid `api_key` in ~/.pretest/config.json (wrong shape). Enter a new key or run `pretest login --key ...`.\",\n ),\n );\n }\n\n const stdinOk = process.stdin.isTTY;\n const stdoutOk = process.stdout.isTTY;\n if (!stdinOk || !stdoutOk) {\n console.error(chalk.red(\"Error: Dashboard API key required to start the proxy.\"));\n console.error(\n chalk.gray(\"Save one with `pretest login --key prtns_live_...` or set PRETEST_API_KEY.\"),\n );\n process.exit(1);\n }\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n console.log(\n chalk.cyan(\n \"No dashboard API key found in ~/.pretest/config.json. Set PRETEST_API_KEY or run pretest login.\",\n ),\n );\n const entered = (await rl.question(chalk.bold(\"Enter your dashboard API key: \"))).trim();\n if (!entered) {\n console.error(chalk.red(\"No key entered; exiting.\"));\n process.exit(1);\n }\n if (!isValidKeyShape(entered)) {\n console.error(chalk.red(\"That does not look like a dashboard API key (expect prtns_live_… or pk_live_…).\"));\n console.error(chalk.gray(`Get a key via the package page, then run \\`pretest login --key ...\\`: ${PUBLISH_PACKAGE_URL}`));\n process.exit(1);\n }\n const path = installDashboardKeyForCurrentProcess(entered);\n console.log(chalk.green(\"Saved API key to\"), chalk.bold(path));\n console.log(chalk.gray(` ${maskKey(entered)}`));\n } finally {\n rl.close();\n }\n\n const persisted = resolveDashboardKeyCandidate();\n if (!persisted.key || persisted.badEnv) {\n console.error(chalk.red(\"Error: Dashboard API key could not be confirmed after login prompt.\"));\n process.exit(1);\n }\n}\n\nexport function runLogin(opts: RunLoginOptions = {}): number {\n const candidate =\n opts.key?.trim() ||\n firstNonEmptyEnv(DASHBOARD_API_KEY_ENVS) ||\n readStdinIfPiped();\n\n if (!candidate) {\n console.error(chalk.red(\"Error: no API key provided.\"));\n console.error(\n chalk.gray(\"Try: pretest login --key pk_live_xxxxx\"),\n );\n console.error(\n chalk.gray(\" or: echo $PRETEST_API_KEY | pretest login\"),\n );\n return 1;\n }\n\n if (!isValidKeyShape(candidate)) {\n console.error(chalk.red(\"Error: that does not look like a dashboard API key.\"));\n console.error(\n chalk.gray(\"Keys start with prtns_live_ (or pk_live_) and are at least 24 characters long.\"),\n );\n console.error(\n chalk.gray(`See: ${PUBLISH_PACKAGE_URL}`),\n );\n return 1;\n }\n\n const path = saveApiKey(candidate, opts.configDir);\n console.log(chalk.green(\"Saved API key to\"), chalk.bold(path));\n console.log(chalk.gray(` ${maskKey(candidate)}`));\n console.log(chalk.gray(\" File mode 600 — readable only by you.\"));\n return 0;\n}\n","/**\n * Environment variables for the dashboard API. `PRETEST_*` is preferred in docs and UI;\n * `PRETENSE_*` is still read for backwards compatibility.\n */\nexport const DASHBOARD_API_KEY_ENVS = [\"PRETEST_API_KEY\", \"PRETENSE_API_KEY\"] as const;\nexport const DASHBOARD_API_URL_ENVS = [\"PRETEST_API_URL\", \"PRETENSE_API_URL\"] as const;\n\n/** Skip ASCII banner when set to \"1\" */\nexport const DASHBOARD_NO_BANNER_ENVS = [\"PRETEST_NO_BANNER\", \"PRETENSE_NO_BANNER\"] as const;\n\nexport function firstNonEmptyEnv(names: readonly string[]): string {\n for (const name of names) {\n const v = process.env[name]?.trim();\n if (v) return v;\n }\n return \"\";\n}\n\n/** Which env name is providing the key (first match), if any */\nexport function activeDashboardApiKeyEnvName(): string | null {\n for (const name of DASHBOARD_API_KEY_ENVS) {\n const v = process.env[name]?.trim();\n if (v) return name;\n }\n return null;\n}\n\nexport function assignDashboardApiKeyToProcess(key: string): void {\n process.env[\"PRETEST_API_KEY\"] = key;\n process.env[\"PRETENSE_API_KEY\"] = key;\n}\n\nexport function clearDashboardApiKeyFromProcess(): void {\n delete process.env[\"PRETEST_API_KEY\"];\n delete process.env[\"PRETENSE_API_KEY\"];\n}\n\nexport function hasDashboardApiKeyInEnv(): boolean {\n return DASHBOARD_API_KEY_ENVS.some((n) => !!process.env[n]?.trim());\n}\n","/** Package/registry page shown in CLI help, pricing nudges, and dashboard key hints. */\nexport const PUBLISH_PACKAGE_URL = \"https://www.npmjs.com/package/@blockyfy/stg-cli\";\n","/**\r\n * Pretest CLI — Backend API Client\r\n *\r\n * Thin HTTP client for the dashboard `/api/cli/*` endpoints.\r\n * Handles key validation, usage reporting, and limit checks with\r\n * caching so the hot proxy path stays fast.\r\n */\r\n\r\nimport { loadApiKey } from \"./commands/login.js\";\r\nimport {\r\n DASHBOARD_API_KEY_ENVS,\r\n DASHBOARD_API_URL_ENVS,\r\n firstNonEmptyEnv,\r\n} from \"./dashboard-env.js\";\r\nimport { PUBLISH_PACKAGE_URL } from \"./publish-info.js\";\r\n\r\n// ─── Types mirroring backend DTOs ────────────────────────────────────────────\r\n\r\nexport interface ValidateResponse {\r\n valid: boolean;\r\n keyId: string;\r\n permission: \"read_write\" | \"read_only\";\r\n organizationId: string | null;\r\n organizationName: string | null;\r\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\";\r\n monthlyMutationLimit: number;\r\n mutationsUsed: number;\r\n mutationsRemaining: number;\r\n periodResetsAt: string;\r\n}\r\n\r\nexport interface UsageSummary {\r\n plan: \"FREE\" | \"PRO\" | \"ENTERPRISE\";\r\n monthlyMutationLimit: number;\r\n mutationsUsed: number;\r\n mutationsRemaining: number;\r\n requestsThisPeriod: number;\r\n secretsBlockedThisPeriod: number;\r\n periodResetsAt: string;\r\n keyExpiresAt: string | null;\r\n keyStatus: \"active\" | \"revoked\";\r\n}\r\n\r\n/** When GET /usage/summary fails, reuse validate payload for status display. */\r\nexport function usageSummaryFromValidate(v: ValidateResponse): UsageSummary {\r\n return {\r\n plan: v.plan,\r\n monthlyMutationLimit: v.monthlyMutationLimit,\r\n mutationsUsed: v.mutationsUsed,\r\n mutationsRemaining: v.mutationsRemaining,\r\n requestsThisPeriod: 0,\r\n secretsBlockedThisPeriod: 0,\r\n periodResetsAt: v.periodResetsAt,\r\n keyExpiresAt: null,\r\n keyStatus: \"active\",\r\n };\r\n}\r\n\r\n// ─── Configuration ───────────────────────────────────────────────────────────\r\n\r\nconst DEFAULT_PRETENSE_API_URL = \"https://pretense-stg-api.nxtsen.com\";\r\nconst DEFAULT_REQUEST_TIMEOUT_MS = 15_000;\r\n\r\n/**\r\n * Resolves the API root from `PRETEST_API_URL` or legacy `PRETENSE_API_URL`.\r\n * Supports a path prefix, e.g. `https://api.example.com/staging` →\r\n * `https://api.example.com/staging/api/cli/auth/validate` (not double `/api`).\r\n *\r\n * Legacy marketing hostname has no `/api/cli/*`; map host to the default API origin while keeping any path prefix.\r\n */\r\nexport function getConfiguredApiRoot(rootOverride?: string): string {\r\n const raw = (\r\n rootOverride?.trim() ||\r\n firstNonEmptyEnv(DASHBOARD_API_URL_ENVS) ||\r\n DEFAULT_PRETENSE_API_URL\r\n ).trim();\r\n if (!raw) {\r\n return DEFAULT_PRETENSE_API_URL.replace(/\\/$/, \"\");\r\n }\r\n let normalized = raw;\r\n if (!/^https?:\\/\\//i.test(normalized)) {\r\n normalized = `https://${normalized}`;\r\n }\r\n try {\r\n const u = new URL(normalized);\r\n const origin =\r\n /^pretense\\.ai$/i.test(u.hostname)\r\n ? DEFAULT_PRETENSE_API_URL.replace(/\\/$/, \"\")\r\n : u.origin;\r\n const path = u.pathname === \"/\" ? \"\" : u.pathname.replace(/\\/$/, \"\");\r\n return `${origin}${path}`;\r\n } catch {\r\n return DEFAULT_PRETENSE_API_URL.replace(/\\/$/, \"\");\r\n }\r\n}\r\n\r\n/**\r\n * Full URL for a CLI HTTP route (`auth/validate`, `log`, `usage/summary`).\r\n * @param pathWithinCli - segment after `/api/cli/` e.g. `auth/validate`\r\n */\r\nexport function getCliApiUrl(\r\n pathWithinCli: string,\r\n rootOverride?: string,\r\n): string {\r\n const root = getConfiguredApiRoot(rootOverride);\r\n const tail = pathWithinCli.replace(/^\\/+/, \"\");\r\n return `${root}/api/cli/${tail}`;\r\n}\r\n\r\nexport function getApiRequestTimeoutMs(): number {\r\n const raw =\r\n process.env[\"PRETEST_API_TIMEOUT_MS\"]?.trim() || process.env[\"PRETENSE_API_TIMEOUT_MS\"]?.trim();\r\n if (!raw || !/^\\d+$/.test(raw)) return DEFAULT_REQUEST_TIMEOUT_MS;\r\n const n = parseInt(raw, 10);\r\n return Math.min(Math.max(n, 3_000), 120_000);\r\n}\r\n\r\nfunction getApiKey(): string | null {\r\n const fromEnv = firstNonEmptyEnv(DASHBOARD_API_KEY_ENVS);\r\n if (fromEnv) return fromEnv;\r\n const fromFile = loadApiKey();\r\n if (!fromFile) return null;\r\n const t = fromFile.trim();\r\n return t.length > 0 ? t : null;\r\n}\r\n\r\n/** Dashboard API key for `/api/cli/*` — not the upstream LLM provider key. */\r\nexport function getDashboardApiKey(): string | null {\r\n return getApiKey();\r\n}\r\n\r\n/** @deprecated Use `getDashboardApiKey`; kept for internal call sites. */\r\nexport const getPretenseApiKey = getDashboardApiKey;\r\n\r\n// ─── Cached validation state ─────────────────────────────────────────────────\r\n\r\nlet cachedValidation: ValidateResponse | null = null;\r\n/** Last time we successfully refreshed `cachedValidation` from `/api/cli/auth/validate`. */\r\nlet lastValidationSuccessAt = 0;\r\n\r\n/** Re-fetch plan/quota from the backend when the cache is older than this (hot path). */\r\nconst VALIDATION_CACHE_FRESH_MS = 45_000;\r\n\r\nexport function getCachedValidation(): ValidateResponse | null {\r\n return cachedValidation;\r\n}\r\n\r\nexport function clearValidationCache(): void {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n}\r\n\r\n/**\r\n * After recording usage locally, adjust cached quota so `isWithinLimits()`\r\n * stays accurate without clearing the cache or refetching every request.\r\n */\r\nexport function bumpCachedUsageAfterLog(identifiersMutated: number): void {\r\n if (!cachedValidation || identifiersMutated <= 0) return;\r\n cachedValidation.mutationsUsed += identifiersMutated;\r\n if (cachedValidation.mutationsRemaining !== -1) {\r\n cachedValidation.mutationsRemaining = Math.max(\r\n 0,\r\n cachedValidation.mutationsRemaining - identifiersMutated,\r\n );\r\n }\r\n}\r\n\r\n// ─── API calls ───────────────────────────────────────────────────────────────\r\n\r\nfunction makeBackendReachabilityError(\r\n code: \"BACKEND_UNAVAILABLE\" | \"AUTH_BACKEND_REJECTED\",\r\n message: string,\r\n): Error & { code: string } {\r\n const err = new Error(message) as Error & { code: string };\r\n err.code = code;\r\n return err;\r\n}\r\n\r\n/**\r\n * Validate the API key against the backend. Caches the result for\r\n * CACHE_TTL_MS so repeated proxy requests don't hammer the server.\r\n *\r\n * Returns null if the backend is unreachable (offline/degraded mode)\r\n * **only when** `enforceReachability` is false (e.g. `status` / `credits`).\r\n *\r\n * When `enforceReachability` is true (proxy with a configured dashboard key),\r\n * network errors and non-OK HTTP responses reject so the proxy cannot run\r\n * against an unverified or bogus key.\r\n *\r\n * Throws on auth errors (401/403, valid: false) so callers can surface\r\n * actionable messages.\r\n */\r\nexport async function validateKey(\r\n opts: {\r\n force?: boolean;\r\n verbose?: boolean;\r\n enforceReachability?: boolean;\r\n } = {},\r\n): Promise<ValidateResponse | null> {\r\n const enforceReachability = opts.enforceReachability === true;\r\n const now = Date.now();\r\n const cacheFresh =\r\n cachedValidation !== null &&\r\n now - lastValidationSuccessAt < VALIDATION_CACHE_FRESH_MS;\r\n if (!opts.force && cacheFresh) {\r\n return cachedValidation;\r\n }\r\n\r\n const validateUrl = getCliApiUrl(\"auth/validate\");\r\n const timeoutMs = getApiRequestTimeoutMs();\r\n const apiKey = getApiKey();\r\n if (!apiKey) {\r\n if (enforceReachability) {\r\n const err = new Error(\"Missing dashboard API key\") as Error & {\r\n code: string;\r\n };\r\n err.code = \"MISSING_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n return null;\r\n }\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n try {\r\n const resp = await fetch(validateUrl, {\r\n method: \"POST\",\r\n headers: {\r\n \"content-type\": \"application/json\",\r\n authorization: `Bearer ${apiKey}`,\r\n },\r\n body: \"{}\",\r\n signal: controller.signal,\r\n });\r\n\r\n if (resp.status === 401 || resp.status === 403) {\r\n const raw = (await resp.json().catch(() => ({}))) as Record<\r\n string,\r\n unknown\r\n >;\r\n const msg =\r\n typeof raw.message === \"string\"\r\n ? raw.message\r\n : \"API key rejected by server\";\r\n const err = new Error(msg) as Error & { code: string };\r\n err.code = typeof raw.code === \"string\" ? raw.code : \"INVALID_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n\r\n if (!resp.ok) {\r\n const msg = `Dashboard API returned HTTP ${resp.status} from ${validateUrl}`;\r\n if (enforceReachability) {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\"AUTH_BACKEND_REJECTED\", msg);\r\n }\r\n return null;\r\n }\r\n\r\n let data: ValidateResponse;\r\n try {\r\n data = (await resp.json()) as ValidateResponse;\r\n } catch {\r\n if (enforceReachability) {\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\r\n \"AUTH_BACKEND_REJECTED\",\r\n `Invalid JSON from ${validateUrl}`,\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n if (typeof data.valid === \"boolean\" && data.valid === false) {\r\n const err = new Error(\"API key is not valid\") as Error & { code: string };\r\n err.code = \"INVALID_API_KEY\";\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw err;\r\n }\r\n\r\n cachedValidation = data;\r\n lastValidationSuccessAt = Date.now();\r\n return data;\r\n } catch (err) {\r\n if (\r\n (err as Error & { code?: string }).code === \"KEY_REVOKED\" ||\r\n (err as Error & { code?: string }).code === \"KEY_EXPIRED\" ||\r\n (err as Error & { code?: string }).code === \"INVALID_API_KEY\" ||\r\n (err as Error & { code?: string }).code === \"AUTH_ERROR\" ||\r\n (err as Error & { code?: string }).code === \"ORG_INACTIVE\" ||\r\n (err as Error & { code?: string }).code === \"MISSING_API_KEY\" ||\r\n (err as Error & { code?: string }).code === \"BACKEND_UNAVAILABLE\" ||\r\n (err as Error & { code?: string }).code === \"AUTH_BACKEND_REJECTED\"\r\n ) {\r\n throw err;\r\n }\r\n if (enforceReachability) {\r\n const msg =\r\n (err as Error).name === \"AbortError\"\r\n ? `Timed out after ${timeoutMs}ms reaching ${validateUrl} (raise PRETEST_API_TIMEOUT_MS or PRETENSE_API_TIMEOUT_MS)`\r\n : `Cannot reach dashboard API at ${validateUrl}: ${(err as Error).message}`;\r\n cachedValidation = null;\r\n lastValidationSuccessAt = 0;\r\n throw makeBackendReachabilityError(\"BACKEND_UNAVAILABLE\", msg);\r\n }\r\n if (opts.verbose) {\r\n process.stderr.write(\r\n `[PRETEST] Backend validation failed: ${(err as Error).message}\\n`,\r\n );\r\n }\r\n return null;\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n\r\n/**\r\n * Fetch usage summary from the backend. Returns null on network errors.\r\n */\r\nexport async function fetchUsageSummary(\r\n opts: { verbose?: boolean } = {},\r\n): Promise<UsageSummary | null> {\r\n const summaryUrl = getCliApiUrl(\"usage/summary\");\r\n const apiKey = getApiKey();\r\n if (!apiKey) return null;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), getApiRequestTimeoutMs());\r\n\r\n try {\r\n const resp = await fetch(summaryUrl, {\r\n method: \"GET\",\r\n headers: { authorization: `Bearer ${apiKey}` },\r\n signal: controller.signal,\r\n });\r\n\r\n if (!resp.ok) return null;\r\n return (await resp.json()) as UsageSummary;\r\n } catch (err) {\r\n if (opts.verbose) {\r\n process.stderr.write(\r\n `[PRETEST] Usage summary fetch failed: ${(err as Error).message}\\n`,\r\n );\r\n }\r\n return null;\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n}\r\n\r\n/**\r\n * Check whether the current key/org is within mutation limits.\r\n * When quota is unknown (no cached validation), allow — the proxy handler\r\n * only reaches this point after validateKey(strict) succeeds for paid mode.\r\n *\r\n * When the cache shows 0 remaining, re-validates against the backend before\r\n * blocking — the local cache can drift high if fire-and-forget log uploads\r\n * failed silently (bumped cache but never reached the DB).\r\n */\r\nexport async function isWithinLimits(): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n}> {\r\n const v = getCachedValidation();\r\n if (!v) return { allowed: true };\r\n\r\n if (v.mutationsRemaining !== -1 && v.mutationsRemaining <= 0) {\r\n const fresh = await validateKey({ force: true }).catch(() => null);\r\n const check = fresh ?? v;\r\n if (check.mutationsRemaining !== -1 && check.mutationsRemaining <= 0) {\r\n return {\r\n allowed: false,\r\n reason: `Monthly mutation limit reached (${check.mutationsUsed}/${check.monthlyMutationLimit}). See ${PUBLISH_PACKAGE_URL}`,\r\n };\r\n }\r\n return { allowed: true };\r\n }\r\n return { allowed: true };\r\n}\r\n","/**\n * Pretest CLI — Log Uploader\n *\n * Fire-and-forget POST of mutation events to `/api/cli/log`. Collects\n * git context (remote / branch / commit SHA) automatically and merges\n * it into the body.\n *\n * This runs AFTER the proxy has already forwarded the LLM request, so\n * uploader failures MUST NEVER impact the user's request path. All\n * errors are swallowed (optionally logged when verbose).\n */\n\nimport { collectGitContextCached, type GitContext } from \"./git-context.js\";\nimport { getApiRequestTimeoutMs, getCliApiUrl } from \"./backend-client.js\";\n\n/** Payload matching the `/api/cli/log` route contract. All optional. */\nexport interface LogUploadEvent {\n file_count?: number;\n identifiers_mutated?: number;\n secrets_blocked?: number;\n llm_provider?: string;\n scan_tokens?: number;\n mutation_tokens?: number;\n read_tokens?: number;\n cli_version?: string;\n}\n\nexport interface LogUploadOptions {\n /**\n * Base API root (same semantics as `PRETENSE_API_URL`).\n * Omit to use `PRETENSE_API_URL` from the environment.\n */\n apiUrl?: string;\n /** API key — must match a row in `api_keys`. */\n apiKey: string;\n /** Optional override for git-context (mostly for tests). */\n gitContext?: GitContext;\n /** Working directory for git lookups (defaults to process.cwd()). */\n cwd?: string;\n /** Abort the POST after this many ms (default: `PRETENSE_API_TIMEOUT_MS` or 15s). */\n timeoutMs?: number;\n /** If true, log errors to stderr instead of silently swallowing. */\n verbose?: boolean;\n}\n\n/**\n * POST an event to `/api/cli/log`, merging git context into the body.\n * Resolves once the server returns (or the request times out / errors).\n * NEVER rejects — callers can `void uploadLog(...)` without a try/catch.\n */\nexport async function uploadLog(\n event: LogUploadEvent,\n options: LogUploadOptions,\n): Promise<void> {\n const apiRoot = options.apiUrl?.trim() || undefined;\n const endpoint = getCliApiUrl(\"log\", apiRoot);\n const { apiKey, verbose = false, timeoutMs = getApiRequestTimeoutMs() } = options;\n if (!apiKey) return;\n\n const gitCtx = options.gitContext ?? (await collectGitContextCached(options.cwd));\n\n // The API route currently accepts `repo_remote_url`, `git_branch`,\n // `commit_sha` (see apps/web/src/app/api/cli/log/route.ts). We also\n // send `git_remote` / `git_commit_sha` under their git-canonical\n // names as a forward-compat bridge — unknown fields are ignored\n // server-side. When the route migrates to the canonical names we\n // drop the legacy aliases in a follow-up.\n const body = {\n ...event,\n ...gitCtx,\n repo_remote_url: gitCtx.git_remote,\n git_branch: gitCtx.git_branch,\n commit_sha: gitCtx.git_commit_sha,\n };\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const resp = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!resp.ok && verbose) {\n process.stderr.write(`[PRETEST] log upload HTTP ${resp.status}\\n`);\n }\n } catch (err) {\n if (verbose) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[PRETEST] log upload failed: ${msg}\\n`);\n }\n } finally {\n clearTimeout(timer);\n }\n}\n","/**\n * Copy/paste env hints printed after the proxy key validates.\n */\n\nimport chalk from \"chalk\";\nimport { PUBLISH_PACKAGE_URL } from \"./publish-info.js\";\n\nexport function printStartClientInstructions(port: number): void {\n const host = `http://localhost:${port}`;\n console.log();\n console.log(chalk.cyan.bold(\"── Client setup (environment variables) ──\"));\n console.log(chalk.gray(\"Point the CLI at the backend API (optional if using default):\"));\n console.log(\n chalk.white(`export PRETEST_API_URL='https://pretense-stg-api.nxtsen.com'`),\n );\n console.log();\n console.log(chalk.gray(\"Log in with your dashboard API key:\"));\n console.log(chalk.white(\"pretest login --key your-dashboard-api-key\"));\n console.log();\n console.log(\n chalk.gray(\"Documentation:\"),\n chalk.cyan.underline(PUBLISH_PACKAGE_URL),\n );\n console.log();\n console.log(\n chalk.gray(\"Set the LLM base URL for your provider (proxy below):\"),\n );\n console.log(chalk.white(`export ANTHROPIC_BASE_URL=\"${host}\"`));\n console.log(chalk.white(`export ANTHROPIC_BASE_URL=${host}`));\n console.log(chalk.white(`export OPENAI_BASE_URL=${host}/v1`));\n console.log(chalk.white(`export GEMINI_BASE_URL=${host}/v1beta`));\n console.log(chalk.white(`export OLLAMA_HOST=${host}`));\n console.log();\n console.log(chalk.gray(\"Set your real upstream LLM API key (unchanged):\"));\n console.log(chalk.white('export ANTHROPIC_API_KEY=\"sk-ant-API-KEY\"'));\n console.log();\n console.log(chalk.cyan.bold(\"── Stop & log out ──\"));\n console.log(\n chalk.gray(\n \"Stop the proxy: press Ctrl+C in the terminal where pretest start is running.\",\n ),\n );\n console.log(\n chalk.gray(\n \"Remove the saved dashboard key from ~/.pretest/config.json:\",\n ),\n );\n console.log(chalk.white(\"pretest logout\"));\n console.log(\n chalk.gray(\n \"(confirm with y / cancel with n.) Mutations stop immediately unless this proxy was started with\",\n ),\n );\n console.log(\n chalk.gray(\n \"PRETEST_API_KEY in that same terminal — then press Ctrl+C and run pretest start again.\",\n ),\n );\n console.log();\n}\n","/**\n * Single source for CLI semver — reads adjacent package.json (works from src/ and dist/).\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nlet cached: string | null = null;\n\nexport function getCliSemver(): string {\n if (cached !== null) return cached;\n try {\n const url = new URL(\"../package.json\", import.meta.url);\n const raw = readFileSync(fileURLToPath(url), \"utf-8\");\n cached = (JSON.parse(raw) as { version?: string }).version ?? \"0.0.0\";\n } catch {\n cached = \"0.0.0\";\n }\n return cached;\n}\n","/**\n * Pretest CLI — Token Visibility Footer\n *\n * Prints a small footer after scan/mutate commands so users always know\n * (a) what plan they're on, (b) how much of their monthly quota they have\n * left, and (c) where to upgrade. This is the \"tokens remaining\" bar that\n * pre-seed CISOs expect from a paid security tool.\n */\n\nimport chalk from \"chalk\";\nimport { detectTier, getTierLimits, loadUsage, type LicenseTier } from \"./config.js\";\n\ninterface PlanLimits {\n monthlyMutations: number;\n monthlyScans: number;\n seats: number;\n pricePerMonth: string;\n}\n\nconst PLAN_LIMITS: Record<LicenseTier, PlanLimits> = {\n free: { monthlyMutations: 1000, monthlyScans: 5000, seats: 3, pricePerMonth: \"$0/month\" },\n pro: { monthlyMutations: 100000, monthlyScans: 500000, seats: 25, pricePerMonth: \"$29/seat/month\" },\n enterprise: {\n monthlyMutations: Number.POSITIVE_INFINITY,\n monthlyScans: Number.POSITIVE_INFINITY,\n seats: Number.POSITIVE_INFINITY,\n pricePerMonth: \"$99/seat/month\",\n },\n};\n\nexport function getPlanLimits(tier: LicenseTier): PlanLimits {\n return PLAN_LIMITS[tier];\n}\n\nfunction fmt(n: number): string {\n if (!Number.isFinite(n)) return \"unlimited\";\n return n.toLocaleString(\"en-US\");\n}\n\n/**\n * Print a one-line \"tokens remaining\" footer after a CLI command completes.\n * Stays silent on enterprise tier (no quota to nag about).\n */\nexport function printTokenFooter(filesScanned: number, mutationsMade: number): void {\n const tier = detectTier();\n const limits = getPlanLimits(tier);\n const usage = loadUsage();\n\n // Enterprise users should not see upgrade nags\n if (tier === \"enterprise\") {\n process.stderr.write(\n chalk.gray(`\\n ${filesScanned} files, ${mutationsMade} mutations · Plan: Enterprise (unlimited)\\n\\n`),\n );\n return;\n }\n\n const used = usage.mutations;\n const cap = limits.monthlyMutations;\n const pct = cap > 0 ? Math.min(100, Math.round((used / cap) * 100)) : 0;\n\n // Reserve color for warning when over 80%\n const usageStr = pct >= 80 ? chalk.yellow(`${fmt(used)} / ${fmt(cap)}`) : chalk.gray(`${fmt(used)} / ${fmt(cap)}`);\n\n process.stderr.write(\n `\\n ${chalk.cyan(filesScanned + \" files\")}, ${chalk.cyan(mutationsMade + \" mutations\")} ` +\n `· Plan: ${chalk.bold(tier.toUpperCase())} · Mutations this month: ${usageStr} (${pct}%)\\n`,\n );\n\n if (tier === \"free\") {\n if (pct >= 80) {\n process.stderr.write(\n chalk.yellow(` ⚠ Approaching free-tier limit. Upgrade: ${chalk.bold(\"pretest upgrade\")}\\n\\n`),\n );\n } else {\n process.stderr.write(\n chalk.gray(` Run ${chalk.bold(\"pretest status\")} for details, ${chalk.bold(\"pretest upgrade\")} to remove limits.\\n\\n`),\n );\n }\n } else {\n process.stderr.write(\"\\n\");\n }\n}\n","/**\n * Pretest CLI banner.\n *\n * Printed before the commander routes a subcommand. Silent when the\n * terminal is a CI environment, pipeline, or non-TTY, or when the user\n * sets PRETEST_NO_BANNER=1 (legacy: PRETENSE_NO_BANNER).\n *\n * Ice-blue tint (#7DD3FC) is applied via chalk.hex which needs a 256-color\n * terminal. We wrap the tint call in try/catch so older terminals without\n * truecolor support silently fall back to the plain banner. Never break\n * startup because a user runs Pretest on a legacy shell.\n */\n\nimport chalk from \"chalk\";\nimport { DASHBOARD_NO_BANNER_ENVS } from \"./dashboard-env.js\";\n\nconst BANNER_RAW = `██████████████ pretest\n██ ██\n██ ██ Stop your code from\n██ ██ leaking to any LLM.\n██████████████\n██ @blockyfy/stg-cli\n██\n██\n██\n██`;\n\nconst ICE_BLUE = \"#7DD3FC\";\n\nfunction shouldPrint(): boolean {\n if (DASHBOARD_NO_BANNER_ENVS.some((n) => process.env[n] === \"1\")) return false;\n if (!process.stdout.isTTY) return false;\n if (process.env.CI) return false;\n return true;\n}\n\nfunction tint(line: string): string {\n // chalk.hex is only safe on terminals that understand truecolor or 256-color.\n // If chalk throws or the user's terminal strips the escape codes, we print\n // the plain line instead of garbled output.\n try {\n return chalk.hex(ICE_BLUE)(line);\n } catch {\n return line;\n }\n}\n\nexport function printBanner(): void {\n if (!shouldPrint()) return;\n const lines = BANNER_RAW.split(\"\\n\");\n for (const line of lines) {\n process.stderr.write(tint(line) + \"\\n\");\n }\n process.stderr.write(\"\\n\");\n}\n","/**\n * Pretest CLI — `status` command\n *\n * Shows the current plan, monthly quota usage, seat count, and quick\n * upgrade hint. Fetches from the backend when reachable; falls back\n * to local state when offline.\n */\n\nimport chalk from \"chalk\";\nimport { detectTier, getTierLimits, loadUsage, type LicenseTier } from \"../config.js\";\nimport { getPlanLimits } from \"../token-footer.js\";\nimport {\n fetchUsageSummary,\n usageSummaryFromValidate,\n validateKey,\n} from \"../backend-client.js\";\nimport { getCliSemver } from \"../version.js\";\n\nconst PLAN_LABEL: Record<LicenseTier, string> = {\n free: \"Free\",\n pro: \"Pro\",\n enterprise: \"Enterprise\",\n};\n\nfunction fmt(n: number): string {\n if (n === -1 || !Number.isFinite(n)) return \"unlimited\";\n return n.toLocaleString(\"en-US\");\n}\n\nexport async function runStatus(): Promise<void> {\n // Prefer GET /usage/summary (full request/secrets stats); fall back to POST\n // /auth/validate so `status` matches Postman when summary is unreachable.\n let remote = await fetchUsageSummary();\n if (!remote) {\n const v = await validateKey({ force: true });\n if (v?.valid) {\n remote = usageSummaryFromValidate(v);\n }\n }\n\n if (remote) {\n const plan = remote.plan;\n const tierBadge =\n plan === \"ENTERPRISE\"\n ? chalk.bgMagenta.white.bold(\" ENTERPRISE \")\n : plan === \"PRO\"\n ? chalk.bgBlue.white.bold(\" PRO \")\n : chalk.bgGray.white.bold(\" FREE \");\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(`${chalk.cyan(\"Pretest\")} ${chalk.gray(`v${getCliSemver()}`)} ${tierBadge} ${chalk.green(\"(synced)\")}`);\n lines.push(\"\");\n lines.push(` Plan: ${chalk.bold(plan)}`);\n lines.push(` Mutations: ${fmt(remote.mutationsUsed)} / ${fmt(remote.monthlyMutationLimit)} this month`);\n lines.push(` Remaining: ${fmt(remote.mutationsRemaining)}`);\n lines.push(` Requests: ${fmt(remote.requestsThisPeriod)} this period`);\n lines.push(` Secrets: ${fmt(remote.secretsBlockedThisPeriod)} blocked`);\n lines.push(` Key status: ${remote.keyStatus === \"active\" ? chalk.green(\"active\") : chalk.red(\"revoked\")}`);\n lines.push(` Resets at: ${new Date(remote.periodResetsAt).toLocaleDateString()}`);\n if (remote.keyExpiresAt) {\n lines.push(` Key expires: ${new Date(remote.keyExpiresAt).toLocaleDateString()}`);\n }\n lines.push(\"\");\n\n if (plan === \"FREE\") {\n lines.push(` ${chalk.gray(\"Upgrade:\")} ${chalk.bold(\"pretest upgrade\")}`);\n lines.push(\"\");\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n return;\n }\n\n // Fallback: local-only status.\n const tier = detectTier();\n const planLimits = getPlanLimits(tier);\n const tierLimits = getTierLimits(tier);\n const usage = loadUsage();\n\n const tierBadge =\n tier === \"enterprise\"\n ? chalk.bgMagenta.white.bold(\" ENTERPRISE \")\n : tier === \"pro\"\n ? chalk.bgBlue.white.bold(\" PRO \")\n : chalk.bgGray.white.bold(\" FREE \");\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(`${chalk.cyan(\"Pretest\")} ${chalk.gray(`v${getCliSemver()}`)} ${tierBadge} ${chalk.yellow(\"(offline)\")}`);\n lines.push(\"\");\n lines.push(` Plan: ${chalk.bold(PLAN_LABEL[tier])} ${chalk.gray(\"(\" + planLimits.pricePerMonth + \")\")}`);\n lines.push(` Mutations: ${fmt(usage.mutations)} / ${fmt(planLimits.monthlyMutations)} this month`);\n lines.push(` Scans: 0 / ${fmt(planLimits.monthlyScans)} this month`);\n lines.push(` Seats: 1 / ${fmt(planLimits.seats)}`);\n lines.push(` Audit log: ${Number.isFinite(tierLimits.auditRetentionDays) ? `${tierLimits.auditRetentionDays} days` : \"unlimited\"}`);\n lines.push(\"\");\n\n if (tier === \"free\") {\n lines.push(` ${chalk.gray(\"Upgrade:\")} ${chalk.bold(\"pretest upgrade\")}`);\n lines.push(` ${chalk.gray(\"Credits:\")} ${chalk.bold(\"pretest credits\")}`);\n lines.push(\"\");\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n}\n","/**\n * Pretest CLI — `upgrade` command\n *\n * Prints a side-by-side comparison of Free / Pro / Enterprise tiers and\n * a one-click URL to start checkout. Doubles as the in-CLI pricing page.\n */\n\nimport chalk from \"chalk\";\nimport { detectTier } from \"../config.js\";\n\nimport { PUBLISH_PACKAGE_URL } from \"../publish-info.js\";\n\nconst PRICING_URL = PUBLISH_PACKAGE_URL;\n\nexport function runUpgrade(): void {\n const tier = detectTier();\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(chalk.cyan.bold(\" Pretest Plans\"));\n lines.push(\"\");\n lines.push(chalk.gray(\" ┌──────────────┬──────────┬──────────┬─────────────┐\"));\n lines.push(chalk.gray(\" │ │ Free │ Pro │ Enterprise │\"));\n lines.push(chalk.gray(\" ├──────────────┼──────────┼──────────┼─────────────┤\"));\n lines.push(` │ Price/seat │ ${chalk.bold(\"$0\")} │ ${chalk.bold(\"$29\")} │ ${chalk.bold(\"$99\")} │`);\n lines.push(\" │ Mutations/mo │ 1,000 │ 100,000 │ unlimited │\");\n lines.push(\" │ Scans/mo │ 5,000 │ 500,000 │ unlimited │\");\n lines.push(\" │ Seats │ 3 │ 25 │ unlimited │\");\n lines.push(\" │ Audit log │ 30 days │ 90 days │ unlimited │\");\n lines.push(\" │ SSO/SAML │ - │ - │ yes │\");\n lines.push(\" │ On-prem │ - │ - │ yes │\");\n lines.push(\" │ SLA │ - │ - │ 24/7 │\");\n lines.push(chalk.gray(\" └──────────────┴──────────┴──────────┴─────────────┘\"));\n lines.push(\"\");\n lines.push(` ${chalk.gray(\"Current plan:\")} ${chalk.bold(tier.toUpperCase())}`);\n lines.push(` ${chalk.gray(\"Upgrade at:\")} ${chalk.cyan.underline(PRICING_URL)}`);\n lines.push(\"\");\n lines.push(chalk.gray(\" After purchase, set:\"));\n lines.push(chalk.gray(\" export PRETEST_LICENSE_KEY=pre_pro_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"));\n lines.push(\"\");\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n}\n","/**\n * Pretest CLI — `credits` command\n *\n * Friendly summary of how much of the monthly mutation/scan quota the\n * user has burned through. Fetches from backend when reachable; falls\n * back to local state when offline.\n */\n\nimport chalk from \"chalk\";\nimport { detectTier, loadUsage, type LicenseTier } from \"../config.js\";\nimport { getPlanLimits } from \"../token-footer.js\";\nimport {\n fetchUsageSummary,\n usageSummaryFromValidate,\n validateKey,\n} from \"../backend-client.js\";\n\nconst PLAN_LABEL: Record<LicenseTier, string> = {\n free: \"Free\",\n pro: \"Pro\",\n enterprise: \"Enterprise\",\n};\n\nfunction fmt(n: number): string {\n if (n === -1 || !Number.isFinite(n)) return \"unlimited\";\n return n.toLocaleString(\"en-US\");\n}\n\nfunction progressBar(used: number, cap: number, width = 24): string {\n if (cap === -1 || !Number.isFinite(cap) || cap <= 0) return chalk.green(\"[\" + \"=\".repeat(width) + \"]\");\n const pct = Math.min(1, used / cap);\n const filled = Math.round(pct * width);\n const bar = \"=\".repeat(filled) + \"-\".repeat(width - filled);\n const colored = pct >= 0.8 ? chalk.yellow(bar) : pct >= 1 ? chalk.red(bar) : chalk.green(bar);\n return \"[\" + colored + \"]\";\n}\n\nexport async function runCredits(): Promise<void> {\n let remote = await fetchUsageSummary();\n if (!remote) {\n const v = await validateKey({ force: true });\n if (v?.valid) {\n remote = usageSummaryFromValidate(v);\n }\n }\n\n if (remote) {\n const used = remote.mutationsUsed;\n const cap = remote.monthlyMutationLimit;\n const remaining = remote.mutationsRemaining;\n const pct = cap > 0 && cap !== -1 ? Math.round((used / cap) * 100) : 0;\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(chalk.cyan.bold(\" Pretest Credits\") + \" \" + chalk.green(\"(synced)\"));\n lines.push(\"\");\n lines.push(` Plan: ${chalk.bold(remote.plan)}`);\n lines.push(` Resets: ${new Date(remote.periodResetsAt).toLocaleDateString()}`);\n lines.push(\"\");\n lines.push(` Mutations: ${progressBar(used, cap)} ${fmt(used)} / ${fmt(cap)}`);\n lines.push(` Used: ${pct}%`);\n lines.push(` Remaining: ${fmt(remaining)}`);\n lines.push(\"\");\n\n if (remote.plan === \"FREE\" && cap !== -1 && used >= cap * 0.8) {\n lines.push(chalk.yellow(\" Warning: Approaching free-tier limit. Run 'pretest upgrade' for unlimited.\"));\n lines.push(\"\");\n } else if (remote.plan === \"FREE\") {\n lines.push(chalk.gray(\" Tip: Run 'pretest upgrade' to compare plans.\"));\n lines.push(\"\");\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n return;\n }\n\n // Fallback: local-only credits.\n const tier = detectTier();\n const limits = getPlanLimits(tier);\n const usage = loadUsage();\n\n const used = usage.mutations;\n const cap = limits.monthlyMutations;\n const remaining = Number.isFinite(cap) ? Math.max(0, cap - used) : Number.POSITIVE_INFINITY;\n const pct = Number.isFinite(cap) && cap > 0 ? Math.round((used / cap) * 100) : 0;\n\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(chalk.cyan.bold(\" Pretest Credits\") + \" \" + chalk.yellow(\"(offline)\"));\n lines.push(\"\");\n lines.push(` Plan: ${chalk.bold(PLAN_LABEL[tier])}`);\n lines.push(` Month: ${usage.month}`);\n lines.push(\"\");\n lines.push(` Mutations: ${progressBar(used, cap)} ${fmt(used)} / ${fmt(cap)}`);\n lines.push(` Used: ${pct}%`);\n lines.push(` Remaining: ${fmt(remaining)}`);\n lines.push(\"\");\n\n if (tier === \"free\" && Number.isFinite(cap) && used >= cap * 0.8) {\n lines.push(chalk.yellow(\" Warning: Approaching free-tier limit. Run 'pretest upgrade' for unlimited.\"));\n lines.push(\"\");\n } else if (tier === \"free\") {\n lines.push(chalk.gray(\" Tip: Run 'pretest upgrade' to compare plans.\"));\n lines.push(\"\");\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n}\n","/**\n * `pretest logout` — remove the saved dashboard API key from\n * ~/.pretest/config.json after interactive confirmation.\n */\n\nimport readline from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport { loadApiKey, removeSavedDashboardCredentials } from \"./login.js\";\nimport { clearValidationCache } from \"../backend-client.js\";\nimport { clearDashboardApiKeyFromProcess, hasDashboardApiKeyInEnv } from \"../dashboard-env.js\";\n\nexport async function runLogout(opts: { assumeYes?: boolean } = {}): Promise<number> {\n if (!loadApiKey()) {\n console.log(chalk.gray(\"No saved dashboard API key in ~/.pretest/config.json.\"));\n console.log(\n chalk.gray(\"If you use PRETEST_API_KEY in your shell, run unset PRETEST_API_KEY.\"),\n );\n return 0;\n }\n\n if (!opts.assumeYes) {\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n console.error(chalk.red(\"Error: confirmation requires an interactive terminal.\"));\n console.error(chalk.gray(\"Run `pretest logout --yes` to skip the prompt.\"));\n return 1;\n }\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const raw = await rl.question(\n chalk.bold(\"Log out and remove your saved API key? Type y for yes, n for no: \"),\n );\n const answer = raw.trim().toLowerCase();\n if (answer !== \"y\" && answer !== \"yes\") {\n console.log(chalk.yellow(\"Logout cancelled.\"));\n return 0;\n }\n } finally {\n rl.close();\n }\n }\n\n const hadEnvDashboardKey = hasDashboardApiKeyInEnv();\n const { removed, path } = removeSavedDashboardCredentials();\n clearValidationCache();\n clearDashboardApiKeyFromProcess();\n\n if (removed) {\n console.log(chalk.green(\"Logged out. Removed saved API key from\"), chalk.bold(path));\n console.log(\n chalk.gray(\"Other terminals: run unset PRETEST_API_KEY if that variable is still exported (e.g. in ~/.zshrc).\"),\n );\n if (hadEnvDashboardKey) {\n console.log(\n chalk.yellow(\n \"This shell had a dashboard key in the environment; it was cleared for this process only. Restart any running pretest proxy (Ctrl+C, then pretest start).\",\n ),\n );\n }\n }\n return 0;\n}\n"],"mappings":"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","names":["chalk","readFileSync","existsSync","readSync","resolve","join","existsSync","renameSync","join","join","existsSync","renameSync","scan","start","readFileSync","writeFileSync","mkdirSync","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","join","writeFileSync","readFileSync","join","existsSync","readFileSync","mkdirSync","writeFileSync","existsSync","readFileSync","mkdirSync","join","dirname","join","dirname","existsSync","mkdirSync","readFileSync","existsSync","existsSync","mkdirSync","writeFileSync","readFileSync","join","homedir","CONFIG_DIR_NAME","CONFIG_FILE","homedir","join","existsSync","mkdirSync","readFileSync","writeFileSync","chalk","chalk","readFileSync","existsSync","upstream","headers","scan","resolve","chalk","chalk","chalk","chalk","chalk","fmt","tierBadge","chalk","lines","chalk","chalk","chalk","PLAN_LABEL","fmt","chalk","used","cap","remaining","pct","lines","readline","chalk","chalk","readline","readSync","resolve","existsSync","join","chalk","scan","readFileSync"]}