@americano98/peye 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/bin.ts","../package.json","../src/cli/compare-command.ts","../src/config/defaults.ts","../src/core/run-compare.ts","../src/utils/errors.ts","../src/utils/severity.ts","../src/analysis/findings.ts","../src/analysis/recommendation.ts","../src/capture/playwright-capture.ts","../src/io/image.ts","../src/compare/engine.ts","../src/compare/regions.ts","../src/compare/structure.ts","../src/compare/heatmap.ts","../src/io/fs.ts","../src/io/inputs.ts","../src/utils/url.ts","../src/utils/viewport.ts","../src/reference/figma-mcp-reference-provider.ts","../src/reference/figma-rest-reference-provider.ts","../src/reference/figma-reference-provider.ts","../src/reference/local-reference-provider.ts","../src/reference/index.ts","../src/types/report.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport packageJson from \"../../package.json\" with { type: \"json\" };\nimport { registerCompareCommand, handleCliError } from \"./compare-command.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"peye\")\n .version(packageJson.version)\n .description(\n \"Standalone visual diff CLI for comparing preview screenshots against Figma references.\",\n )\n .configureHelp({\n sortOptions: true,\n sortSubcommands: true,\n })\n .showHelpAfterError();\n\nregisterCompareCommand(program);\n\nprogram.parseAsync(process.argv).catch(handleCliError);\n","{\n \"name\": \"@americano98/peye\",\n \"version\": \"0.1.0\",\n \"description\": \"Standalone CLI for visual diffing UI screenshots against Figma references.\",\n \"type\": \"module\",\n \"packageManager\": \"pnpm@10.11.0\",\n \"bin\": {\n \"peye\": \"dist/bin.js\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\"\n ],\n \"engines\": {\n \"node\": \">=22\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"clean\": \"rm -rf coverage dist test-output peye-output\",\n \"dev\": \"tsx src/cli/bin.ts\",\n \"format\": \"prettier . --write\",\n \"format:check\": \"prettier . --check\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"prepack\": \"pnpm check\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc --noEmit\",\n \"check\": \"pnpm format:check && pnpm typecheck && pnpm lint && pnpm test && pnpm build\"\n },\n \"keywords\": [\n \"cli\",\n \"visual-diff\",\n \"figma\",\n \"playwright\",\n \"pixelmatch\"\n ],\n \"homepage\": \"https://github.com/americano98/peye#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/americano98/peye.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/americano98/peye/issues\"\n },\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"1.27.1\",\n \"commander\": \"^14.0.3\",\n \"pixelmatch\": \"7.1.0\",\n \"playwright\": \"1.58.2\",\n \"sharp\": \"0.34.5\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"10.0.1\",\n \"@types/node\": \"^22.19.15\",\n \"eslint\": \"10.0.3\",\n \"eslint-config-prettier\": \"10.1.8\",\n \"globals\": \"17.4.0\",\n \"prettier\": \"3.8.1\",\n \"tsup\": \"8.5.1\",\n \"tsx\": \"4.21.0\",\n \"typescript\": \"5.9.3\",\n \"typescript-eslint\": \"8.57.1\",\n \"vitest\": \"^4.1.0\"\n }\n}\n","import path from \"node:path\";\nimport type { Command } from \"commander\";\nimport { DEFAULT_MODE, DEFAULT_THRESHOLDS } from \"../config/defaults.js\";\nimport { runCompare } from \"../core/run-compare.js\";\nimport { COMPARE_MODES, type CompareCommandOptions } from \"../types/report.js\";\nimport { AppError, isAppError } from \"../utils/errors.js\";\n\ninterface CompareCliOptions extends CompareCommandOptions {\n quiet: boolean;\n reportStdout: boolean;\n}\n\nexport function registerCompareCommand(program: Command): void {\n program\n .command(\"compare\")\n .description(\"Compare a preview screenshot or URL against a Figma reference or local image.\")\n .requiredOption(\"--preview <url|path>\", \"Preview URL or screenshot path\")\n .requiredOption(\"--reference <figma-url|path>\", \"Figma URL or local reference screenshot path\")\n .requiredOption(\"--output <dir>\", \"Output directory for report and generated artifacts\")\n .option(\n \"--viewport <width|widthxheight>\",\n \"Viewport width or widthxheight used for preview URL capture, for example 1920 or 1920x900\",\n )\n .option(\"--mode <mode>\", \"Analysis mode: all, pixel, layout, color\", DEFAULT_MODE)\n .option(\"--selector <css>\", \"CSS selector for preview element capture\")\n .option(\"--full-page\", \"Capture the full preview page when preview is a URL\", false)\n .option(\"--quiet\", \"Suppress the human-readable terminal summary\", false)\n .option(\n \"--report-stdout\",\n \"Write compact report JSON to stdout and suppress the human-readable summary\",\n false,\n )\n .option(\n \"--threshold-pass <number>\",\n \"Pass threshold in percent\",\n parseFloat,\n DEFAULT_THRESHOLDS.pass,\n )\n .option(\n \"--threshold-tolerated <number>\",\n \"Tolerated threshold in percent\",\n parseFloat,\n DEFAULT_THRESHOLDS.tolerated,\n )\n .option(\n \"--threshold-retry <number>\",\n \"Retry threshold in percent\",\n parseFloat,\n DEFAULT_THRESHOLDS.retry,\n )\n .action(async (rawOptions: CompareCliOptions) => {\n const { quiet, reportStdout, ...options } = validateOptions(rawOptions);\n const result = await runCompare(options);\n\n writeCliOutput(result.report, { quiet, reportStdout });\n process.exitCode = result.exitCode;\n });\n}\n\nfunction validateOptions(options: CompareCliOptions): CompareCliOptions {\n if (!COMPARE_MODES.includes(options.mode)) {\n throw new AppError(\n `Invalid --mode value \"${options.mode}\". Expected one of: ${COMPARE_MODES.join(\", \")}.`,\n );\n }\n\n for (const [label, value] of [\n [\"threshold-pass\", options.thresholdPass],\n [\"threshold-tolerated\", options.thresholdTolerated],\n [\"threshold-retry\", options.thresholdRetry],\n ] as const) {\n if (!Number.isFinite(value) || value < 0) {\n throw new AppError(`--${label} must be a non-negative number.`);\n }\n }\n\n return options;\n}\n\nfunction writeCliOutput(\n report: Awaited<ReturnType<typeof runCompare>>[\"report\"],\n options: Pick<CompareCliOptions, \"quiet\" | \"reportStdout\">,\n): void {\n if (options.reportStdout) {\n process.stdout.write(`${JSON.stringify(report)}\\n`);\n return;\n }\n\n if (options.quiet) {\n return;\n }\n\n printSummary(report);\n}\n\nfunction printSummary(report: Awaited<ReturnType<typeof runCompare>>[\"report\"]): void {\n console.log(`recommendation: ${report.summary.recommendation}`);\n console.log(`severity: ${report.summary.severity}`);\n console.log(`reason: ${report.summary.reason}`);\n console.log(`mismatchPercent: ${report.metrics.mismatchPercent.toFixed(4)}%`);\n console.log(`findings: ${report.findings.length}/${report.metrics.findingsCount}`);\n console.log(`output: ${path.dirname(report.artifacts.report)}`);\n}\n\nexport function handleCliError(error: unknown): void {\n if (isAppError(error)) {\n console.error(error.message);\n process.exitCode = error.exitCode;\n return;\n }\n\n if (error instanceof Error) {\n console.error(error.message);\n } else {\n console.error(\"Unknown error\");\n }\n\n process.exitCode = 1;\n}\n","import type { CompareMode, CompareThresholds } from \"../types/report.js\";\n\nexport const DEFAULT_MODE: CompareMode = \"all\";\n\nexport const DEFAULT_THRESHOLDS: CompareThresholds = {\n pass: 0.5,\n tolerated: 1.5,\n retry: 5,\n};\n\nexport const DEFAULT_PIXELMATCH_THRESHOLD = 0.1;\nexport const DEFAULT_EDGE_THRESHOLD = 96;\nexport const DEFAULT_MIN_REGION_PIXELS = 9;\nexport const DEFAULT_CAPTURE_DELAY_MS = 250;\nexport const DEFAULT_VIEWPORT_HEIGHT = 900;\nexport const DEFAULT_NAVIGATION_TIMEOUT_MS = 30_000;\nexport const DEFAULT_RESOURCE_TIMEOUT_MS = 15_000;\nexport const DEFAULT_FONT_READY_TIMEOUT_MS = 5_000;\nexport const DEFAULT_REPORT_FINDINGS_LIMIT = 25;\nexport const DEFAULT_MAX_TEXT_SNIPPET_LENGTH = 80;\nexport const DEFAULT_MAX_SELECTOR_LENGTH = 120;\nexport const DEFAULT_MAX_TAG_ROLLUPS = 10;\nexport const DEFAULT_DOM_OVERLAP_THRESHOLD = 0.3;\nexport const DEFAULT_CLUSTER_PADDING_PX = 8;\nexport const DEFAULT_HOTSPOT_CLUSTER_PADDING_PX = 6;\nexport const DEFAULT_HOTSPOT_LIMIT_PER_FINDING = 5;\nexport const DEFAULT_FIGMA_SOURCE = \"auto\";\nexport const DEFAULT_FIGMA_API_BASE_URL = \"https://api.figma.com\";\nexport const DEFAULT_FIGMA_MCP_DESKTOP_URL = \"http://127.0.0.1:3845/mcp\";\nexport const DEFAULT_FIGMA_MCP_REMOTE_URL = \"https://mcp.figma.com/mcp\";\nexport const DEFAULT_FIGMA_OAUTH_TIMEOUT_MS = 180_000;\nexport const LAYOUT_EDGE_RATIO_THRESHOLD = 0.35;\nexport const COLOR_REGION_DELTA_THRESHOLD = 10;\nexport const STRONG_DIMENSION_DELTA_PX = 40;\nexport const STRONG_DIMENSION_ASPECT_DELTA = 0.1;\nexport const HUMAN_REVIEW_MISMATCH_MULTIPLIER = 3;\nexport const MAX_RGB_DISTANCE = 441.6729559300637;\n","import path from \"node:path\";\nimport { DEFAULT_MODE } from \"../config/defaults.js\";\nimport { buildFindingsAnalysis } from \"../analysis/findings.js\";\nimport { decideRecommendation } from \"../analysis/recommendation.js\";\nimport { materializePreviewImage } from \"../capture/playwright-capture.js\";\nimport { runComparisonEngine } from \"../compare/engine.js\";\nimport { createHeatmapArtifact } from \"../compare/heatmap.js\";\nimport { ensureDirectory, pathExists, writeJsonFile } from \"../io/fs.js\";\nimport { loadNormalizedImage, padImageToCanvas, writeRawRgbaPng } from \"../io/image.js\";\nimport {\n inferPreviewInputSource,\n inferReferenceInputSource,\n parsePreviewInput,\n parseReferenceInput,\n resolveViewportForReport,\n} from \"../io/inputs.js\";\nimport { materializeReferenceImage } from \"../reference/index.js\";\nimport type {\n CompareArtifacts,\n CompletedRun,\n ParsedPreviewInput,\n ParsedReferenceInput,\n PreparedImage,\n PreparedPreviewImage,\n PreparedReferenceImage,\n} from \"../types/internal.js\";\nimport type {\n CompareCommandOptions,\n CompareReport,\n InputSourceReport,\n Recommendation,\n ReferenceInputSourceReport,\n} from \"../types/report.js\";\nimport { AppError, createFailureReport, isAppError } from \"../utils/errors.js\";\n\nexport async function runCompare(options: CompareCommandOptions): Promise<CompletedRun> {\n validateThresholdOrdering(options);\n const outputDir = await ensureDirectory(options.output);\n const artifactPaths = createArtifactPaths(outputDir);\n\n let previewInput: ParsedPreviewInput | null = null;\n let referenceInput: ParsedReferenceInput | null = null;\n let preparedPreview: PreparedPreviewImage | null = null;\n let preparedReference: PreparedReferenceImage | null = null;\n\n try {\n previewInput = await parsePreviewInput(options);\n referenceInput = await parseReferenceInput(options.reference);\n preparedPreview = await materializePreviewImage(\n previewInput,\n artifactPaths.preview,\n options.fullPage,\n );\n preparedReference = await materializeReferenceImage(referenceInput, artifactPaths.reference);\n\n const previewImage = await loadNormalizedImage(preparedPreview.path);\n const referenceImage = await loadNormalizedImage(preparedReference.path);\n const width = Math.max(previewImage.width, referenceImage.width);\n const height = Math.max(previewImage.height, referenceImage.height);\n const paddedPreview = padImageToCanvas(previewImage, width, height);\n const paddedReference = padImageToCanvas(referenceImage, width, height);\n\n const comparison = runComparisonEngine({\n reference: paddedReference.data,\n preview: paddedPreview.data,\n width,\n height,\n referenceOriginal: {\n width: referenceImage.width,\n height: referenceImage.height,\n },\n previewOriginal: {\n width: previewImage.width,\n height: previewImage.height,\n },\n mode: options.mode ?? DEFAULT_MODE,\n });\n const findingsAnalysis = buildFindingsAnalysis({\n analysisMode: preparedPreview.analysisMode,\n rawRegions: comparison.rawRegions,\n domSnapshot: preparedPreview.domSnapshot,\n width,\n height,\n });\n const heatmap = createHeatmapArtifact({\n reference: paddedReference.data,\n preview: paddedPreview.data,\n mismatchMask: comparison.mismatchMask,\n visuals: findingsAnalysis.visuals,\n width,\n height,\n });\n\n await Promise.all([\n writeRawRgbaPng(artifactPaths.overlay, comparison.buffers.overlay, width, height),\n writeRawRgbaPng(artifactPaths.diff, comparison.buffers.diff, width, height),\n writeRawRgbaPng(artifactPaths.heatmap, heatmap, width, height),\n ]);\n\n const metrics = {\n ...comparison.metrics,\n findingsCount: findingsAnalysis.metrics.findingsCount,\n affectedElementCount: findingsAnalysis.metrics.affectedElementCount,\n };\n const decision = decideRecommendation({\n metrics,\n thresholds: {\n pass: options.thresholdPass,\n tolerated: options.thresholdTolerated,\n retry: options.thresholdRetry,\n },\n findings: findingsAnalysis.findings,\n });\n\n const report: CompareReport = {\n analysisMode: preparedPreview.analysisMode,\n summary: decision,\n inputs: {\n preview: {\n input: previewInput.input,\n kind: previewInput.kind,\n resolved: previewInput.resolved,\n selector: previewInput.selector,\n },\n reference: {\n input: referenceInput.input,\n kind: referenceInput.kind,\n resolved: referenceInput.resolved,\n selector: null,\n transport: preparedReference.transport,\n },\n viewport: resolveViewportForReport(previewInput.viewport, {\n width: previewImage.width,\n height: previewImage.height,\n }),\n mode: options.mode,\n fullPage: options.fullPage,\n },\n images: {\n preview: { width: previewImage.width, height: previewImage.height },\n reference: { width: referenceImage.width, height: referenceImage.height },\n canvas: { width, height },\n },\n metrics,\n rollups: findingsAnalysis.rollups,\n findings: findingsAnalysis.findings,\n artifacts: artifactPaths,\n error: null,\n };\n\n await writeJsonFile(artifactPaths.report, report);\n\n return {\n report,\n exitCode: exitCodeForRecommendation(report.summary.recommendation),\n };\n } catch (error) {\n if (isAppError(error)) {\n const report = createFailureReport({\n reason: error.message,\n recommendation: error.recommendation ?? \"needs_human_review\",\n severity: error.severity ?? (error.exitCode === 1 ? \"medium\" : \"high\"),\n preview: toPreviewSourceReport(previewInput, options),\n reference: toReferenceSourceReport(referenceInput, options.reference, preparedReference),\n viewport: previewInput?.viewport ?? null,\n analysisMode: preparedPreview?.analysisMode ?? inferAnalysisMode(previewInput, options),\n mode: options.mode,\n fullPage: options.fullPage,\n images: buildImagesReport(preparedPreview, preparedReference),\n artifacts: {\n ...artifactPaths,\n preview: (await pathExists(artifactPaths.preview)) ? artifactPaths.preview : null,\n reference: (await pathExists(artifactPaths.reference)) ? artifactPaths.reference : null,\n overlay: null,\n diff: null,\n heatmap: null,\n },\n error: {\n code: error.code,\n message: error.message,\n exitCode: error.exitCode,\n },\n });\n\n await writeJsonFile(artifactPaths.report, report);\n\n return {\n report,\n exitCode: error.exitCode,\n };\n }\n\n throw error;\n }\n}\n\nfunction buildImagesReport(\n preparedPreview: PreparedImage | null,\n preparedReference: PreparedImage | null,\n): CompareReport[\"images\"] {\n const preview =\n preparedPreview === null\n ? null\n : {\n width: preparedPreview.width,\n height: preparedPreview.height,\n };\n const reference =\n preparedReference === null\n ? null\n : {\n width: preparedReference.width,\n height: preparedReference.height,\n };\n\n return {\n preview,\n reference,\n canvas:\n preview === null || reference === null\n ? null\n : {\n width: Math.max(preview.width, reference.width),\n height: Math.max(preview.height, reference.height),\n },\n };\n}\n\nfunction inferAnalysisMode(\n previewInput: ParsedPreviewInput | null,\n options: Pick<CompareCommandOptions, \"preview\">,\n): CompareReport[\"analysisMode\"] {\n if (previewInput) {\n return previewInput.kind === \"url\" ? \"dom-elements\" : \"visual-clusters\";\n }\n\n return options.preview.startsWith(\"http://\") || options.preview.startsWith(\"https://\")\n ? \"dom-elements\"\n : \"visual-clusters\";\n}\n\nfunction createArtifactPaths(outputDir: string): CompareArtifacts {\n return {\n preview: path.join(outputDir, \"preview.png\"),\n reference: path.join(outputDir, \"reference.png\"),\n overlay: path.join(outputDir, \"overlay.png\"),\n diff: path.join(outputDir, \"diff.png\"),\n heatmap: path.join(outputDir, \"heatmap.png\"),\n report: path.join(outputDir, \"report.json\"),\n };\n}\n\nfunction toPreviewSourceReport(\n previewInput: ParsedPreviewInput | null,\n options: Pick<CompareCommandOptions, \"preview\" | \"selector\">,\n): InputSourceReport {\n if (!previewInput) {\n return inferPreviewInputSource(options);\n }\n\n return {\n input: previewInput.input,\n kind: previewInput.kind,\n resolved: previewInput.resolved,\n selector: previewInput.selector,\n };\n}\n\nfunction toReferenceSourceReport(\n referenceInput: ParsedReferenceInput | null,\n reference: string,\n preparedReference: PreparedReferenceImage | null,\n): ReferenceInputSourceReport {\n if (preparedReference) {\n const inferred = inferReferenceInputSource(reference);\n\n return {\n input: referenceInput?.input ?? reference,\n kind: referenceInput?.kind ?? inferred.kind,\n resolved: referenceInput?.resolved ?? inferred.resolved,\n selector: null,\n transport: preparedReference.transport,\n };\n }\n\n if (!referenceInput) {\n return inferReferenceInputSource(reference);\n }\n\n return {\n input: referenceInput.input,\n kind: referenceInput.kind,\n resolved: referenceInput.resolved,\n selector: null,\n transport: referenceInput.kind === \"path\" ? \"path\" : null,\n };\n}\n\nfunction validateThresholdOrdering(options: CompareCommandOptions): void {\n if (options.thresholdPass > options.thresholdTolerated) {\n throw new AppError(\"--threshold-pass must be less than or equal to --threshold-tolerated.\");\n }\n\n if (options.thresholdTolerated > options.thresholdRetry) {\n throw new AppError(\"--threshold-tolerated must be less than or equal to --threshold-retry.\");\n }\n}\n\nfunction exitCodeForRecommendation(recommendation: Recommendation): number {\n switch (recommendation) {\n case \"pass\":\n case \"pass_with_tolerated_differences\":\n return 0;\n case \"retry_fix\":\n return 2;\n case \"needs_human_review\":\n return 3;\n default:\n return 1;\n }\n}\n","import type {\n ArtifactReport,\n AnalysisMode,\n CompareReport,\n ErrorReport,\n ImageDimensionsReport,\n MetricsReport,\n Recommendation,\n Severity,\n} from \"../types/report.js\";\n\nexport interface AppErrorOptions {\n exitCode?: number;\n recommendation?: Recommendation | null;\n severity?: Severity | null;\n code?: string;\n cause?: unknown;\n}\n\nexport class AppError extends Error {\n readonly code: string;\n readonly exitCode: number;\n readonly recommendation: Recommendation | null;\n readonly severity: Severity | null;\n\n constructor(message: string, options?: AppErrorOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = \"AppError\";\n this.code = options?.code ?? \"app_error\";\n this.exitCode = options?.exitCode ?? 1;\n this.recommendation = options?.recommendation ?? null;\n this.severity = options?.severity ?? null;\n }\n}\n\nexport function isAppError(error: unknown): error is AppError {\n return error instanceof AppError;\n}\n\nexport function ensureError(error: unknown): Error {\n if (error instanceof Error) {\n return error;\n }\n\n return new Error(typeof error === \"string\" ? error : \"Unknown error\");\n}\n\nexport function createFailureReport(params: {\n reason: string;\n recommendation: Recommendation;\n severity: Severity;\n preview: CompareReport[\"inputs\"][\"preview\"];\n reference: CompareReport[\"inputs\"][\"reference\"];\n viewport: CompareReport[\"inputs\"][\"viewport\"];\n analysisMode: AnalysisMode;\n mode: CompareReport[\"inputs\"][\"mode\"];\n fullPage: boolean;\n images: ImageDimensionsReport;\n artifacts: ArtifactReport;\n error: ErrorReport;\n}): CompareReport {\n const emptyMetrics: MetricsReport = {\n mismatchPixels: 0,\n mismatchPercent: 0,\n meanColorDelta: null,\n maxColorDelta: null,\n structuralMismatchPercent: null,\n dimensionMismatch: {\n widthDelta: 0,\n heightDelta: 0,\n aspectRatioDelta: 0,\n hasMismatch: false,\n },\n findingsCount: 0,\n affectedElementCount: 0,\n };\n\n return {\n analysisMode: params.analysisMode,\n summary: {\n recommendation: params.recommendation,\n severity: params.severity,\n reason: params.reason,\n },\n inputs: {\n preview: params.preview,\n reference: params.reference,\n viewport: params.viewport,\n mode: params.mode,\n fullPage: params.fullPage,\n },\n images: params.images,\n metrics: emptyMetrics,\n rollups: {\n bySeverity: [],\n byKind: [],\n byTag: [],\n rawRegionCount: 0,\n findingsCount: 0,\n affectedElementCount: 0,\n omittedFindings: 0,\n },\n findings: [],\n artifacts: params.artifacts,\n error: params.error,\n };\n}\n","import type { Severity } from \"../types/report.js\";\n\nconst SEVERITY_RANK: Record<Severity, number> = {\n low: 0,\n medium: 1,\n high: 2,\n critical: 3,\n};\n\nexport function maxSeverity(values: Severity[]): Severity {\n if (values.length === 0) {\n return \"low\";\n }\n\n return values.reduce((current, candidate) =>\n SEVERITY_RANK[candidate] > SEVERITY_RANK[current] ? candidate : current,\n );\n}\n\nexport function compareSeverityDescending(left: Severity, right: Severity): number {\n return SEVERITY_RANK[right] - SEVERITY_RANK[left];\n}\n","import {\n DEFAULT_CLUSTER_PADDING_PX,\n DEFAULT_DOM_OVERLAP_THRESHOLD,\n DEFAULT_HOTSPOT_CLUSTER_PADDING_PX,\n DEFAULT_HOTSPOT_LIMIT_PER_FINDING,\n DEFAULT_MAX_TAG_ROLLUPS,\n DEFAULT_REPORT_FINDINGS_LIMIT,\n} from \"../config/defaults.js\";\nimport type {\n ComparisonRegion,\n DomSnapshot,\n DomSnapshotElement,\n CaptureEdge,\n} from \"../types/internal.js\";\nimport type {\n AnalysisMode,\n BoundingBox,\n FindingElementReport,\n FindingReport,\n FindingSignalReport,\n FindingSource,\n IssueType,\n KindRollup,\n RegionKind,\n RollupsReport,\n Severity,\n SeverityRollup,\n TagRollup,\n} from \"../types/report.js\";\nimport { AppError } from \"../utils/errors.js\";\nimport { compareSeverityDescending, maxSeverity } from \"../utils/severity.js\";\n\ninterface DraftFinding {\n source: FindingSource;\n kind: RegionKind;\n severity: Severity;\n summary: string;\n bbox: BoundingBox;\n regionCount: number;\n mismatchPixels: number;\n mismatchPercentOfCanvas: number;\n issueTypes: IssueType[];\n signals: FindingSignalReport[];\n hotspots: BoundingBox[];\n element: FindingElementReport | null;\n}\n\ninterface DraftFindingGroup {\n finding: DraftFinding;\n regions: ComparisonRegion[];\n}\n\nexport interface FindingVisualization {\n severity: Severity;\n primaryBox: BoundingBox;\n hotspotBoxes: BoundingBox[];\n}\n\nconst FINDING_KIND_ORDER: RegionKind[] = [\"dimension\", \"mixed\", \"layout\", \"color\", \"pixel\"];\n\nexport function buildFindingsAnalysis(params: {\n analysisMode: AnalysisMode;\n rawRegions: ComparisonRegion[];\n domSnapshot: DomSnapshot | null;\n width: number;\n height: number;\n}): {\n findings: FindingReport[];\n rollups: RollupsReport;\n metrics: {\n findingsCount: number;\n affectedElementCount: number;\n };\n visuals: FindingVisualization[];\n} {\n const totalPixels = params.width * params.height;\n const draftFindingGroups =\n params.analysisMode === \"dom-elements\"\n ? buildDomFindings(\n params.rawRegions,\n params.domSnapshot,\n params.width,\n params.height,\n totalPixels,\n )\n : buildVisualClusterFindings(params.rawRegions, totalPixels, params.width, params.height);\n const sortedGroups = draftFindingGroups.sort((left, right) =>\n compareDraftFindings(left.finding, right.finding),\n );\n const sortedFindings = sortedGroups.map((group) => group.finding);\n const limitedGroups = sortedGroups.slice(0, DEFAULT_REPORT_FINDINGS_LIMIT);\n const limitedFindings = limitedGroups.map((group) => group.finding);\n const affectedElementCount =\n params.analysisMode === \"dom-elements\"\n ? new Set(\n sortedFindings\n .map((finding) => finding.element?.selector ?? null)\n .filter((selector): selector is string => selector !== null),\n ).size\n : 0;\n\n return {\n findings: limitedFindings.map((finding, index) => ({\n id: `finding-${String(index + 1).padStart(3, \"0\")}`,\n ...finding,\n })),\n rollups: {\n bySeverity: buildSeverityRollups(sortedFindings),\n byKind: buildKindRollups(sortedFindings),\n byTag:\n params.analysisMode === \"dom-elements\"\n ? buildTagRollups(sortedFindings).slice(0, DEFAULT_MAX_TAG_ROLLUPS)\n : [],\n rawRegionCount: params.rawRegions.length,\n findingsCount: sortedFindings.length,\n affectedElementCount,\n omittedFindings: Math.max(0, sortedFindings.length - limitedFindings.length),\n },\n metrics: {\n findingsCount: sortedFindings.length,\n affectedElementCount,\n },\n visuals: sortedGroups.map((group) => {\n const primaryBox = group.finding.element?.bbox ?? group.finding.bbox;\n\n return {\n severity: group.finding.severity,\n primaryBox,\n hotspotBoxes: group.finding.hotspots,\n };\n }),\n };\n}\n\nfunction buildDomFindings(\n rawRegions: ComparisonRegion[],\n domSnapshot: DomSnapshot | null,\n width: number,\n height: number,\n totalPixels: number,\n): DraftFindingGroup[] {\n if (!domSnapshot) {\n throw new AppError(\"Preview URL capture did not produce a DOM snapshot.\", {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"dom_snapshot_missing\",\n });\n }\n\n if (rawRegions.length === 0) {\n return [];\n }\n\n const candidates = buildDomCandidates(domSnapshot, width, height);\n const regionsByElement = new Map<string, ComparisonRegion[]>();\n const elementsById = new Map(candidates.map((element) => [element.id, element]));\n\n for (const region of rawRegions) {\n const element = resolveDomElementForRegion(region, candidates);\n const existing = regionsByElement.get(element.id);\n\n if (existing) {\n existing.push(region);\n } else {\n regionsByElement.set(element.id, [region]);\n }\n }\n\n return Array.from(regionsByElement.entries(), ([elementId, regions]) => {\n const element = elementsById.get(elementId);\n\n if (!element) {\n throw new AppError(`DOM element snapshot missing for finding group ${elementId}.`, {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"dom_snapshot_element_missing\",\n });\n }\n\n return {\n finding: buildDraftFinding({\n source: \"dom-element\",\n regions,\n totalPixels,\n element,\n canvasWidth: width,\n canvasHeight: height,\n }),\n regions,\n };\n });\n}\n\nfunction buildVisualClusterFindings(\n rawRegions: ComparisonRegion[],\n totalPixels: number,\n width: number,\n height: number,\n): DraftFindingGroup[] {\n if (rawRegions.length === 0) {\n return [];\n }\n\n const clusters = clusterRegions(rawRegions);\n return clusters.map((cluster) => ({\n finding: buildDraftFinding({\n source: \"visual-cluster\",\n regions: cluster,\n totalPixels,\n element: null,\n canvasWidth: width,\n canvasHeight: height,\n }),\n regions: cluster,\n }));\n}\n\nfunction buildDraftFinding(params: {\n source: FindingSource;\n regions: ComparisonRegion[];\n totalPixels: number;\n element: DomSnapshotElement | null;\n canvasWidth: number;\n canvasHeight: number;\n}): DraftFinding {\n const bbox = unionRegionBoxes(params.regions);\n const mismatchPixels = params.regions.reduce((sum, region) => sum + region.pixelCount, 0);\n const kind = aggregateKind(params.regions);\n const elementReport = params.element ? toElementReport(params.element) : null;\n const primaryBox = elementReport?.bbox ?? bbox;\n\n return {\n source: params.source,\n kind,\n severity: maxSeverity(params.regions.map((region) => region.severity)),\n summary: buildFindingSummary(kind, elementReport?.tag ?? null),\n bbox,\n regionCount: params.regions.length,\n mismatchPixels,\n mismatchPercentOfCanvas:\n params.totalPixels === 0\n ? 0\n : Number(((mismatchPixels / params.totalPixels) * 100).toFixed(4)),\n issueTypes: issueTypesForKind(kind),\n signals: buildFindingSignals({\n kind,\n bbox,\n element: params.element,\n canvasWidth: params.canvasWidth,\n canvasHeight: params.canvasHeight,\n }),\n hotspots: buildHotspotBoxes(params.regions, primaryBox),\n element: elementReport,\n };\n}\n\nfunction buildDomCandidates(\n domSnapshot: DomSnapshot,\n width: number,\n height: number,\n): DomSnapshotElement[] {\n const root: DomSnapshotElement = {\n ...domSnapshot.root,\n bbox: {\n x: 0,\n y: 0,\n width,\n height,\n },\n };\n\n return [root, ...domSnapshot.elements];\n}\n\nfunction resolveDomElementForRegion(\n region: ComparisonRegion,\n candidates: DomSnapshotElement[],\n): DomSnapshotElement {\n const centerX = region.x + region.width / 2;\n const centerY = region.y + region.height / 2;\n const containing = candidates.filter((candidate) =>\n containsPoint(candidate.bbox, centerX, centerY),\n );\n\n if (containing.length > 0) {\n return containing.sort(compareDomCandidates)[0];\n }\n\n const regionBox = {\n x: region.x,\n y: region.y,\n width: region.width,\n height: region.height,\n };\n let bestCandidate: DomSnapshotElement | null = null;\n let bestOverlap = 0;\n\n for (const candidate of candidates) {\n const overlap = overlapRatio(regionBox, candidate.bbox);\n\n if (overlap > bestOverlap) {\n bestCandidate = candidate;\n bestOverlap = overlap;\n continue;\n }\n\n if (\n overlap === bestOverlap &&\n bestCandidate &&\n compareDomCandidates(candidate, bestCandidate) < 0\n ) {\n bestCandidate = candidate;\n }\n }\n\n if (bestCandidate && bestOverlap >= DEFAULT_DOM_OVERLAP_THRESHOLD) {\n return bestCandidate;\n }\n\n throw new AppError(\n `Could not assign mismatch region at (${region.x}, ${region.y}, ${region.width}x${region.height}) to a DOM element.`,\n {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"dom_region_assignment_failed\",\n },\n );\n}\n\nfunction compareDomCandidates(left: DomSnapshotElement, right: DomSnapshotElement): number {\n if (left.depth !== right.depth) {\n return right.depth - left.depth;\n }\n\n const leftArea = left.bbox.width * left.bbox.height;\n const rightArea = right.bbox.width * right.bbox.height;\n\n if (leftArea !== rightArea) {\n return leftArea - rightArea;\n }\n\n return left.selector.localeCompare(right.selector);\n}\n\nfunction clusterRegions(\n rawRegions: ComparisonRegion[],\n padding = DEFAULT_CLUSTER_PADDING_PX,\n): ComparisonRegion[][] {\n const visited = new Uint8Array(rawRegions.length);\n const clusters: ComparisonRegion[][] = [];\n\n for (let index = 0; index < rawRegions.length; index += 1) {\n if (visited[index] === 1) {\n continue;\n }\n\n visited[index] = 1;\n const queue = [index];\n const cluster: ComparisonRegion[] = [];\n\n while (queue.length > 0) {\n const currentIndex = queue.shift();\n\n if (currentIndex === undefined) {\n break;\n }\n\n const currentRegion = rawRegions[currentIndex];\n cluster.push(currentRegion);\n\n for (let candidateIndex = 0; candidateIndex < rawRegions.length; candidateIndex += 1) {\n if (visited[candidateIndex] === 1) {\n continue;\n }\n\n if (expandedBoxesIntersect(currentRegion, rawRegions[candidateIndex], padding)) {\n visited[candidateIndex] = 1;\n queue.push(candidateIndex);\n }\n }\n }\n\n clusters.push(cluster);\n }\n\n return clusters;\n}\n\nfunction expandedBoxesIntersect(left: BoundingBox, right: BoundingBox, padding: number): boolean {\n return boxesIntersect(expandBox(left, padding), expandBox(right, padding));\n}\n\nfunction expandBox(box: BoundingBox, padding: number): BoundingBox {\n return {\n x: box.x - padding,\n y: box.y - padding,\n width: box.width + padding * 2,\n height: box.height + padding * 2,\n };\n}\n\nfunction boxesIntersect(left: BoundingBox, right: BoundingBox): boolean {\n return !(\n left.x + left.width < right.x ||\n right.x + right.width < left.x ||\n left.y + left.height < right.y ||\n right.y + right.height < left.y\n );\n}\n\nfunction containsPoint(box: BoundingBox, x: number, y: number): boolean {\n return x >= box.x && x <= box.x + box.width && y >= box.y && y <= box.y + box.height;\n}\n\nfunction overlapRatio(left: BoundingBox, right: BoundingBox): number {\n const intersectionWidth =\n Math.min(left.x + left.width, right.x + right.width) - Math.max(left.x, right.x);\n const intersectionHeight =\n Math.min(left.y + left.height, right.y + right.height) - Math.max(left.y, right.y);\n\n if (intersectionWidth <= 0 || intersectionHeight <= 0) {\n return 0;\n }\n\n const regionArea = Math.max(1, left.width * left.height);\n return (intersectionWidth * intersectionHeight) / regionArea;\n}\n\nfunction unionRegionBoxes(regions: ComparisonRegion[]): BoundingBox {\n const minX = Math.min(...regions.map((region) => region.x));\n const minY = Math.min(...regions.map((region) => region.y));\n const maxX = Math.max(...regions.map((region) => region.x + region.width));\n const maxY = Math.max(...regions.map((region) => region.y + region.height));\n\n return {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n}\n\nfunction buildHotspotBoxes(regions: ComparisonRegion[], primaryBox: BoundingBox): BoundingBox[] {\n if (regions.length <= 1) {\n return [];\n }\n\n return clusterRegions(regions, DEFAULT_HOTSPOT_CLUSTER_PADDING_PX)\n .map((cluster) => ({\n bbox: unionRegionBoxes(cluster),\n mismatchPixels: cluster.reduce((sum, region) => sum + region.pixelCount, 0),\n }))\n .filter(({ bbox }) => !isNearlySameBox(bbox, primaryBox))\n .sort((left, right) => {\n if (left.mismatchPixels !== right.mismatchPixels) {\n return right.mismatchPixels - left.mismatchPixels;\n }\n\n if (left.bbox.y !== right.bbox.y) {\n return left.bbox.y - right.bbox.y;\n }\n\n return left.bbox.x - right.bbox.x;\n })\n .slice(0, DEFAULT_HOTSPOT_LIMIT_PER_FINDING)\n .map(({ bbox }) => bbox);\n}\n\nfunction isNearlySameBox(left: BoundingBox, right: BoundingBox): boolean {\n const leftArea = Math.max(1, left.width * left.height);\n const rightArea = Math.max(1, right.width * right.height);\n const areaRatio = Math.min(leftArea, rightArea) / Math.max(leftArea, rightArea);\n\n return areaRatio >= 0.9 && overlapRatio(left, right) >= 0.9;\n}\n\nfunction aggregateKind(regions: ComparisonRegion[]): RegionKind {\n const kinds = new Set(regions.map((region) => region.kind));\n\n if (kinds.has(\"dimension\")) {\n return \"dimension\";\n }\n\n if (kinds.has(\"mixed\")) {\n return \"mixed\";\n }\n\n if (kinds.has(\"layout\") && (kinds.has(\"color\") || kinds.has(\"pixel\"))) {\n return \"mixed\";\n }\n\n if (kinds.has(\"layout\")) {\n return \"layout\";\n }\n\n if (kinds.has(\"color\")) {\n return \"color\";\n }\n\n return \"pixel\";\n}\n\nfunction buildFindingSummary(kind: RegionKind, tag: string | null): string {\n const subject = tag ? `Element <${tag}>` : \"Visual cluster\";\n\n switch (kind) {\n case \"dimension\":\n return `${subject} is missing content, has extra content, or was captured at the wrong canvas size.`;\n case \"layout\":\n return `${subject} differs in position, spacing, or alignment.`;\n case \"color\":\n return `${subject} differs in color or visual styling.`;\n case \"mixed\":\n return `${subject} differs in both layout and styling.`;\n case \"pixel\":\n default:\n return `${subject} differs in rendering or fine-grained styling.`;\n }\n}\n\nfunction issueTypesForKind(kind: RegionKind): IssueType[] {\n switch (kind) {\n case \"dimension\":\n return [\"missing_or_extra\", \"size\"];\n case \"layout\":\n return [\"position\", \"spacing\"];\n case \"color\":\n return [\"color\", \"style\"];\n case \"mixed\":\n return [\"position\", \"spacing\", \"style\"];\n case \"pixel\":\n default:\n return [\"style\"];\n }\n}\n\nfunction buildFindingSignals(params: {\n kind: RegionKind;\n bbox: BoundingBox;\n element: DomSnapshotElement | null;\n canvasWidth: number;\n canvasHeight: number;\n}): FindingSignalReport[] {\n const signals: FindingSignalReport[] = [];\n const textClippingSignal = buildTextClippingSignal(params.element);\n\n if (textClippingSignal) {\n signals.push(textClippingSignal);\n }\n\n const captureCropSignal = buildCaptureCropSignal(params.element);\n\n if (captureCropSignal) {\n signals.push(captureCropSignal);\n } else {\n const viewportSignal = buildViewportMismatchSignal(\n params.kind,\n params.bbox,\n params.canvasWidth,\n params.canvasHeight,\n );\n\n if (viewportSignal) {\n signals.push(viewportSignal);\n }\n }\n\n return signals;\n}\n\nfunction buildTextClippingSignal(element: DomSnapshotElement | null): FindingSignalReport | null {\n if (!element?.textSnippet || !element.textMetrics) {\n return null;\n }\n\n const { textMetrics } = element;\n const hasOverflowX = textMetrics.scrollWidth > textMetrics.clientWidth + 1;\n const hasOverflowY = textMetrics.scrollHeight > textMetrics.clientHeight + 1;\n const clipsX =\n hasOverflowX &&\n (textMetrics.overflowX === \"hidden\" ||\n textMetrics.overflowX === \"clip\" ||\n textMetrics.textOverflow === \"ellipsis\");\n const lineClampActive =\n textMetrics.lineClamp !== null &&\n textMetrics.lineClamp !== \"\" &&\n textMetrics.lineClamp !== \"none\" &&\n textMetrics.lineClamp !== \"0\" &&\n textMetrics.lineClamp !== \"normal\";\n const clipsY =\n hasOverflowY &&\n (textMetrics.overflowY === \"hidden\" || textMetrics.overflowY === \"clip\" || lineClampActive);\n\n if (!clipsX && !clipsY) {\n return null;\n }\n\n const axis =\n clipsX && clipsY\n ? \"horizontal and vertical axes\"\n : clipsX\n ? \"horizontal axis\"\n : \"vertical axis\";\n\n return {\n code: \"probable_text_clipping\",\n confidence: lineClampActive || (clipsX && clipsY) ? \"high\" : \"medium\",\n message: `Text content likely overflows the element bounds and is being clipped on the ${axis}.`,\n };\n}\n\nfunction buildCaptureCropSignal(element: DomSnapshotElement | null): FindingSignalReport | null {\n if (!element || element.captureClippedEdges.length === 0) {\n return null;\n }\n\n return {\n code: \"possible_capture_crop\",\n confidence: \"high\",\n message: `Element bounds were clipped by the preview capture on the ${formatEdgeList(element.captureClippedEdges)} edge(s); check selector scope and capture framing.`,\n };\n}\n\nfunction buildViewportMismatchSignal(\n kind: RegionKind,\n bbox: BoundingBox,\n canvasWidth: number,\n canvasHeight: number,\n): FindingSignalReport | null {\n if (kind !== \"dimension\") {\n return null;\n }\n\n const touchingEdges = boxEdgesAgainstCanvas(bbox, canvasWidth, canvasHeight);\n\n if (touchingEdges.length === 0) {\n return null;\n }\n\n return {\n code: \"possible_viewport_mismatch\",\n confidence: \"medium\",\n message: `Dimension mismatch reaches the ${formatEdgeList(touchingEdges)} edge(s) of the comparison canvas; verify viewport, selected frame, and capture target.`,\n };\n}\n\nfunction boxEdgesAgainstCanvas(\n box: BoundingBox,\n canvasWidth: number,\n canvasHeight: number,\n): CaptureEdge[] {\n const edges: CaptureEdge[] = [];\n\n if (box.y <= 0) {\n edges.push(\"top\");\n }\n\n if (box.x + box.width >= canvasWidth) {\n edges.push(\"right\");\n }\n\n if (box.y + box.height >= canvasHeight) {\n edges.push(\"bottom\");\n }\n\n if (box.x <= 0) {\n edges.push(\"left\");\n }\n\n return edges;\n}\n\nfunction formatEdgeList(edges: CaptureEdge[]): string {\n if (edges.length === 1) {\n return edges[0];\n }\n\n if (edges.length === 2) {\n return `${edges[0]} and ${edges[1]}`;\n }\n\n return `${edges.slice(0, -1).join(\", \")}, and ${edges[edges.length - 1]}`;\n}\n\nfunction toElementReport(element: DomSnapshotElement): FindingElementReport {\n return {\n tag: element.tag,\n selector: element.selector,\n role: element.role,\n textSnippet: element.textSnippet,\n bbox: element.bbox,\n };\n}\n\nfunction buildSeverityRollups(findings: DraftFinding[]): SeverityRollup[] {\n const severityCounts = new Map<Severity, number>();\n\n for (const finding of findings) {\n severityCounts.set(finding.severity, (severityCounts.get(finding.severity) ?? 0) + 1);\n }\n\n return Array.from(severityCounts.entries())\n .map(([severity, count]) => ({ severity, count }))\n .sort((left, right) => compareSeverityDescending(left.severity, right.severity));\n}\n\nfunction buildKindRollups(findings: DraftFinding[]): KindRollup[] {\n const kindCounts = new Map<RegionKind, number>();\n\n for (const finding of findings) {\n kindCounts.set(finding.kind, (kindCounts.get(finding.kind) ?? 0) + 1);\n }\n\n return Array.from(kindCounts.entries())\n .map(([kind, count]) => ({ kind, count }))\n .sort(\n (left, right) =>\n FINDING_KIND_ORDER.indexOf(left.kind) - FINDING_KIND_ORDER.indexOf(right.kind),\n );\n}\n\nfunction buildTagRollups(findings: DraftFinding[]): TagRollup[] {\n const tagCounts = new Map<string, number>();\n\n for (const finding of findings) {\n const tag = finding.element?.tag;\n\n if (!tag) {\n continue;\n }\n\n tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);\n }\n\n return Array.from(tagCounts.entries())\n .map(([tag, count]) => ({ tag, count }))\n .sort((left, right) => {\n if (left.count !== right.count) {\n return right.count - left.count;\n }\n\n return left.tag.localeCompare(right.tag);\n });\n}\n\nfunction compareDraftFindings(left: DraftFinding, right: DraftFinding): number {\n const severityOrder = compareSeverityDescending(left.severity, right.severity);\n\n if (severityOrder !== 0) {\n return severityOrder;\n }\n\n if (left.mismatchPixels !== right.mismatchPixels) {\n return right.mismatchPixels - left.mismatchPixels;\n }\n\n if (left.bbox.y !== right.bbox.y) {\n return left.bbox.y - right.bbox.y;\n }\n\n if (left.bbox.x !== right.bbox.x) {\n return left.bbox.x - right.bbox.x;\n }\n\n return left.summary.localeCompare(right.summary);\n}\n","import {\n HUMAN_REVIEW_MISMATCH_MULTIPLIER,\n STRONG_DIMENSION_ASPECT_DELTA,\n STRONG_DIMENSION_DELTA_PX,\n} from \"../config/defaults.js\";\nimport type { RecommendationDecision } from \"../types/internal.js\";\nimport type { FindingReport, MetricsReport } from \"../types/report.js\";\nimport { maxSeverity } from \"../utils/severity.js\";\n\nexport function decideRecommendation(params: {\n metrics: MetricsReport;\n thresholds: { pass: number; tolerated: number; retry: number };\n findings: FindingReport[];\n}): RecommendationDecision {\n const { metrics, thresholds, findings } = params;\n const highestFindingSeverity = maxSeverity(findings.map((finding) => finding.severity));\n const strongDimensionMismatch = hasStrongDimensionMismatch(metrics);\n\n if (\n strongDimensionMismatch ||\n metrics.mismatchPercent > thresholds.retry * HUMAN_REVIEW_MISMATCH_MULTIPLIER\n ) {\n return {\n recommendation: \"needs_human_review\",\n severity: maxSeverity([\n highestFindingSeverity,\n strongDimensionMismatch ? \"critical\" : \"high\",\n ]),\n reason: strongDimensionMismatch\n ? \"Reference and preview dimensions diverge too much for a reliable automated verdict.\"\n : `Mismatch percentage ${metrics.mismatchPercent.toFixed(2)}% is too large for an automated fix recommendation.`,\n };\n }\n\n if (metrics.mismatchPercent <= thresholds.pass && highestFindingSeverity === \"low\") {\n return {\n recommendation: \"pass\",\n severity: \"low\",\n reason: `Mismatch is ${metrics.mismatchPercent.toFixed(2)}%, within the strict pass threshold.`,\n };\n }\n\n if (metrics.mismatchPercent <= thresholds.tolerated && highestFindingSeverity === \"low\") {\n return {\n recommendation: \"pass_with_tolerated_differences\",\n severity: \"low\",\n reason: `Mismatch is ${metrics.mismatchPercent.toFixed(2)}%, within the tolerated threshold.`,\n };\n }\n\n if (\n metrics.mismatchPercent <= thresholds.retry ||\n highestFindingSeverity === \"medium\" ||\n highestFindingSeverity === \"high\"\n ) {\n return {\n recommendation: \"retry_fix\",\n severity: highestFindingSeverity === \"critical\" ? \"high\" : highestFindingSeverity,\n reason: `Mismatch is ${metrics.mismatchPercent.toFixed(2)}%; localized issues were detected and should be fixed before retrying.`,\n };\n }\n\n return {\n recommendation: \"needs_human_review\",\n severity: maxSeverity([highestFindingSeverity, \"high\"]),\n reason: `Mismatch is ${metrics.mismatchPercent.toFixed(2)}% and exceeds the retry threshold.`,\n };\n}\n\nfunction hasStrongDimensionMismatch(metrics: MetricsReport): boolean {\n return (\n metrics.dimensionMismatch.hasMismatch &&\n (Math.abs(metrics.dimensionMismatch.widthDelta) >= STRONG_DIMENSION_DELTA_PX ||\n Math.abs(metrics.dimensionMismatch.heightDelta) >= STRONG_DIMENSION_DELTA_PX ||\n metrics.dimensionMismatch.aspectRatioDelta >= STRONG_DIMENSION_ASPECT_DELTA)\n );\n}\n","import { unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { chromium, type Locator, type Page } from \"playwright\";\nimport {\n DEFAULT_CAPTURE_DELAY_MS,\n DEFAULT_FONT_READY_TIMEOUT_MS,\n DEFAULT_MAX_SELECTOR_LENGTH,\n DEFAULT_MAX_TEXT_SNIPPET_LENGTH,\n DEFAULT_NAVIGATION_TIMEOUT_MS,\n} from \"../config/defaults.js\";\nimport type { DomSnapshot, ParsedPreviewInput, PreparedPreviewImage } from \"../types/internal.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\nimport { normalizeImageToPng } from \"../io/image.js\";\n\nexport async function materializePreviewImage(\n preview: ParsedPreviewInput,\n outputPath: string,\n fullPage: boolean,\n): Promise<PreparedPreviewImage> {\n if (preview.kind === \"path\") {\n try {\n const normalized = await normalizeImageToPng(preview.resolved, outputPath);\n return {\n ...normalized,\n analysisMode: \"visual-clusters\",\n domSnapshot: null,\n };\n } catch (error) {\n throw new AppError(\n `Failed to normalize preview image: ${preview.resolved}. ${ensureError(error).message}`,\n {\n code: \"preview_image_normalization_failed\",\n cause: error,\n },\n );\n }\n }\n\n const temporaryCapturePath = buildTemporaryCapturePath(outputPath);\n const browser = await chromium.launch({ headless: true });\n let domSnapshot: DomSnapshot | null;\n\n try {\n const page = await browser.newPage({\n viewport: preview.viewport,\n deviceScaleFactor: 1,\n });\n\n await navigateForCapture(page, preview.resolved);\n await waitForCaptureStability(page);\n\n if (preview.selector !== null) {\n domSnapshot = await captureSelectorScreenshot(page, preview.selector, temporaryCapturePath);\n } else {\n domSnapshot = await collectPageDomSnapshot(page, fullPage);\n await page.screenshot({\n path: temporaryCapturePath,\n animations: \"disabled\",\n caret: \"hide\",\n fullPage,\n scale: \"css\",\n type: \"png\",\n });\n }\n } finally {\n await browser.close();\n }\n\n try {\n const normalized = await normalizeImageToPng(temporaryCapturePath, outputPath);\n return {\n ...normalized,\n analysisMode: \"dom-elements\",\n domSnapshot,\n };\n } catch (error) {\n throw new AppError(\n `Failed to normalize captured preview image: ${temporaryCapturePath}. ${ensureError(error).message}`,\n {\n code: \"preview_capture_normalization_failed\",\n cause: error,\n },\n );\n } finally {\n await unlink(temporaryCapturePath).catch(() => undefined);\n }\n}\n\nasync function navigateForCapture(page: Page, url: string): Promise<void> {\n try {\n await page.goto(url, {\n waitUntil: \"networkidle\",\n timeout: DEFAULT_NAVIGATION_TIMEOUT_MS,\n });\n } catch {\n await page.goto(url, {\n waitUntil: \"load\",\n timeout: DEFAULT_NAVIGATION_TIMEOUT_MS,\n });\n }\n}\n\nasync function waitForCaptureStability(page: Page): Promise<void> {\n await page\n .evaluate(\n async ({ fontTimeoutMs }) => {\n const fonts = document.fonts;\n\n if (!fonts) {\n return;\n }\n\n await Promise.race([\n fonts.ready,\n new Promise((resolve) => {\n window.setTimeout(resolve, fontTimeoutMs);\n }),\n ]);\n },\n { fontTimeoutMs: DEFAULT_FONT_READY_TIMEOUT_MS },\n )\n .catch(() => undefined);\n\n await page.waitForTimeout(DEFAULT_CAPTURE_DELAY_MS);\n}\n\nasync function captureSelectorScreenshot(\n page: Page,\n selector: string,\n outputPath: string,\n): Promise<DomSnapshot> {\n try {\n const locator = page.locator(selector).first();\n await locator.waitFor({ state: \"visible\", timeout: DEFAULT_NAVIGATION_TIMEOUT_MS });\n await locator.scrollIntoViewIfNeeded();\n const domSnapshot = await collectSelectorDomSnapshot(locator);\n await locator.screenshot({\n path: outputPath,\n animations: \"disabled\",\n caret: \"hide\",\n scale: \"css\",\n type: \"png\",\n });\n return domSnapshot;\n } catch (error) {\n throw new AppError(\n `Preview selector could not be captured: ${selector}. ${ensureError(error).message}`,\n {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"preview_selector_capture_failed\",\n cause: error,\n },\n );\n }\n}\n\nfunction buildTemporaryCapturePath(outputPath: string): string {\n const parsedPath = path.parse(outputPath);\n return path.join(\n parsedPath.dir,\n `${parsedPath.name}.capture-${process.pid}-${Date.now()}${parsedPath.ext || \".png\"}`,\n );\n}\n\nasync function collectSelectorDomSnapshot(locator: Locator): Promise<DomSnapshot> {\n return locator.evaluate(\n (root, { maxSelectorLength, maxTextLength }) => {\n const excludedTags = new Set([\"script\", \"style\", \"noscript\", \"meta\", \"link\", \"head\"]);\n const inlineNoiseTags = new Set([\"span\", \"strong\", \"em\", \"b\", \"i\", \"u\", \"small\"]);\n const semanticTags = new Set([\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"p\",\n \"button\",\n \"a\",\n \"img\",\n \"svg\",\n \"video\",\n \"canvas\",\n \"input\",\n \"textarea\",\n \"select\",\n \"label\",\n \"li\",\n \"section\",\n \"article\",\n \"nav\",\n \"main\",\n \"aside\",\n \"header\",\n \"footer\",\n ]);\n const rootRect = root.getBoundingClientRect();\n const captureBounds = {\n x: 0,\n y: 0,\n width: Math.max(1, Math.round(rootRect.width)),\n height: Math.max(1, Math.round(rootRect.height)),\n };\n\n const normalizeWhitespace = (value: string): string => value.replace(/\\s+/g, \" \").trim();\n const clipValue = (value: string, limit: number): string =>\n value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1))}\\u2026`;\n const toTag = (element: Element): string => element.tagName.toLowerCase();\n const isTransparent = (value: string): boolean =>\n value === \"transparent\" || value === \"rgba(0, 0, 0, 0)\" || value === \"rgba(0,0,0,0)\";\n const hasVisibleBorder = (style: CSSStyleDeclaration): boolean =>\n Number.parseFloat(style.borderTopWidth) > 0 ||\n Number.parseFloat(style.borderRightWidth) > 0 ||\n Number.parseFloat(style.borderBottomWidth) > 0 ||\n Number.parseFloat(style.borderLeftWidth) > 0;\n const hasPaintedBox = (style: CSSStyleDeclaration): boolean =>\n style.backgroundImage !== \"none\" ||\n !isTransparent(style.backgroundColor) ||\n hasVisibleBorder(style) ||\n style.boxShadow !== \"none\";\n const escapeIdentifier = (value: string): string =>\n typeof CSS !== \"undefined\" && typeof CSS.escape === \"function\" ? CSS.escape(value) : value;\n const directTextSnippet = (element: Element): string => {\n const text =\n element instanceof HTMLElement\n ? element.innerText || element.textContent || \"\"\n : element.textContent || \"\";\n return clipValue(normalizeWhitespace(text), maxTextLength);\n };\n const depthFromRoot = (element: Element): number => {\n let depth = 0;\n let current: Element | null = element;\n\n while (current && current !== root) {\n depth += 1;\n current = current.parentElement;\n }\n\n return depth;\n };\n const nthOfType = (element: Element): number => {\n let index = 1;\n let sibling = element.previousElementSibling;\n\n while (sibling) {\n if (sibling.tagName === element.tagName) {\n index += 1;\n }\n\n sibling = sibling.previousElementSibling;\n }\n\n return index;\n };\n const segmentFor = (element: Element): string => {\n const tag = toTag(element);\n\n if (element.id) {\n return `${tag}#${escapeIdentifier(element.id)}`;\n }\n\n const classNames = Array.from(element.classList)\n .filter((className) => /^[A-Za-z_][\\w-]*$/u.test(className))\n .slice(0, 2);\n\n if (classNames.length > 0) {\n return `${tag}.${classNames.map((className) => escapeIdentifier(className)).join(\".\")}`;\n }\n\n return `${tag}:nth-of-type(${nthOfType(element)})`;\n };\n const buildSelector = (element: Element): string => {\n if (element === root) {\n return clipValue(segmentFor(element), maxSelectorLength);\n }\n\n const parts: string[] = [];\n let current: Element | null = element;\n\n while (current && parts.length < 3) {\n parts.unshift(segmentFor(current));\n\n if (current === root) {\n break;\n }\n\n current = current.parentElement;\n }\n\n return clipValue(parts.join(\" > \"), maxSelectorLength);\n };\n const clipBoxToBounds = (\n box: { x: number; y: number; width: number; height: number },\n bounds: { x: number; y: number; width: number; height: number },\n ) => {\n const left = Math.max(bounds.x, box.x);\n const top = Math.max(bounds.y, box.y);\n const right = Math.min(bounds.x + bounds.width, box.x + box.width);\n const bottom = Math.min(bounds.y + bounds.height, box.y + box.height);\n\n if (right <= left || bottom <= top) {\n return null;\n }\n\n return {\n x: Math.round(left),\n y: Math.round(top),\n width: Math.round(right - left),\n height: Math.round(bottom - top),\n };\n };\n const clippedEdgesForBox = (\n box: { x: number; y: number; width: number; height: number },\n bounds: { x: number; y: number; width: number; height: number },\n ): Array<\"top\" | \"right\" | \"bottom\" | \"left\"> => {\n const edges: Array<\"top\" | \"right\" | \"bottom\" | \"left\"> = [];\n\n if (box.y < bounds.y) {\n edges.push(\"top\");\n }\n\n if (box.x + box.width > bounds.x + bounds.width) {\n edges.push(\"right\");\n }\n\n if (box.y + box.height > bounds.y + bounds.height) {\n edges.push(\"bottom\");\n }\n\n if (box.x < bounds.x) {\n edges.push(\"left\");\n }\n\n return edges;\n };\n const toRelativeBox = (element: Element) => {\n const rect = element.getBoundingClientRect();\n const rawBox = {\n x: rect.left - rootRect.left,\n y: rect.top - rootRect.top,\n width: rect.width,\n height: rect.height,\n };\n const bbox = clipBoxToBounds(rawBox, captureBounds);\n\n if (!bbox) {\n return null;\n }\n\n return {\n bbox,\n captureClippedEdges: clippedEdgesForBox(rawBox, captureBounds),\n };\n };\n const isVisible = (element: Element): boolean => {\n const rect = element.getBoundingClientRect();\n\n if (rect.width <= 0 || rect.height <= 0) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n return (\n style.display !== \"none\" &&\n style.visibility !== \"hidden\" &&\n style.opacity !== \"0\" &&\n style.pointerEvents !== \"none\"\n );\n };\n const isMeaningful = (element: Element): boolean => {\n if (element === root) {\n return true;\n }\n\n const tag = toTag(element);\n\n if (excludedTags.has(tag) || inlineNoiseTags.has(tag)) {\n return false;\n }\n\n if (!isVisible(element)) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n const hasText = directTextSnippet(element).length > 0;\n const hasRole = Boolean(element.getAttribute(\"role\"));\n\n return (\n hasText ||\n hasRole ||\n semanticTags.has(tag) ||\n hasPaintedBox(style) ||\n element.children.length === 0\n );\n };\n const buildSnapshotElement = (element: Element) => {\n const boxInfo = toRelativeBox(element);\n\n if (!boxInfo) {\n return null;\n }\n\n const style = window.getComputedStyle(element);\n const textMetrics =\n element instanceof HTMLElement\n ? {\n clientWidth: Math.round(element.clientWidth),\n clientHeight: Math.round(element.clientHeight),\n scrollWidth: Math.round(element.scrollWidth),\n scrollHeight: Math.round(element.scrollHeight),\n overflowX: style.overflowX,\n overflowY: style.overflowY,\n textOverflow: style.textOverflow,\n whiteSpace: style.whiteSpace,\n lineClamp:\n style.getPropertyValue(\"-webkit-line-clamp\") ||\n style.getPropertyValue(\"line-clamp\") ||\n null,\n }\n : null;\n\n return {\n id: buildSelector(element),\n tag: toTag(element),\n selector: buildSelector(element),\n role: element.getAttribute(\"role\"),\n textSnippet: directTextSnippet(element) || null,\n bbox: boxInfo.bbox,\n depth: depthFromRoot(element),\n captureClippedEdges: boxInfo.captureClippedEdges,\n textMetrics,\n };\n };\n const allElements = [root, ...Array.from(root.querySelectorAll(\"*\"))]\n .filter((element) => isMeaningful(element))\n .map((element) => buildSnapshotElement(element))\n .filter((element): element is NonNullable<typeof element> => element !== null);\n const [snapshotRoot, ...elements] = allElements;\n\n if (!snapshotRoot) {\n throw new Error(\"No meaningful DOM elements were found inside the selector capture.\");\n }\n\n return {\n root: snapshotRoot,\n elements,\n };\n },\n {\n maxSelectorLength: DEFAULT_MAX_SELECTOR_LENGTH,\n maxTextLength: DEFAULT_MAX_TEXT_SNIPPET_LENGTH,\n },\n );\n}\n\nasync function collectPageDomSnapshot(page: Page, fullPage: boolean): Promise<DomSnapshot> {\n return page.evaluate(\n ({ fullPageCapture, maxSelectorLength, maxTextLength }) => {\n const excludedTags = new Set([\"script\", \"style\", \"noscript\", \"meta\", \"link\", \"head\"]);\n const inlineNoiseTags = new Set([\"span\", \"strong\", \"em\", \"b\", \"i\", \"u\", \"small\"]);\n const semanticTags = new Set([\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"p\",\n \"button\",\n \"a\",\n \"img\",\n \"svg\",\n \"video\",\n \"canvas\",\n \"input\",\n \"textarea\",\n \"select\",\n \"label\",\n \"li\",\n \"section\",\n \"article\",\n \"nav\",\n \"main\",\n \"aside\",\n \"header\",\n \"footer\",\n ]);\n const root = document.body ?? document.documentElement;\n const captureBounds = fullPageCapture\n ? {\n x: 0,\n y: 0,\n width: Math.max(\n document.documentElement.scrollWidth,\n document.body?.scrollWidth ?? 0,\n window.innerWidth,\n ),\n height: Math.max(\n document.documentElement.scrollHeight,\n document.body?.scrollHeight ?? 0,\n window.innerHeight,\n ),\n }\n : {\n x: 0,\n y: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n\n const normalizeWhitespace = (value: string): string => value.replace(/\\s+/g, \" \").trim();\n const clipValue = (value: string, limit: number): string =>\n value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1))}\\u2026`;\n const toTag = (element: Element): string => element.tagName.toLowerCase();\n const isTransparent = (value: string): boolean =>\n value === \"transparent\" || value === \"rgba(0, 0, 0, 0)\" || value === \"rgba(0,0,0,0)\";\n const hasVisibleBorder = (style: CSSStyleDeclaration): boolean =>\n Number.parseFloat(style.borderTopWidth) > 0 ||\n Number.parseFloat(style.borderRightWidth) > 0 ||\n Number.parseFloat(style.borderBottomWidth) > 0 ||\n Number.parseFloat(style.borderLeftWidth) > 0;\n const hasPaintedBox = (style: CSSStyleDeclaration): boolean =>\n style.backgroundImage !== \"none\" ||\n !isTransparent(style.backgroundColor) ||\n hasVisibleBorder(style) ||\n style.boxShadow !== \"none\";\n const escapeIdentifier = (value: string): string =>\n typeof CSS !== \"undefined\" && typeof CSS.escape === \"function\" ? CSS.escape(value) : value;\n const directTextSnippet = (element: Element): string => {\n const text =\n element instanceof HTMLElement\n ? element.innerText || element.textContent || \"\"\n : element.textContent || \"\";\n return clipValue(normalizeWhitespace(text), maxTextLength);\n };\n const depthFromRoot = (element: Element): number => {\n let depth = 0;\n let current: Element | null = element;\n\n while (current && current !== root) {\n depth += 1;\n current = current.parentElement;\n }\n\n return depth;\n };\n const nthOfType = (element: Element): number => {\n let index = 1;\n let sibling = element.previousElementSibling;\n\n while (sibling) {\n if (sibling.tagName === element.tagName) {\n index += 1;\n }\n\n sibling = sibling.previousElementSibling;\n }\n\n return index;\n };\n const segmentFor = (element: Element): string => {\n const tag = toTag(element);\n\n if (element.id) {\n return `${tag}#${escapeIdentifier(element.id)}`;\n }\n\n const classNames = Array.from(element.classList)\n .filter((className) => /^[A-Za-z_][\\w-]*$/u.test(className))\n .slice(0, 2);\n\n if (classNames.length > 0) {\n return `${tag}.${classNames.map((className) => escapeIdentifier(className)).join(\".\")}`;\n }\n\n return `${tag}:nth-of-type(${nthOfType(element)})`;\n };\n const buildSelector = (element: Element): string => {\n if (element === root) {\n return clipValue(segmentFor(element), maxSelectorLength);\n }\n\n const parts: string[] = [];\n let current: Element | null = element;\n\n while (current && parts.length < 3) {\n parts.unshift(segmentFor(current));\n\n if (current === root) {\n break;\n }\n\n current = current.parentElement;\n }\n\n return clipValue(parts.join(\" > \"), maxSelectorLength);\n };\n const clipBoxToBounds = (\n box: { x: number; y: number; width: number; height: number },\n bounds: { x: number; y: number; width: number; height: number },\n ) => {\n const left = Math.max(bounds.x, box.x);\n const top = Math.max(bounds.y, box.y);\n const right = Math.min(bounds.x + bounds.width, box.x + box.width);\n const bottom = Math.min(bounds.y + bounds.height, box.y + box.height);\n\n if (right <= left || bottom <= top) {\n return null;\n }\n\n return {\n x: Math.round(left),\n y: Math.round(top),\n width: Math.round(right - left),\n height: Math.round(bottom - top),\n };\n };\n const clippedEdgesForBox = (\n box: { x: number; y: number; width: number; height: number },\n bounds: { x: number; y: number; width: number; height: number },\n ): Array<\"top\" | \"right\" | \"bottom\" | \"left\"> => {\n const edges: Array<\"top\" | \"right\" | \"bottom\" | \"left\"> = [];\n\n if (box.y < bounds.y) {\n edges.push(\"top\");\n }\n\n if (box.x + box.width > bounds.x + bounds.width) {\n edges.push(\"right\");\n }\n\n if (box.y + box.height > bounds.y + bounds.height) {\n edges.push(\"bottom\");\n }\n\n if (box.x < bounds.x) {\n edges.push(\"left\");\n }\n\n return edges;\n };\n const toRelativeBox = (element: Element) => {\n const rect = element.getBoundingClientRect();\n const x = fullPageCapture ? rect.left + window.scrollX : rect.left;\n const y = fullPageCapture ? rect.top + window.scrollY : rect.top;\n const rawBox = {\n x,\n y,\n width: rect.width,\n height: rect.height,\n };\n const bbox = clipBoxToBounds(rawBox, captureBounds);\n\n if (!bbox) {\n return null;\n }\n\n return {\n bbox,\n captureClippedEdges: clippedEdgesForBox(rawBox, captureBounds),\n };\n };\n const isVisible = (element: Element): boolean => {\n const rect = element.getBoundingClientRect();\n\n if (rect.width <= 0 || rect.height <= 0) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n return (\n style.display !== \"none\" &&\n style.visibility !== \"hidden\" &&\n style.opacity !== \"0\" &&\n style.pointerEvents !== \"none\"\n );\n };\n const isMeaningful = (element: Element): boolean => {\n if (element === root) {\n return true;\n }\n\n const tag = toTag(element);\n\n if (excludedTags.has(tag) || inlineNoiseTags.has(tag)) {\n return false;\n }\n\n if (!isVisible(element)) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n const hasText = directTextSnippet(element).length > 0;\n const hasRole = Boolean(element.getAttribute(\"role\"));\n\n return (\n hasText ||\n hasRole ||\n semanticTags.has(tag) ||\n hasPaintedBox(style) ||\n element.children.length === 0\n );\n };\n const buildSnapshotElement = (element: Element) => {\n const boxInfo = toRelativeBox(element);\n\n if (!boxInfo) {\n return null;\n }\n\n const style = window.getComputedStyle(element);\n const textMetrics =\n element instanceof HTMLElement\n ? {\n clientWidth: Math.round(element.clientWidth),\n clientHeight: Math.round(element.clientHeight),\n scrollWidth: Math.round(element.scrollWidth),\n scrollHeight: Math.round(element.scrollHeight),\n overflowX: style.overflowX,\n overflowY: style.overflowY,\n textOverflow: style.textOverflow,\n whiteSpace: style.whiteSpace,\n lineClamp:\n style.getPropertyValue(\"-webkit-line-clamp\") ||\n style.getPropertyValue(\"line-clamp\") ||\n null,\n }\n : null;\n\n return {\n id: buildSelector(element),\n tag: toTag(element),\n selector: buildSelector(element),\n role: element.getAttribute(\"role\"),\n textSnippet: directTextSnippet(element) || null,\n bbox: boxInfo.bbox,\n depth: depthFromRoot(element),\n captureClippedEdges: boxInfo.captureClippedEdges,\n textMetrics,\n };\n };\n const allElements = [root, ...Array.from(root.querySelectorAll(\"*\"))]\n .filter((element) => isMeaningful(element))\n .map((element) => buildSnapshotElement(element))\n .filter((element): element is NonNullable<typeof element> => element !== null);\n const [snapshotRoot, ...elements] = allElements;\n\n if (!snapshotRoot) {\n throw new Error(\"No meaningful DOM elements were found in the page capture.\");\n }\n\n return {\n root: snapshotRoot,\n elements,\n };\n },\n {\n fullPageCapture: fullPage,\n maxSelectorLength: DEFAULT_MAX_SELECTOR_LENGTH,\n maxTextLength: DEFAULT_MAX_TEXT_SNIPPET_LENGTH,\n },\n );\n}\n","import { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport sharp from \"sharp\";\nimport type { NormalizedImageData, PreparedImage } from \"../types/internal.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\n\ninterface NormalizeImageOptions {\n resizeTo?: {\n width: number;\n height: number;\n };\n}\n\nexport async function normalizeImageToPng(\n inputPath: string,\n outputPath: string,\n): Promise<PreparedImage> {\n return normalizeSourceToPng(inputPath, outputPath, `Failed to normalize image: ${inputPath}`);\n}\n\nexport async function bufferToNormalizedPng(\n buffer: Buffer,\n outputPath: string,\n options?: NormalizeImageOptions,\n): Promise<PreparedImage> {\n return normalizeSourceToPng(\n buffer,\n outputPath,\n \"Failed to normalize in-memory image buffer.\",\n options,\n );\n}\n\nexport async function loadNormalizedImage(imagePath: string): Promise<NormalizedImageData> {\n try {\n const { data, info } = await sharp(imagePath)\n .rotate()\n .ensureAlpha()\n .toColorspace(\"srgb\")\n .raw()\n .toBuffer({ resolveWithObject: true });\n\n return {\n width: info.width,\n height: info.height,\n data: new Uint8ClampedArray(data),\n };\n } catch (error) {\n throw new AppError(`Failed to load normalized image data: ${imagePath}`, {\n code: \"image_load_failed\",\n cause: error,\n });\n }\n}\n\nexport async function getImageDimensions(\n imagePath: string,\n): Promise<{ width: number; height: number }> {\n try {\n const metadata = await sharp(imagePath).metadata();\n\n if (!metadata.width || !metadata.height) {\n throw new AppError(`Could not read image dimensions for ${imagePath}`, {\n code: \"image_dimensions_missing\",\n });\n }\n\n return {\n width: metadata.width,\n height: metadata.height,\n };\n } catch (error) {\n if (error instanceof AppError) {\n throw error;\n }\n\n throw new AppError(`Failed to read image dimensions: ${imagePath}`, {\n code: \"image_dimensions_failed\",\n cause: error,\n });\n }\n}\n\nexport function padImageToCanvas(\n image: NormalizedImageData,\n width: number,\n height: number,\n): NormalizedImageData {\n if (image.width === width && image.height === height) {\n return image;\n }\n\n const target = new Uint8ClampedArray(width * height * 4);\n\n for (let y = 0; y < image.height; y += 1) {\n const sourceOffset = y * image.width * 4;\n const targetOffset = y * width * 4;\n target.set(image.data.subarray(sourceOffset, sourceOffset + image.width * 4), targetOffset);\n }\n\n return {\n width,\n height,\n data: target,\n };\n}\n\nexport async function writeRawRgbaPng(\n outputPath: string,\n data: Uint8ClampedArray,\n width: number,\n height: number,\n): Promise<void> {\n try {\n await sharp(Buffer.from(data), {\n raw: {\n width,\n height,\n channels: 4,\n },\n })\n .png()\n .toFile(outputPath);\n } catch (error) {\n throw new AppError(`Failed to write PNG artifact: ${outputPath}`, {\n code: \"artifact_write_failed\",\n cause: error,\n });\n }\n}\n\nasync function normalizeSourceToPng(\n input: string | Buffer,\n outputPath: string,\n errorMessage: string,\n options?: NormalizeImageOptions,\n): Promise<PreparedImage> {\n const resolvedOutputPath = path.resolve(outputPath);\n\n try {\n let pipeline = sharp(input).rotate().ensureAlpha().toColorspace(\"srgb\");\n\n if (options?.resizeTo) {\n pipeline = pipeline.resize(options.resizeTo.width, options.resizeTo.height, {\n fit: \"fill\",\n kernel: sharp.kernel.lanczos3,\n });\n }\n\n const { data, info } = await pipeline.png().toBuffer({ resolveWithObject: true });\n\n if (!info.width || !info.height) {\n throw new AppError(`Could not read normalized image dimensions for ${resolvedOutputPath}`, {\n code: \"image_dimensions_missing\",\n });\n }\n\n await writeFile(resolvedOutputPath, data);\n\n return {\n path: resolvedOutputPath,\n width: info.width,\n height: info.height,\n };\n } catch (error) {\n if (error instanceof AppError) {\n throw error;\n }\n\n throw new AppError(`${errorMessage}: ${ensureError(error).message}`, {\n code: \"image_normalization_failed\",\n cause: error,\n });\n }\n}\n","import pixelmatch from \"pixelmatch\";\nimport {\n COLOR_REGION_DELTA_THRESHOLD,\n DEFAULT_PIXELMATCH_THRESHOLD,\n LAYOUT_EDGE_RATIO_THRESHOLD,\n MAX_RGB_DISTANCE,\n STRONG_DIMENSION_ASPECT_DELTA,\n STRONG_DIMENSION_DELTA_PX,\n} from \"../config/defaults.js\";\nimport type { ComparisonRegion } from \"../types/internal.js\";\nimport type {\n CompareMode,\n DimensionMismatch,\n MetricsReport,\n RegionKind,\n Severity,\n} from \"../types/report.js\";\nimport { compareSeverityDescending } from \"../utils/severity.js\";\nimport { extractRegions } from \"./regions.js\";\nimport { analyzeStructure } from \"./structure.js\";\n\nexport interface EngineResult {\n metrics: MetricsReport;\n rawRegions: ComparisonRegion[];\n mismatchMask: Uint8Array;\n buffers: {\n overlay: Uint8ClampedArray;\n diff: Uint8ClampedArray;\n };\n}\n\nexport function runComparisonEngine(params: {\n reference: Uint8ClampedArray;\n preview: Uint8ClampedArray;\n width: number;\n height: number;\n referenceOriginal: { width: number; height: number };\n previewOriginal: { width: number; height: number };\n mode: CompareMode;\n}): EngineResult {\n const totalPixels = params.width * params.height;\n const diffBuffer = new Uint8ClampedArray(totalPixels * 4);\n const maskBuffer = new Uint8ClampedArray(totalPixels * 4);\n const colorDeltaMap = new Float32Array(totalPixels);\n const mismatchPixels = pixelmatch(\n params.reference,\n params.preview,\n diffBuffer,\n params.width,\n params.height,\n {\n threshold: DEFAULT_PIXELMATCH_THRESHOLD,\n alpha: 0.2,\n diffColor: [255, 0, 0],\n diffColorAlt: [0, 180, 255],\n includeAA: true,\n },\n );\n\n pixelmatch(params.reference, params.preview, maskBuffer, params.width, params.height, {\n threshold: DEFAULT_PIXELMATCH_THRESHOLD,\n alpha: 1,\n diffColor: [255, 255, 255],\n diffColorAlt: [255, 255, 255],\n includeAA: true,\n diffMask: true,\n });\n\n const mismatchMask = new Uint8Array(totalPixels);\n let colorDeltaSum = 0;\n let maxColorDelta = 0;\n let mismatchedColorSamples = 0;\n\n for (let index = 0; index < totalPixels; index += 1) {\n const offset = index * 4;\n const hasMismatch =\n maskBuffer[offset] > 0 ||\n maskBuffer[offset + 1] > 0 ||\n maskBuffer[offset + 2] > 0 ||\n maskBuffer[offset + 3] > 0;\n\n if (!hasMismatch) {\n continue;\n }\n\n mismatchMask[index] = 1;\n const redDelta = params.reference[offset] - params.preview[offset];\n const greenDelta = params.reference[offset + 1] - params.preview[offset + 1];\n const blueDelta = params.reference[offset + 2] - params.preview[offset + 2];\n const delta =\n (Math.sqrt(redDelta ** 2 + greenDelta ** 2 + blueDelta ** 2) / MAX_RGB_DISTANCE) * 100;\n colorDeltaMap[index] = delta;\n colorDeltaSum += delta;\n maxColorDelta = Math.max(maxColorDelta, delta);\n mismatchedColorSamples += 1;\n }\n\n const dimensionMismatch = buildDimensionMismatch(\n params.referenceOriginal,\n params.previewOriginal,\n );\n const structural =\n params.mode === \"all\" || params.mode === \"layout\"\n ? analyzeStructure(params.reference, params.preview, params.width, params.height)\n : null;\n\n const rawRegions = buildRegions({\n mismatchMask,\n edgeDiffMask: structural?.edgeDiffMask ?? null,\n width: params.width,\n height: params.height,\n totalPixels,\n dimensionMismatch,\n overlapWidth: Math.min(params.referenceOriginal.width, params.previewOriginal.width),\n overlapHeight: Math.min(params.referenceOriginal.height, params.previewOriginal.height),\n colorDeltaMap,\n mode: params.mode,\n });\n\n const overlay = createOverlay(params.reference, params.preview, mismatchMask);\n\n return {\n metrics: {\n mismatchPixels,\n mismatchPercent:\n totalPixels === 0 ? 0 : Number(((mismatchPixels / totalPixels) * 100).toFixed(4)),\n meanColorDelta:\n params.mode === \"all\" || params.mode === \"color\"\n ? mismatchedColorSamples > 0\n ? Number((colorDeltaSum / mismatchedColorSamples).toFixed(4))\n : 0\n : null,\n maxColorDelta:\n params.mode === \"all\" || params.mode === \"color\" ? Number(maxColorDelta.toFixed(4)) : null,\n structuralMismatchPercent:\n structural === null ? null : Number(structural.structuralMismatchPercent.toFixed(4)),\n dimensionMismatch,\n findingsCount: 0,\n affectedElementCount: 0,\n },\n rawRegions,\n mismatchMask,\n buffers: {\n overlay,\n diff: diffBuffer,\n },\n };\n}\n\nfunction buildDimensionMismatch(\n reference: { width: number; height: number },\n preview: { width: number; height: number },\n): DimensionMismatch {\n const widthDelta = preview.width - reference.width;\n const heightDelta = preview.height - reference.height;\n const referenceAspect = reference.width / reference.height;\n const previewAspect = preview.width / preview.height;\n\n return {\n widthDelta,\n heightDelta,\n aspectRatioDelta: Number(Math.abs(previewAspect - referenceAspect).toFixed(6)),\n hasMismatch: widthDelta !== 0 || heightDelta !== 0,\n };\n}\n\nfunction buildRegions(params: {\n mismatchMask: Uint8Array;\n edgeDiffMask: Uint8Array | null;\n width: number;\n height: number;\n totalPixels: number;\n dimensionMismatch: DimensionMismatch;\n overlapWidth: number;\n overlapHeight: number;\n colorDeltaMap: Float32Array;\n mode: CompareMode;\n}): ComparisonRegion[] {\n const rawRegions = extractRegions(params.mismatchMask, params.width, params.height);\n\n return rawRegions\n .map((region) => {\n const bboxArea = region.width * region.height;\n const mismatchPercent = bboxArea === 0 ? 0 : (region.pixelCount / bboxArea) * 100;\n const kind = classifyRegionKind({\n region,\n edgeDiffMask: params.edgeDiffMask,\n width: params.width,\n overlapWidth: params.overlapWidth,\n overlapHeight: params.overlapHeight,\n colorDeltaMap: params.colorDeltaMap,\n mode: params.mode,\n });\n const severity = classifyRegionSeverity(\n (region.pixelCount / params.totalPixels) * 100,\n kind,\n params.dimensionMismatch,\n );\n\n return {\n ...region,\n mismatchPercent: Number(mismatchPercent.toFixed(4)),\n kind,\n severity,\n };\n })\n .sort(compareRegions);\n}\n\nfunction classifyRegionKind(params: {\n region: { x: number; y: number; width: number; height: number };\n edgeDiffMask: Uint8Array | null;\n width: number;\n overlapWidth: number;\n overlapHeight: number;\n colorDeltaMap: Float32Array;\n mode: CompareMode;\n}): RegionKind {\n const { region, edgeDiffMask, width, overlapWidth, overlapHeight, colorDeltaMap, mode } = params;\n const outsideOverlap =\n region.x + region.width > overlapWidth || region.y + region.height > overlapHeight;\n\n if (outsideOverlap) {\n return \"dimension\";\n }\n\n const regionMeanColorDelta = meanColorDeltaForRegion(region, colorDeltaMap, width);\n\n if (mode === \"pixel\") {\n return \"pixel\";\n }\n\n if (mode === \"color\") {\n return regionMeanColorDelta >= COLOR_REGION_DELTA_THRESHOLD ? \"color\" : \"pixel\";\n }\n\n if (!edgeDiffMask) {\n return regionMeanColorDelta >= COLOR_REGION_DELTA_THRESHOLD ? \"color\" : \"pixel\";\n }\n\n let edgePixels = 0;\n for (let y = region.y; y < region.y + region.height; y += 1) {\n for (let x = region.x; x < region.x + region.width; x += 1) {\n if (edgeDiffMask[y * width + x] === 1) {\n edgePixels += 1;\n }\n }\n }\n\n const edgeRatio = edgePixels / Math.max(1, region.width * region.height);\n\n if (mode === \"layout\") {\n return edgeRatio >= LAYOUT_EDGE_RATIO_THRESHOLD ? \"layout\" : \"pixel\";\n }\n\n if (\n edgeRatio >= LAYOUT_EDGE_RATIO_THRESHOLD &&\n regionMeanColorDelta >= COLOR_REGION_DELTA_THRESHOLD\n ) {\n return \"mixed\";\n }\n\n if (edgeRatio >= LAYOUT_EDGE_RATIO_THRESHOLD) {\n return \"layout\";\n }\n\n if (regionMeanColorDelta >= COLOR_REGION_DELTA_THRESHOLD) {\n return \"color\";\n }\n\n return \"pixel\";\n}\n\nfunction meanColorDeltaForRegion(\n region: { x: number; y: number; width: number; height: number },\n colorDeltaMap: Float32Array,\n width: number,\n): number {\n let totalDelta = 0;\n let sampleCount = 0;\n\n for (let y = region.y; y < region.y + region.height; y += 1) {\n for (let x = region.x; x < region.x + region.width; x += 1) {\n const delta = colorDeltaMap[y * width + x];\n\n if (delta <= 0) {\n continue;\n }\n\n totalDelta += delta;\n sampleCount += 1;\n }\n }\n\n return sampleCount === 0 ? 0 : totalDelta / sampleCount;\n}\n\nfunction classifyRegionSeverity(\n areaPercent: number,\n kind: RegionKind,\n dimensionMismatch: DimensionMismatch,\n): Severity {\n if (kind === \"dimension\") {\n const strongDimensionShift =\n Math.abs(dimensionMismatch.widthDelta) >= STRONG_DIMENSION_DELTA_PX ||\n Math.abs(dimensionMismatch.heightDelta) >= STRONG_DIMENSION_DELTA_PX ||\n dimensionMismatch.aspectRatioDelta >= STRONG_DIMENSION_ASPECT_DELTA;\n\n return strongDimensionShift ? \"critical\" : \"high\";\n }\n\n let severity: Severity;\n\n if (areaPercent >= 12) {\n severity = \"critical\";\n } else if (areaPercent >= 4) {\n severity = \"high\";\n } else if (areaPercent >= 1.5) {\n severity = \"medium\";\n } else {\n severity = \"low\";\n }\n\n if (kind === \"layout\" && severity === \"low\") {\n return \"medium\";\n }\n\n if (kind === \"mixed\" && severity === \"low\") {\n return \"medium\";\n }\n\n return severity;\n}\n\nfunction createOverlay(\n reference: Uint8ClampedArray,\n preview: Uint8ClampedArray,\n mismatchMask: Uint8Array,\n): Uint8ClampedArray {\n const overlay = new Uint8ClampedArray(reference.length);\n\n for (let index = 0; index < mismatchMask.length; index += 1) {\n const offset = index * 4;\n overlay[offset] = Math.round((reference[offset] + preview[offset]) / 2);\n overlay[offset + 1] = Math.round((reference[offset + 1] + preview[offset + 1]) / 2);\n overlay[offset + 2] = Math.round((reference[offset + 2] + preview[offset + 2]) / 2);\n overlay[offset + 3] = 255;\n\n if (mismatchMask[index] === 1) {\n overlay[offset] = Math.min(255, overlay[offset] + 50);\n }\n }\n\n return overlay;\n}\n\nfunction compareRegions(left: ComparisonRegion, right: ComparisonRegion): number {\n const severityOrder = compareSeverityDescending(left.severity, right.severity);\n\n if (severityOrder !== 0) {\n return severityOrder;\n }\n\n if (left.pixelCount !== right.pixelCount) {\n return right.pixelCount - left.pixelCount;\n }\n\n if (left.y !== right.y) {\n return left.y - right.y;\n }\n\n return left.x - right.x;\n}\n","import { DEFAULT_MIN_REGION_PIXELS } from \"../config/defaults.js\";\n\nexport interface RawRegion {\n x: number;\n y: number;\n width: number;\n height: number;\n pixelCount: number;\n}\n\nexport function extractRegions(\n mask: Uint8Array,\n width: number,\n height: number,\n minPixels = DEFAULT_MIN_REGION_PIXELS,\n): RawRegion[] {\n const visited = new Uint8Array(mask.length);\n const regions: RawRegion[] = [];\n const queue = new Uint32Array(mask.length);\n\n for (let index = 0; index < mask.length; index += 1) {\n if (mask[index] === 0 || visited[index] === 1) {\n continue;\n }\n\n let head = 0;\n let tail = 0;\n queue[tail] = index;\n tail += 1;\n visited[index] = 1;\n\n let minX = index % width;\n let maxX = minX;\n let minY = Math.floor(index / width);\n let maxY = minY;\n let pixelCount = 0;\n\n while (head < tail) {\n const current = queue[head];\n head += 1;\n\n const x = current % width;\n const y = Math.floor(current / width);\n pixelCount += 1;\n\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n\n if (x > 0) {\n const neighbor = current - 1;\n if (mask[neighbor] === 1 && visited[neighbor] === 0) {\n visited[neighbor] = 1;\n queue[tail] = neighbor;\n tail += 1;\n }\n }\n\n if (x < width - 1) {\n const neighbor = current + 1;\n if (mask[neighbor] === 1 && visited[neighbor] === 0) {\n visited[neighbor] = 1;\n queue[tail] = neighbor;\n tail += 1;\n }\n }\n\n if (y > 0) {\n const neighbor = current - width;\n if (mask[neighbor] === 1 && visited[neighbor] === 0) {\n visited[neighbor] = 1;\n queue[tail] = neighbor;\n tail += 1;\n }\n }\n\n if (y < height - 1) {\n const neighbor = current + width;\n if (mask[neighbor] === 1 && visited[neighbor] === 0) {\n visited[neighbor] = 1;\n queue[tail] = neighbor;\n tail += 1;\n }\n }\n }\n\n if (pixelCount < minPixels) {\n continue;\n }\n\n regions.push({\n x: minX,\n y: minY,\n width: maxX - minX + 1,\n height: maxY - minY + 1,\n pixelCount,\n });\n }\n\n return regions;\n}\n","import { DEFAULT_EDGE_THRESHOLD } from \"../config/defaults.js\";\n\nexport interface StructuralAnalysis {\n edgeMaskReference: Uint8Array;\n edgeMaskPreview: Uint8Array;\n edgeDiffMask: Uint8Array;\n structuralMismatchPercent: number;\n}\n\nexport function analyzeStructure(\n reference: Uint8ClampedArray,\n preview: Uint8ClampedArray,\n width: number,\n height: number,\n): StructuralAnalysis {\n const lumaReference = rgbaToLuma(reference, width, height);\n const lumaPreview = rgbaToLuma(preview, width, height);\n const edgeMaskReference = sobelEdgeMask(lumaReference, width, height, DEFAULT_EDGE_THRESHOLD);\n const edgeMaskPreview = sobelEdgeMask(lumaPreview, width, height, DEFAULT_EDGE_THRESHOLD);\n const edgeDiffMask = new Uint8Array(width * height);\n\n let unionCount = 0;\n let diffCount = 0;\n\n for (let index = 0; index < edgeDiffMask.length; index += 1) {\n const ref = edgeMaskReference[index];\n const prev = edgeMaskPreview[index];\n const union = ref === 1 || prev === 1;\n\n if (union) {\n unionCount += 1;\n }\n\n if (ref !== prev) {\n edgeDiffMask[index] = 1;\n diffCount += 1;\n }\n }\n\n return {\n edgeMaskReference,\n edgeMaskPreview,\n edgeDiffMask,\n structuralMismatchPercent: unionCount === 0 ? 0 : (diffCount / unionCount) * 100,\n };\n}\n\nfunction rgbaToLuma(data: Uint8ClampedArray, width: number, height: number): Float32Array {\n const luma = new Float32Array(width * height);\n\n for (let index = 0; index < width * height; index += 1) {\n const offset = index * 4;\n luma[index] = data[offset] * 0.2126 + data[offset + 1] * 0.7152 + data[offset + 2] * 0.0722;\n }\n\n return luma;\n}\n\nfunction sobelEdgeMask(\n luma: Float32Array,\n width: number,\n height: number,\n threshold: number,\n): Uint8Array {\n const edgeMask = new Uint8Array(width * height);\n\n for (let y = 1; y < height - 1; y += 1) {\n for (let x = 1; x < width - 1; x += 1) {\n const topLeft = luma[(y - 1) * width + (x - 1)];\n const top = luma[(y - 1) * width + x];\n const topRight = luma[(y - 1) * width + (x + 1)];\n const left = luma[y * width + (x - 1)];\n const right = luma[y * width + (x + 1)];\n const bottomLeft = luma[(y + 1) * width + (x - 1)];\n const bottom = luma[(y + 1) * width + x];\n const bottomRight = luma[(y + 1) * width + (x + 1)];\n\n const gx = -topLeft + topRight - 2 * left + 2 * right - bottomLeft + bottomRight;\n const gy = topLeft + 2 * top + topRight - bottomLeft - 2 * bottom - bottomRight;\n const magnitude = Math.sqrt(gx * gx + gy * gy);\n\n if (magnitude >= threshold) {\n edgeMask[y * width + x] = 1;\n }\n }\n }\n\n return edgeMask;\n}\n","import type { FindingVisualization } from \"../analysis/findings.js\";\nimport type { Severity } from \"../types/report.js\";\n\nexport function createHeatmapArtifact(params: {\n reference: Uint8ClampedArray;\n preview: Uint8ClampedArray;\n mismatchMask: Uint8Array;\n visuals: FindingVisualization[];\n width: number;\n height: number;\n}): Uint8ClampedArray {\n const heatmap = new Uint8ClampedArray(params.reference.length);\n\n for (let index = 0; index < params.mismatchMask.length; index += 1) {\n const offset = index * 4;\n const base = Math.round(((params.reference[offset] + params.preview[offset]) / 2) * 0.25);\n heatmap[offset] = base;\n heatmap[offset + 1] = base;\n heatmap[offset + 2] = base;\n heatmap[offset + 3] = 255;\n\n if (params.mismatchMask[index] === 1) {\n heatmap[offset] = 255;\n heatmap[offset + 1] = 120;\n heatmap[offset + 2] = 0;\n }\n }\n\n for (const visual of params.visuals) {\n drawBoundingBox(\n heatmap,\n params.width,\n params.height,\n visual.primaryBox,\n boundingBoxColor(visual.severity),\n 2,\n );\n\n for (const hotspotBox of visual.hotspotBoxes) {\n drawBoundingBox(\n heatmap,\n params.width,\n params.height,\n hotspotBox,\n hotspotColor(visual.severity),\n 1,\n );\n }\n }\n\n return heatmap;\n}\n\nfunction drawBoundingBox(\n image: Uint8ClampedArray,\n width: number,\n height: number,\n box: { x: number; y: number; width: number; height: number },\n color: [number, number, number, number],\n thickness: number,\n): void {\n for (let inset = 0; inset < thickness; inset += 1) {\n const xStart = Math.max(0, box.x + inset);\n const yStart = Math.max(0, box.y + inset);\n const xEnd = Math.min(width - 1, box.x + box.width - 1 - inset);\n const yEnd = Math.min(height - 1, box.y + box.height - 1 - inset);\n\n if (xEnd < xStart || yEnd < yStart) {\n continue;\n }\n\n for (let x = xStart; x <= xEnd; x += 1) {\n paintPixel(image, width, x, yStart, color);\n paintPixel(image, width, x, yEnd, color);\n }\n\n for (let y = yStart; y <= yEnd; y += 1) {\n paintPixel(image, width, xStart, y, color);\n paintPixel(image, width, xEnd, y, color);\n }\n }\n}\n\nfunction paintPixel(\n image: Uint8ClampedArray,\n width: number,\n x: number,\n y: number,\n color: [number, number, number, number],\n): void {\n const offset = (y * width + x) * 4;\n image[offset] = color[0];\n image[offset + 1] = color[1];\n image[offset + 2] = color[2];\n image[offset + 3] = color[3];\n}\n\nfunction boundingBoxColor(severity: Severity): [number, number, number, number] {\n switch (severity) {\n case \"critical\":\n return [255, 255, 255, 255];\n case \"high\":\n return [255, 0, 255, 255];\n case \"medium\":\n return [0, 255, 255, 255];\n case \"low\":\n default:\n return [0, 255, 0, 255];\n }\n}\n\nfunction hotspotColor(severity: Severity): [number, number, number, number] {\n switch (severity) {\n case \"critical\":\n return [255, 220, 120, 255];\n case \"high\":\n return [255, 140, 120, 255];\n case \"medium\":\n return [120, 220, 255, 255];\n case \"low\":\n default:\n return [120, 255, 180, 255];\n }\n}\n","import { access, mkdir, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { AppError } from \"../utils/errors.js\";\n\ninterface FilesystemError {\n code?: string;\n}\n\nexport async function ensureDirectory(dirPath: string): Promise<string> {\n const resolved = path.resolve(dirPath);\n await mkdir(resolved, { recursive: true });\n return resolved;\n}\n\nexport async function ensureFileExists(filePath: string): Promise<string> {\n const resolved = path.resolve(filePath);\n\n try {\n const fileStat = await stat(resolved);\n\n if (!fileStat.isFile()) {\n throw new AppError(`Expected a file but received a different path: ${resolved}`);\n }\n\n return resolved;\n } catch (error) {\n if (error instanceof AppError) {\n throw error;\n }\n\n const code = (error as FilesystemError).code;\n\n if (code === \"ENOENT\") {\n throw new AppError(`Input file does not exist: ${resolved}`, {\n code: \"input_file_missing\",\n cause: error,\n });\n }\n\n if (code === \"EACCES\") {\n throw new AppError(`Input file is not readable: ${resolved}`, {\n code: \"input_file_unreadable\",\n cause: error,\n });\n }\n\n throw new AppError(`Failed to access input file: ${resolved}`, {\n code: \"input_file_access_failed\",\n cause: error,\n });\n }\n}\n\nexport async function writeJsonFile(filePath: string, value: unknown): Promise<void> {\n await writeFile(filePath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n","import path from \"node:path\";\nimport type { ParsedPreviewInput, ParsedReferenceInput } from \"../types/internal.js\";\nimport type {\n CompareCommandOptions,\n InputSourceReport,\n ReferenceInputSourceReport,\n Viewport,\n} from \"../types/report.js\";\nimport { AppError } from \"../utils/errors.js\";\nimport { hashToSelector, isFigmaUrl, isHttpUrl, parseFigmaUrl } from \"../utils/url.js\";\nimport { parseViewport } from \"../utils/viewport.js\";\nimport { ensureFileExists } from \"./fs.js\";\n\nexport async function parsePreviewInput(\n options: CompareCommandOptions,\n): Promise<ParsedPreviewInput> {\n const selector = hashToSelector(options.preview, options.selector);\n\n if (isHttpUrl(options.preview)) {\n if (!options.viewport) {\n throw new AppError(\n \"Preview URL requires --viewport so the browser screenshot is deterministic.\",\n {\n code: \"preview_viewport_required\",\n },\n );\n }\n\n const viewport = parseViewport(options.viewport);\n\n if (options.fullPage && selector) {\n throw new AppError(\n \"--full-page cannot be used together with --selector or a preview URL hash fragment.\",\n {\n code: \"preview_full_page_selector_conflict\",\n },\n );\n }\n\n return {\n kind: \"url\",\n input: options.preview,\n resolved: new URL(options.preview).toString(),\n selector,\n viewport,\n };\n }\n\n if (options.selector) {\n throw new AppError(\"--selector can only be used when --preview is a URL.\", {\n code: \"preview_selector_requires_url\",\n });\n }\n\n if (options.fullPage) {\n throw new AppError(\"--full-page can only be used when --preview is a URL.\", {\n code: \"preview_full_page_requires_url\",\n });\n }\n\n const resolvedPath = await ensureFileExists(options.preview);\n const viewport = options.viewport ? parseViewport(options.viewport) : null;\n\n return {\n kind: \"path\",\n input: options.preview,\n resolved: resolvedPath,\n selector: null,\n viewport,\n };\n}\n\nexport async function parseReferenceInput(reference: string): Promise<ParsedReferenceInput> {\n if (isHttpUrl(reference)) {\n const parsedFigmaUrl = parseFigmaUrl(reference);\n\n return {\n kind: \"figma-url\",\n input: reference,\n resolved: parsedFigmaUrl.resolved,\n fileKey: parsedFigmaUrl.fileKey,\n nodeId: parsedFigmaUrl.nodeId,\n };\n }\n\n const resolvedPath = await ensureFileExists(reference);\n\n return {\n kind: \"path\",\n input: reference,\n resolved: resolvedPath,\n };\n}\n\nexport function resolveViewportForReport(\n previewViewport: Viewport | null,\n imageDimensions: { width: number; height: number },\n): Viewport {\n return previewViewport ?? { width: imageDimensions.width, height: imageDimensions.height };\n}\n\nexport function inferPreviewInputSource(\n options: Pick<CompareCommandOptions, \"preview\" | \"selector\">,\n): InputSourceReport {\n if (isHttpUrl(options.preview)) {\n return {\n input: options.preview,\n kind: \"url\",\n resolved: new URL(options.preview).toString(),\n selector: hashToSelector(options.preview, options.selector),\n };\n }\n\n return {\n input: options.preview,\n kind: \"path\",\n resolved: path.resolve(options.preview),\n selector: null,\n };\n}\n\nexport function inferReferenceInputSource(reference: string): ReferenceInputSourceReport {\n if (isHttpUrl(reference)) {\n return {\n input: reference,\n kind: isFigmaUrl(reference) ? \"figma-url\" : \"url\",\n resolved: new URL(reference).toString(),\n selector: null,\n transport: null,\n };\n }\n\n return {\n input: reference,\n kind: \"path\",\n resolved: path.resolve(reference),\n selector: null,\n transport: \"path\",\n };\n}\n","import { AppError } from \"./errors.js\";\n\nfunction parseUrl(value: string): URL | null {\n try {\n return new URL(value);\n } catch {\n return null;\n }\n}\n\nexport function isHttpUrl(value: string): boolean {\n const url = parseUrl(value);\n return url?.protocol === \"http:\" || url?.protocol === \"https:\";\n}\n\nexport function isFigmaUrl(value: string): boolean {\n const url = parseUrl(value);\n\n if (!url) {\n return false;\n }\n\n return url.hostname === \"figma.com\" || url.hostname.endsWith(\".figma.com\");\n}\n\nexport function hashToSelector(input: string, explicitSelector?: string): string | null {\n if (explicitSelector) {\n return explicitSelector;\n }\n\n if (!isHttpUrl(input)) {\n return null;\n }\n\n const url = new URL(input);\n const hash = url.hash.replace(/^#/, \"\");\n\n if (!hash) {\n return null;\n }\n\n return `#${decodeURIComponent(hash)}`;\n}\n\nexport interface ParsedFigmaUrl {\n fileKey: string;\n nodeId: string;\n resolved: string;\n}\n\nexport function normalizeNodeId(value: string): string {\n return decodeURIComponent(value).replace(/-/g, \":\");\n}\n\nexport function parseFigmaUrl(input: string): ParsedFigmaUrl {\n const url = parseUrl(input);\n\n if (!url) {\n throw new AppError(`Invalid Figma URL: ${input}`, {\n code: \"figma_url_invalid\",\n });\n }\n\n if (!isFigmaUrl(input)) {\n throw new AppError(`Reference URL must be a Figma URL or local image path: ${input}`, {\n code: \"figma_url_expected\",\n });\n }\n\n const parts = url.pathname.split(\"/\").filter(Boolean);\n\n if (parts.length < 2) {\n throw new AppError(`Could not extract file key from Figma URL: ${input}`, {\n code: \"figma_file_key_missing\",\n });\n }\n\n let fileKey: string | undefined;\n\n if (parts[0] === \"design\" && parts[2] === \"branch\") {\n fileKey = parts[3];\n } else if (parts[0] === \"design\" || parts[0] === \"file\") {\n fileKey = parts[1];\n } else if (parts[1] === \"branch\" && parts[2]) {\n fileKey = parts[2];\n }\n\n if (!fileKey) {\n fileKey = parts[1];\n }\n\n const nodeId = url.searchParams.get(\"node-id\");\n\n if (!nodeId) {\n throw new AppError(\n `Figma URL must include a node-id query parameter so the CLI can export the correct frame: ${input}`,\n {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"figma_node_id_missing\",\n },\n );\n }\n\n return {\n fileKey,\n nodeId: normalizeNodeId(nodeId),\n resolved: url.toString(),\n };\n}\n","import { DEFAULT_VIEWPORT_HEIGHT } from \"../config/defaults.js\";\nimport type { Viewport } from \"../types/report.js\";\nimport { AppError } from \"./errors.js\";\n\nexport function parseViewport(value: string): Viewport {\n const trimmedValue = value.trim();\n const explicitMatch = /^(?<width>\\d+)x(?<height>\\d+)$/i.exec(trimmedValue);\n\n if (explicitMatch?.groups) {\n const width = Number(explicitMatch.groups.width);\n const height = Number(explicitMatch.groups.height);\n\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n throw new AppError(\n `Invalid viewport \"${value}\". Width and height must be positive integers.`,\n {\n code: \"viewport_invalid_dimensions\",\n },\n );\n }\n\n return { width, height };\n }\n\n const widthOnlyMatch = /^(?<width>\\d+)$/i.exec(trimmedValue);\n\n if (widthOnlyMatch?.groups) {\n const width = Number(widthOnlyMatch.groups.width);\n\n if (!Number.isFinite(width) || width <= 0) {\n throw new AppError(`Invalid viewport \"${value}\". Width must be a positive integer.`, {\n code: \"viewport_invalid_width\",\n });\n }\n\n return {\n width,\n height: DEFAULT_VIEWPORT_HEIGHT,\n };\n }\n\n throw new AppError(\n `Invalid viewport \"${value}\". Expected WIDTH or WIDTHxHEIGHT, for example 1920 or 1920x900.`,\n {\n code: \"viewport_invalid_format\",\n },\n );\n}\n","import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { createServer } from \"node:http\";\nimport { readFile, rm, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport sharp from \"sharp\";\nimport type {\n OAuthDiscoveryState,\n OAuthClientProvider,\n} from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport { UnauthorizedError } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n StreamableHTTPClientTransport,\n StreamableHTTPError,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type {\n OAuthClientInformationMixed,\n OAuthClientMetadata,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport { DEFAULT_FIGMA_OAUTH_TIMEOUT_MS, DEFAULT_RESOURCE_TIMEOUT_MS } from \"../config/defaults.js\";\nimport { ensureDirectory } from \"../io/fs.js\";\nimport { bufferToNormalizedPng } from \"../io/image.js\";\nimport type { ParsedReferenceInput, PreparedReferenceImage } from \"../types/internal.js\";\nimport type { ReferenceTransport } from \"../types/report.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\nimport type { ReferenceProvider } from \"./provider.js\";\n\nconst PEYE_CLIENT_NAME = \"peye\";\nconst PEYE_CLIENT_VERSION = \"0.1.0\";\nconst SCREENSHOT_TOOL_NAME = \"get_screenshot\";\nconst METADATA_TOOL_NAME = \"get_metadata\";\nconst MAX_ACCEPTABLE_ASPECT_RATIO_DELTA = 0.02;\n\ninterface FigmaMcpReferenceProviderOptions {\n readonly serverUrl: string;\n readonly transport: Extract<ReferenceTransport, \"figma-mcp-desktop\" | \"figma-mcp-remote\">;\n}\n\ninterface OAuthStateFile {\n clientInformation?: OAuthClientInformationMixed;\n tokens?: OAuthTokens;\n codeVerifier?: string;\n discoveryState?: OAuthDiscoveryState;\n}\n\ninterface Deferred<TValue> {\n promise: Promise<TValue>;\n reject: (error: unknown) => void;\n resolve: (value: TValue) => void;\n}\n\ninterface OAuthCallbackServer {\n readonly redirectUrl: string;\n waitForAuthorizationCode(): Promise<string>;\n close(): Promise<void>;\n}\n\nexport class FigmaMcpReferenceProvider implements ReferenceProvider {\n readonly kind = \"figma-url\" as const;\n private readonly serverUrl: string;\n private readonly transport: FigmaMcpReferenceProviderOptions[\"transport\"];\n\n constructor(options: FigmaMcpReferenceProviderOptions) {\n this.serverUrl = options.serverUrl;\n this.transport = options.transport;\n }\n\n async prepare(\n reference: ParsedReferenceInput,\n outputPath: string,\n ): Promise<PreparedReferenceImage> {\n if (reference.kind !== \"figma-url\") {\n throw new AppError(\n `Unsupported reference input kind for Figma MCP provider: ${reference.kind}`,\n {\n code: \"reference_provider_kind_mismatch\",\n },\n );\n }\n\n const callbackServer =\n this.transport === \"figma-mcp-remote\" && isInteractiveTerminal()\n ? await createOAuthCallbackServer()\n : null;\n const oauthProvider =\n this.transport === \"figma-mcp-remote\" && callbackServer\n ? await PersistentOAuthClientProvider.create(this.serverUrl, callbackServer)\n : null;\n const transportOptions =\n oauthProvider === null\n ? { fetch: fetchWithTimeout }\n : { authProvider: oauthProvider, fetch: fetchWithTimeout };\n const transport = new StreamableHTTPClientTransport(new URL(this.serverUrl), transportOptions);\n const client = new Client(\n {\n name: PEYE_CLIENT_NAME,\n version: PEYE_CLIENT_VERSION,\n },\n {\n capabilities: {},\n },\n );\n\n try {\n await runWithOAuthRetry(transport, oauthProvider, callbackServer, () =>\n client.connect(transport as Transport),\n );\n\n const tools = await runWithOAuthRetry(transport, oauthProvider, callbackServer, () =>\n client.listTools(),\n );\n const hasScreenshotTool = tools.tools.some((tool) => tool.name === SCREENSHOT_TOOL_NAME);\n\n if (!hasScreenshotTool) {\n throw new AppError(\n `Figma MCP server at ${this.serverUrl} does not expose ${SCREENSHOT_TOOL_NAME}.`,\n {\n code: \"figma_mcp_tool_missing\",\n },\n );\n }\n\n const result = await runWithOAuthRetry(transport, oauthProvider, callbackServer, () =>\n client.callTool({\n name: SCREENSHOT_TOOL_NAME,\n arguments: {\n fileKey: reference.fileKey,\n nodeId: reference.nodeId,\n },\n }),\n );\n const buffer = extractImageBuffer(result, this.serverUrl);\n const resizeTarget = tools.tools.some((tool) => tool.name === METADATA_TOOL_NAME)\n ? await resolveMetadataResizeTarget(\n client,\n transport,\n oauthProvider,\n callbackServer,\n reference,\n buffer,\n )\n : null;\n const prepared =\n resizeTarget === null\n ? await bufferToNormalizedPng(buffer, outputPath)\n : await bufferToNormalizedPng(buffer, outputPath, {\n resizeTo: resizeTarget,\n });\n\n return {\n ...prepared,\n transport: this.transport,\n };\n } catch (error) {\n throw mapMcpError(error, this.transport, this.serverUrl);\n } finally {\n await client.close().catch(() => undefined);\n await transport.close().catch(() => undefined);\n await callbackServer?.close().catch(() => undefined);\n }\n }\n}\n\nasync function resolveMetadataResizeTarget(\n client: Client,\n transport: StreamableHTTPClientTransport,\n oauthProvider: PersistentOAuthClientProvider | null,\n callbackServer: OAuthCallbackServer | null,\n reference: Extract<ParsedReferenceInput, { kind: \"figma-url\" }>,\n screenshotBuffer: Buffer,\n): Promise<{ width: number; height: number } | null> {\n const metadataResult = await runWithOAuthRetry(transport, oauthProvider, callbackServer, () =>\n client.callTool({\n name: METADATA_TOOL_NAME,\n arguments: {\n fileKey: reference.fileKey,\n nodeId: reference.nodeId,\n },\n }),\n );\n\n const targetDimensions = extractNodeDimensions(metadataResult);\n\n if (targetDimensions === null) {\n return null;\n }\n\n const currentDimensions = await readBufferDimensions(screenshotBuffer);\n\n if (\n currentDimensions.width >= targetDimensions.width ||\n currentDimensions.height >= targetDimensions.height\n ) {\n return null;\n }\n\n const currentAspectRatio = currentDimensions.width / currentDimensions.height;\n const targetAspectRatio = targetDimensions.width / targetDimensions.height;\n\n if (Math.abs(currentAspectRatio - targetAspectRatio) > MAX_ACCEPTABLE_ASPECT_RATIO_DELTA) {\n return null;\n }\n\n return targetDimensions;\n}\n\nasync function runWithOAuthRetry<TValue>(\n transport: StreamableHTTPClientTransport,\n provider: PersistentOAuthClientProvider | null,\n callbackServer: OAuthCallbackServer | null,\n operation: () => Promise<TValue>,\n): Promise<TValue> {\n let hasRetried = false;\n\n while (true) {\n try {\n return await operation();\n } catch (error) {\n if (!(error instanceof UnauthorizedError) || provider === null || callbackServer === null) {\n throw error;\n }\n\n if (hasRetried) {\n throw error;\n }\n\n hasRetried = true;\n const authorizationCode = await callbackServer.waitForAuthorizationCode();\n await transport.finishAuth(authorizationCode);\n }\n }\n}\n\nfunction extractImageBuffer(\n result: Awaited<ReturnType<Client[\"callTool\"]>>,\n serverUrl: string,\n): Buffer {\n if (\"toolResult\" in result) {\n throw new AppError(`Figma MCP server at ${serverUrl} returned an unsupported tool result.`, {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"figma_mcp_invalid_response\",\n });\n }\n\n if (result.isError) {\n const message = extractTextContent(result.content) ?? \"Figma MCP tool returned an error.\";\n throw new AppError(message, {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"figma_mcp_invalid_response\",\n });\n }\n\n for (const block of result.content) {\n if (block.type === \"image\" && block.mimeType.startsWith(\"image/\")) {\n return Buffer.from(block.data, \"base64\");\n }\n\n if (block.type === \"resource\" && \"blob\" in block.resource) {\n const mimeType = block.resource.mimeType ?? \"\";\n\n if (mimeType.startsWith(\"image/\")) {\n return Buffer.from(block.resource.blob, \"base64\");\n }\n }\n }\n\n throw new AppError(\n `Figma MCP server at ${serverUrl} returned no image content for get_screenshot.`,\n {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"figma_mcp_invalid_response\",\n },\n );\n}\n\nfunction extractNodeDimensions(\n result: Awaited<ReturnType<Client[\"callTool\"]>>,\n): { width: number; height: number } | null {\n if (\"toolResult\" in result || result.isError) {\n return null;\n }\n\n const metadataText = extractTextContent(result.content);\n\n if (!metadataText) {\n return null;\n }\n\n const rootTagMatch = metadataText.match(/<[^>]+>/);\n\n if (!rootTagMatch) {\n return null;\n }\n\n const widthMatch = rootTagMatch[0].match(/\\bwidth=\"([^\"]+)\"/);\n const heightMatch = rootTagMatch[0].match(/\\bheight=\"([^\"]+)\"/);\n const width = Math.round(Number.parseFloat(widthMatch?.[1] ?? \"\"));\n const height = Math.round(Number.parseFloat(heightMatch?.[1] ?? \"\"));\n\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n return null;\n }\n\n return { width, height };\n}\n\nfunction extractTextContent(\n content: ReadonlyArray<{ type: string; text?: string }>,\n): string | null {\n for (const block of content) {\n if (block.type === \"text\") {\n return block.text ?? null;\n }\n }\n\n return null;\n}\n\nasync function readBufferDimensions(buffer: Buffer): Promise<{ width: number; height: number }> {\n const metadata = await sharp(buffer).metadata();\n\n if (!metadata.width || !metadata.height) {\n throw new AppError(\"Could not read dimensions from the Figma MCP screenshot buffer.\", {\n code: \"figma_mcp_invalid_response\",\n });\n }\n\n return {\n width: metadata.width,\n height: metadata.height,\n };\n}\n\nfunction mapMcpError(error: unknown, transport: ReferenceTransport, serverUrl: string): AppError {\n if (error instanceof AppError) {\n return error;\n }\n\n if (error instanceof UnauthorizedError) {\n return new AppError(\n transport === \"figma-mcp-remote\"\n ? \"Remote Figma MCP requires OAuth authorization.\"\n : `Figma MCP at ${serverUrl} rejected the request as unauthorized.`,\n {\n code: \"figma_mcp_auth_required\",\n cause: error,\n },\n );\n }\n\n if (error instanceof StreamableHTTPError && error.code === 401) {\n return new AppError(\n transport === \"figma-mcp-remote\"\n ? \"Remote Figma MCP requires OAuth authorization.\"\n : `Figma MCP at ${serverUrl} rejected the request as unauthorized.`,\n {\n code: \"figma_mcp_auth_required\",\n cause: error,\n },\n );\n }\n\n return new AppError(\n `Failed to read Figma reference through ${transport} at ${serverUrl}. ${ensureError(error).message}`,\n {\n code: \"figma_mcp_request_failed\",\n cause: error,\n },\n );\n}\n\nfunction isInteractiveTerminal(): boolean {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\nfunction fetchWithTimeout(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const timeoutSignal = AbortSignal.timeout(DEFAULT_RESOURCE_TIMEOUT_MS);\n const signal = init?.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;\n return fetch(input, {\n ...init,\n signal,\n });\n}\n\nclass PersistentOAuthClientProvider implements OAuthClientProvider {\n private readonly callbackServer: OAuthCallbackServer;\n private readonly storagePath: string;\n private readonly oauthState: OAuthStateFile;\n\n private constructor(\n callbackServer: OAuthCallbackServer,\n storagePath: string,\n state: OAuthStateFile,\n ) {\n this.callbackServer = callbackServer;\n this.storagePath = storagePath;\n this.oauthState = state;\n }\n\n static async create(\n serverUrl: string,\n callbackServer: OAuthCallbackServer,\n ): Promise<PersistentOAuthClientProvider> {\n const storagePath = await oauthStatePath(serverUrl);\n const state = await loadOAuthState(storagePath);\n return new PersistentOAuthClientProvider(callbackServer, storagePath, state);\n }\n\n get redirectUrl(): string {\n return this.callbackServer.redirectUrl;\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n client_name: \"peye\",\n redirect_uris: [this.callbackServer.redirectUrl],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n };\n }\n\n clientInformation(): OAuthClientInformationMixed | undefined {\n return this.oauthState.clientInformation;\n }\n\n async saveClientInformation(clientInformation: OAuthClientInformationMixed): Promise<void> {\n this.oauthState.clientInformation = clientInformation;\n await this.persist();\n }\n\n tokens(): OAuthTokens | undefined {\n return this.oauthState.tokens;\n }\n\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n this.oauthState.tokens = tokens;\n await this.persist();\n }\n\n redirectToAuthorization(authorizationUrl: URL): void {\n process.stderr.write(\n [\n \"Remote Figma MCP requires authorization.\",\n `Open this URL to continue: ${authorizationUrl.toString()}`,\n ].join(\"\\n\") + \"\\n\",\n );\n openExternalUrl(authorizationUrl.toString());\n }\n\n async saveCodeVerifier(codeVerifier: string): Promise<void> {\n this.oauthState.codeVerifier = codeVerifier;\n await this.persist();\n }\n\n codeVerifier(): string {\n if (!this.oauthState.codeVerifier) {\n throw new Error(\"No OAuth code verifier available.\");\n }\n\n return this.oauthState.codeVerifier;\n }\n\n async invalidateCredentials(\n scope: \"all\" | \"client\" | \"tokens\" | \"verifier\" | \"discovery\",\n ): Promise<void> {\n if (scope === \"all\" || scope === \"client\") {\n delete this.oauthState.clientInformation;\n }\n\n if (scope === \"all\" || scope === \"tokens\") {\n delete this.oauthState.tokens;\n }\n\n if (scope === \"all\" || scope === \"verifier\") {\n delete this.oauthState.codeVerifier;\n }\n\n if (scope === \"all\" || scope === \"discovery\") {\n delete this.oauthState.discoveryState;\n }\n\n const hasState = Object.values(this.oauthState).some((value) => value !== undefined);\n\n if (!hasState) {\n await rm(this.storagePath, { force: true }).catch(() => undefined);\n return;\n }\n\n await this.persist();\n }\n\n discoveryState(): OAuthDiscoveryState | undefined {\n return this.oauthState.discoveryState;\n }\n\n async saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> {\n this.oauthState.discoveryState = state;\n await this.persist();\n }\n\n private async persist(): Promise<void> {\n await ensureDirectory(path.dirname(this.storagePath));\n await writeFile(this.storagePath, `${JSON.stringify(this.oauthState, null, 2)}\\n`, \"utf8\");\n }\n}\n\nasync function loadOAuthState(storagePath: string): Promise<OAuthStateFile> {\n try {\n const raw = await readFile(storagePath, \"utf8\");\n return JSON.parse(raw) as OAuthStateFile;\n } catch (error) {\n const message = ensureError(error).message;\n\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return {};\n }\n\n throw new AppError(`Failed to load persisted Figma MCP OAuth state. ${message}`, {\n code: \"figma_mcp_oauth_state_invalid\",\n cause: error,\n });\n }\n}\n\nasync function oauthStatePath(serverUrl: string): Promise<string> {\n const digest = createHash(\"sha256\").update(serverUrl).digest(\"hex\").slice(0, 16);\n const dir = path.join(resolveConfigDir(), \"oauth\");\n await ensureDirectory(dir);\n return path.join(dir, `figma-${digest}.json`);\n}\n\nfunction resolveConfigDir(): string {\n if (process.platform === \"win32\" && process.env.APPDATA) {\n return path.join(process.env.APPDATA, \"peye\");\n }\n\n if (process.env.XDG_CONFIG_HOME) {\n return path.join(process.env.XDG_CONFIG_HOME, \"peye\");\n }\n\n return path.join(os.homedir(), \".config\", \"peye\");\n}\n\nasync function createOAuthCallbackServer(): Promise<OAuthCallbackServer> {\n const deferred = createDeferred<string>();\n const server = createServer((request, response) => {\n const requestUrl = new URL(request.url ?? \"/\", \"http://127.0.0.1\");\n const authorizationCode = requestUrl.searchParams.get(\"code\");\n const error = requestUrl.searchParams.get(\"error\");\n\n if (authorizationCode) {\n response.statusCode = 200;\n response.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n response.end(\n \"<html><body><h1>Authorization complete</h1><p>You can close this window.</p></body></html>\",\n );\n deferred.resolve(authorizationCode);\n return;\n }\n\n if (error) {\n response.statusCode = 400;\n response.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n response.end(`<html><body><h1>Authorization failed</h1><p>${error}</p></body></html>`);\n deferred.reject(new Error(`OAuth authorization failed: ${error}`));\n return;\n }\n\n response.statusCode = 400;\n response.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n response.end(\"<html><body><h1>Invalid callback</h1></body></html>\");\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n server.off(\"error\", reject);\n resolve();\n });\n });\n\n const address = server.address();\n\n if (!address || typeof address === \"string\") {\n throw new AppError(\"Failed to start local OAuth callback server.\", {\n code: \"figma_mcp_oauth_callback_failed\",\n });\n }\n\n return {\n redirectUrl: `http://127.0.0.1:${address.port}/callback`,\n waitForAuthorizationCode: async () => {\n return new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new AppError(\"Timed out waiting for the Figma MCP OAuth callback.\", {\n code: \"figma_mcp_oauth_timeout\",\n }),\n );\n }, DEFAULT_FIGMA_OAUTH_TIMEOUT_MS);\n timeout.unref?.();\n\n deferred.promise.then(\n (code) => {\n clearTimeout(timeout);\n resolve(code);\n },\n (error) => {\n clearTimeout(timeout);\n reject(ensureError(error));\n },\n );\n });\n },\n close: async () => {\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n },\n };\n}\n\nfunction createDeferred<TValue>(): Deferred<TValue> {\n let resolve!: (value: TValue) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<TValue>((innerResolve, innerReject) => {\n resolve = innerResolve;\n reject = innerReject;\n });\n\n return {\n promise,\n reject,\n resolve,\n };\n}\n\nfunction openExternalUrl(url: string): void {\n const command =\n process.platform === \"darwin\"\n ? [\"open\", url]\n : process.platform === \"win32\"\n ? [\"cmd\", \"/c\", \"start\", \"\", url]\n : [\"xdg-open\", url];\n\n const [file, ...args] = command;\n\n try {\n const child = spawn(file, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.once(\"error\", () => {\n process.stderr.write(\"Open the authorization URL manually if the browser did not start.\\n\");\n });\n child.unref();\n } catch {\n process.stderr.write(`Open the authorization URL manually if the browser did not start.\\n`);\n }\n}\n","import { DEFAULT_FIGMA_API_BASE_URL, DEFAULT_RESOURCE_TIMEOUT_MS } from \"../config/defaults.js\";\nimport { bufferToNormalizedPng } from \"../io/image.js\";\nimport type { ParsedReferenceInput, PreparedReferenceImage } from \"../types/internal.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\nimport type { ReferenceProvider } from \"./provider.js\";\n\ninterface FigmaImagesResponse {\n err?: string;\n images?: Record<string, string | undefined>;\n}\n\nexport class FigmaRestReferenceProvider implements ReferenceProvider {\n readonly kind = \"figma-url\" as const;\n\n async prepare(\n reference: ParsedReferenceInput,\n outputPath: string,\n ): Promise<PreparedReferenceImage> {\n if (reference.kind !== \"figma-url\") {\n throw new AppError(`Unsupported reference input kind for Figma provider: ${reference.kind}`, {\n code: \"reference_provider_kind_mismatch\",\n });\n }\n\n const token = process.env.FIGMA_TOKEN;\n\n if (!token) {\n throw new AppError(\"FIGMA_TOKEN is required when --reference points to a Figma URL.\", {\n code: \"figma_token_missing\",\n });\n }\n\n const endpoint = new URL(`/v1/images/${reference.fileKey}`, figmaApiBaseUrl());\n endpoint.searchParams.set(\"ids\", reference.nodeId);\n endpoint.searchParams.set(\"format\", \"png\");\n endpoint.searchParams.set(\"scale\", \"1\");\n\n const payload = await fetchFigmaJson<FigmaImagesResponse>(\n endpoint,\n token,\n `Failed to export Figma node image for ${reference.nodeId}.`,\n );\n const imageUrl = payload.images?.[reference.nodeId];\n\n if (!imageUrl) {\n throw new AppError(`Figma did not return an image URL for node ${reference.nodeId}.`, {\n exitCode: 3,\n recommendation: \"needs_human_review\",\n severity: \"high\",\n code: \"figma_image_missing\",\n });\n }\n\n const buffer = await fetchBinary(\n imageUrl,\n `Failed to download exported Figma image for ${reference.nodeId}.`,\n );\n const prepared = await bufferToNormalizedPng(buffer, outputPath);\n\n return {\n ...prepared,\n transport: \"figma-rest\",\n };\n }\n}\n\nfunction figmaApiBaseUrl(): string {\n return process.env.FIGMA_API_BASE_URL ?? DEFAULT_FIGMA_API_BASE_URL;\n}\n\nasync function fetchFigmaJson<TPayload>(\n url: URL,\n token: string,\n failureMessage: string,\n): Promise<TPayload> {\n const response = await fetchWithTimeout(\n url,\n {\n headers: {\n \"X-Figma-Token\": token,\n },\n },\n failureMessage,\n );\n\n try {\n return (await response.json()) as TPayload;\n } catch (error) {\n throw new AppError(`${failureMessage} Invalid JSON response from Figma API.`, {\n code: \"figma_response_invalid_json\",\n cause: error,\n });\n }\n}\n\nasync function fetchBinary(url: string, failureMessage: string): Promise<Buffer> {\n const response = await fetchWithTimeout(url, undefined, failureMessage);\n return Buffer.from(await response.arrayBuffer());\n}\n\nasync function fetchWithTimeout(\n input: URL | string,\n init: RequestInit | undefined,\n failureMessage: string,\n): Promise<Response> {\n try {\n const response = await fetch(input, {\n ...init,\n signal: AbortSignal.timeout(DEFAULT_RESOURCE_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new AppError(`${failureMessage} Received ${response.status} ${response.statusText}.`, {\n code: \"remote_request_failed\",\n });\n }\n\n return response;\n } catch (error) {\n if (error instanceof AppError) {\n throw error;\n }\n\n throw new AppError(`${failureMessage} ${ensureError(error).message}`, {\n code: \"remote_request_failed\",\n cause: error,\n });\n }\n}\n","import {\n DEFAULT_FIGMA_MCP_DESKTOP_URL,\n DEFAULT_FIGMA_MCP_REMOTE_URL,\n DEFAULT_FIGMA_SOURCE,\n} from \"../config/defaults.js\";\nimport type { ParsedReferenceInput, PreparedReferenceImage } from \"../types/internal.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\nimport { FigmaMcpReferenceProvider } from \"./figma-mcp-reference-provider.js\";\nimport { FigmaRestReferenceProvider } from \"./figma-rest-reference-provider.js\";\nimport type { ReferenceProvider } from \"./provider.js\";\n\ntype FigmaSourceMode = \"auto\" | \"mcp\" | \"rest\";\n\ninterface AttemptFailure {\n label: string;\n error: AppError;\n}\n\nexport class FigmaReferenceProvider implements ReferenceProvider {\n readonly kind = \"figma-url\" as const;\n\n async prepare(\n reference: ParsedReferenceInput,\n outputPath: string,\n ): Promise<PreparedReferenceImage> {\n const providers = buildProviders();\n const failures: AttemptFailure[] = [];\n\n for (const provider of providers) {\n try {\n return await provider.instance.prepare(reference, outputPath);\n } catch (error) {\n const appError =\n error instanceof AppError\n ? error\n : new AppError(ensureError(error).message, {\n cause: error,\n code: \"figma_reference_attempt_failed\",\n });\n\n failures.push({\n label: provider.label,\n error: appError,\n });\n }\n }\n\n throw buildFailureFromAttempts(failures);\n }\n}\n\nfunction buildProviders(): Array<{ instance: ReferenceProvider; label: string }> {\n const mode = resolveFigmaSourceMode();\n const desktopProvider = new FigmaMcpReferenceProvider({\n serverUrl: process.env.PEYE_FIGMA_MCP_DESKTOP_URL ?? DEFAULT_FIGMA_MCP_DESKTOP_URL,\n transport: \"figma-mcp-desktop\",\n });\n const remoteProvider = new FigmaMcpReferenceProvider({\n serverUrl: process.env.PEYE_FIGMA_MCP_REMOTE_URL ?? DEFAULT_FIGMA_MCP_REMOTE_URL,\n transport: \"figma-mcp-remote\",\n });\n const restProvider = new FigmaRestReferenceProvider();\n\n if (mode === \"rest\") {\n return [{ instance: restProvider, label: \"Figma REST\" }];\n }\n\n if (mode === \"mcp\") {\n return [\n { instance: desktopProvider, label: \"Figma MCP desktop\" },\n { instance: remoteProvider, label: \"Figma MCP remote\" },\n ];\n }\n\n return [\n { instance: desktopProvider, label: \"Figma MCP desktop\" },\n { instance: remoteProvider, label: \"Figma MCP remote\" },\n { instance: restProvider, label: \"Figma REST\" },\n ];\n}\n\nfunction resolveFigmaSourceMode(): FigmaSourceMode {\n const mode = process.env.PEYE_FIGMA_SOURCE ?? DEFAULT_FIGMA_SOURCE;\n\n if (mode === \"auto\" || mode === \"mcp\" || mode === \"rest\") {\n return mode;\n }\n\n throw new AppError(\n `Invalid PEYE_FIGMA_SOURCE value \"${mode}\". Expected one of: auto, mcp, rest.`,\n {\n code: \"figma_source_invalid\",\n },\n );\n}\n\nfunction buildFailureFromAttempts(failures: AttemptFailure[]): AppError {\n if (failures.length === 1) {\n return failures[0].error;\n }\n\n const preferredError =\n failures.find(\n (failure) =>\n failure.error.code === \"figma_mcp_invalid_response\" ||\n failure.error.code === \"figma_image_missing\",\n )?.error ?? failures.at(-1)?.error;\n\n const nextSteps = [\n \"Start the Figma desktop app MCP server.\",\n \"Run peye in an interactive terminal to authorize remote Figma MCP.\",\n \"Set FIGMA_TOKEN to enable REST fallback.\",\n ];\n const attemptLines = failures.map((failure) => `- ${failure.label}: ${failure.error.message}`);\n\n return new AppError(\n [\n preferredError?.message ?? \"Failed to resolve the Figma reference.\",\n \"Reference lookup attempts:\",\n ...attemptLines,\n \"Next steps:\",\n ...nextSteps.map((step) => `- ${step}`),\n ].join(\"\\n\"),\n {\n exitCode: preferredError?.exitCode ?? 3,\n recommendation: preferredError?.recommendation ?? \"needs_human_review\",\n severity: preferredError?.severity ?? \"high\",\n code: preferredError?.code ?? \"figma_reference_unavailable\",\n cause: preferredError,\n },\n );\n}\n","import type { ParsedReferenceInput, PreparedReferenceImage } from \"../types/internal.js\";\nimport { normalizeImageToPng } from \"../io/image.js\";\nimport { AppError, ensureError } from \"../utils/errors.js\";\nimport type { ReferenceProvider } from \"./provider.js\";\n\nexport class LocalReferenceProvider implements ReferenceProvider {\n readonly kind = \"path\" as const;\n\n async prepare(\n reference: ParsedReferenceInput,\n outputPath: string,\n ): Promise<PreparedReferenceImage> {\n try {\n const prepared = await normalizeImageToPng(reference.resolved, outputPath);\n return {\n ...prepared,\n transport: \"path\",\n };\n } catch (error) {\n throw new AppError(\n `Failed to normalize reference image: ${reference.resolved}. ${ensureError(error).message}`,\n {\n code: \"reference_image_normalization_failed\",\n cause: error,\n },\n );\n }\n }\n}\n","import type { ParsedReferenceInput, PreparedReferenceImage } from \"../types/internal.js\";\nimport { AppError } from \"../utils/errors.js\";\nimport { FigmaReferenceProvider } from \"./figma-reference-provider.js\";\nimport { LocalReferenceProvider } from \"./local-reference-provider.js\";\nimport type { ReferenceProvider } from \"./provider.js\";\n\nconst providers = new Map<ParsedReferenceInput[\"kind\"], ReferenceProvider>([\n [\"figma-url\", new FigmaReferenceProvider()],\n [\"path\", new LocalReferenceProvider()],\n]);\n\nexport async function materializeReferenceImage(\n reference: ParsedReferenceInput,\n outputPath: string,\n): Promise<PreparedReferenceImage> {\n const provider = providers.get(reference.kind);\n\n if (!provider) {\n throw new AppError(`No reference provider registered for ${reference.kind}.`, {\n code: \"reference_provider_missing\",\n });\n }\n\n return provider.prepare(reference, outputPath);\n}\n","export const COMPARE_MODES = [\"all\", \"pixel\", \"layout\", \"color\"] as const;\nexport const ANALYSIS_MODES = [\"dom-elements\", \"visual-clusters\"] as const;\nexport const FINDING_SIGNAL_CODES = [\n \"probable_text_clipping\",\n \"possible_capture_crop\",\n \"possible_viewport_mismatch\",\n] as const;\nexport const SIGNAL_CONFIDENCES = [\"low\", \"medium\", \"high\"] as const;\n\nexport type CompareMode = (typeof COMPARE_MODES)[number];\nexport type AnalysisMode = (typeof ANALYSIS_MODES)[number];\nexport type FindingSignalCode = (typeof FINDING_SIGNAL_CODES)[number];\nexport type SignalConfidence = (typeof SIGNAL_CONFIDENCES)[number];\n\nexport type Recommendation =\n | \"pass\"\n | \"pass_with_tolerated_differences\"\n | \"retry_fix\"\n | \"needs_human_review\";\n\nexport type Severity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\nexport type RegionKind = \"pixel\" | \"color\" | \"layout\" | \"mixed\" | \"dimension\";\nexport type InputSourceKind = \"url\" | \"path\" | \"figma-url\";\nexport type ReferenceTransport = \"figma-mcp-desktop\" | \"figma-mcp-remote\" | \"figma-rest\" | \"path\";\nexport type FindingSource = \"dom-element\" | \"visual-cluster\";\nexport type IssueType = \"position\" | \"spacing\" | \"size\" | \"color\" | \"style\" | \"missing_or_extra\";\n\nexport interface Viewport {\n width: number;\n height: number;\n}\n\nexport interface BoundingBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface DimensionMismatch {\n widthDelta: number;\n heightDelta: number;\n aspectRatioDelta: number;\n hasMismatch: boolean;\n}\n\nexport interface ImageDimensionsReport {\n preview: Viewport | null;\n reference: Viewport | null;\n canvas: Viewport | null;\n}\n\nexport interface MetricsReport {\n mismatchPixels: number;\n mismatchPercent: number;\n meanColorDelta: number | null;\n maxColorDelta: number | null;\n structuralMismatchPercent: number | null;\n dimensionMismatch: DimensionMismatch;\n findingsCount: number;\n affectedElementCount: number;\n}\n\nexport interface CompareThresholds {\n pass: number;\n tolerated: number;\n retry: number;\n}\n\nexport interface InputSourceReport {\n input: string;\n kind: InputSourceKind;\n resolved: string;\n selector: string | null;\n}\n\nexport interface ReferenceInputSourceReport extends InputSourceReport {\n transport: ReferenceTransport | null;\n}\n\nexport interface ArtifactReport {\n reference: string | null;\n preview: string | null;\n overlay: string | null;\n diff: string | null;\n heatmap: string | null;\n report: string;\n}\n\nexport interface SummaryReport {\n recommendation: Recommendation;\n severity: Severity;\n reason: string;\n}\n\nexport interface ErrorReport {\n code: string;\n message: string;\n exitCode: number;\n}\n\nexport interface FindingElementReport {\n tag: string;\n selector: string;\n role: string | null;\n textSnippet: string | null;\n bbox: BoundingBox;\n}\n\nexport interface FindingSignalReport {\n code: FindingSignalCode;\n confidence: SignalConfidence;\n message: string;\n}\n\nexport interface FindingReport {\n id: string;\n source: FindingSource;\n kind: RegionKind;\n severity: Severity;\n summary: string;\n bbox: BoundingBox;\n regionCount: number;\n mismatchPixels: number;\n mismatchPercentOfCanvas: number;\n issueTypes: IssueType[];\n signals: FindingSignalReport[];\n hotspots: BoundingBox[];\n element: FindingElementReport | null;\n}\n\nexport interface SeverityRollup {\n severity: Severity;\n count: number;\n}\n\nexport interface KindRollup {\n kind: RegionKind;\n count: number;\n}\n\nexport interface TagRollup {\n tag: string;\n count: number;\n}\n\nexport interface RollupsReport {\n bySeverity: SeverityRollup[];\n byKind: KindRollup[];\n byTag: TagRollup[];\n rawRegionCount: number;\n findingsCount: number;\n affectedElementCount: number;\n omittedFindings: number;\n}\n\nexport interface CompareReport {\n analysisMode: AnalysisMode;\n summary: SummaryReport;\n inputs: {\n preview: InputSourceReport;\n reference: ReferenceInputSourceReport;\n viewport: Viewport | null;\n mode: CompareMode;\n fullPage: boolean;\n };\n images: ImageDimensionsReport;\n metrics: MetricsReport;\n rollups: RollupsReport;\n findings: FindingReport[];\n artifacts: ArtifactReport;\n error: ErrorReport | null;\n}\n\nexport interface CompareCommandOptions {\n preview: string;\n reference: string;\n output: string;\n viewport?: string;\n mode: CompareMode;\n selector?: string;\n fullPage: boolean;\n thresholdPass: number;\n thresholdTolerated: number;\n thresholdRetry: number;\n}\n"],"mappings":"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","names":["path","path","path","path","writeFile","path","path","writeFile","path","viewport","path","writeFile","path","sharp","sharp","path","writeFile","fetchWithTimeout","providers","path","program","path"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@americano98/peye",
3
+ "version": "0.1.0",
4
+ "description": "Standalone CLI for visual diffing UI screenshots against Figma references.",
5
+ "type": "module",
6
+ "packageManager": "pnpm@10.11.0",
7
+ "bin": {
8
+ "peye": "dist/bin.js"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "engines": {
17
+ "node": ">=22"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "clean": "rm -rf coverage dist test-output peye-output",
22
+ "dev": "tsx src/cli/bin.ts",
23
+ "format": "prettier . --write",
24
+ "format:check": "prettier . --check",
25
+ "lint": "eslint .",
26
+ "lint:fix": "eslint . --fix",
27
+ "prepack": "pnpm check",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "typecheck": "tsc --noEmit",
31
+ "check": "pnpm format:check && pnpm typecheck && pnpm lint && pnpm test && pnpm build"
32
+ },
33
+ "keywords": [
34
+ "cli",
35
+ "visual-diff",
36
+ "figma",
37
+ "playwright",
38
+ "pixelmatch"
39
+ ],
40
+ "homepage": "https://github.com/americano98/peye#readme",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/americano98/peye.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/americano98/peye/issues"
47
+ },
48
+ "license": "MIT",
49
+ "dependencies": {
50
+ "@modelcontextprotocol/sdk": "1.27.1",
51
+ "commander": "^14.0.3",
52
+ "pixelmatch": "7.1.0",
53
+ "playwright": "1.58.2",
54
+ "sharp": "0.34.5"
55
+ },
56
+ "devDependencies": {
57
+ "@eslint/js": "10.0.1",
58
+ "@types/node": "^22.19.15",
59
+ "eslint": "10.0.3",
60
+ "eslint-config-prettier": "10.1.8",
61
+ "globals": "17.4.0",
62
+ "prettier": "3.8.1",
63
+ "tsup": "8.5.1",
64
+ "tsx": "4.21.0",
65
+ "typescript": "5.9.3",
66
+ "typescript-eslint": "8.57.1",
67
+ "vitest": "^4.1.0"
68
+ }
69
+ }