bruniai 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # bruniai
2
+
3
+ AI-powered visual regression testing tool - core comparison library.
4
+
5
+ This package provides the core comparison functionality for visual regression testing. It can be used standalone or as a dependency for building custom integrations (e.g., MCP servers, Next.js apps, etc.).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install bruniai
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { compareUrls } from "bruniai";
17
+
18
+ const result = await compareUrls({
19
+ baseUrl: "https://example.com",
20
+ previewUrl: "https://preview.example.com",
21
+ page: "/contact"
22
+ });
23
+
24
+ console.log(result.status); // "pass" | "fail" | "warning" | "none"
25
+ console.log(result.visual_analysis);
26
+ console.log(result.images.base_screenshot);
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### `compareUrls(input: CompareUrlsInput): Promise<CompareUrlsOutput>`
32
+
33
+ Performs a visual comparison between two URLs.
34
+
35
+ **Parameters:**
36
+ - `baseUrl` (string): Base/reference URL to compare against
37
+ - `previewUrl` (string): Preview/changed URL to analyze
38
+ - `page` (string, optional): Page path to compare (default: "/")
39
+ - `prNumber` (string, optional): PR number for metadata
40
+ - `repository` (string, optional): Repository name for metadata
41
+ - `prTitle` (string, optional): PR title for context
42
+ - `prDescription` (string, optional): PR description for context
43
+
44
+ **Returns:**
45
+ - `status`: Overall comparison status ("pass" | "fail" | "warning" | "none")
46
+ - `visual_analysis`: Detailed visual analysis result from AI
47
+ - `sections_analysis`: Formatted sections analysis text
48
+ - `images`: Object containing paths to generated screenshots and diff images
49
+
50
+ ## Requirements
51
+
52
+ - Node.js 18+
53
+ - OpenAI API key (set as `OPENAI_API_KEY` environment variable)
54
+
55
+ ## Development
56
+
57
+ ### Building
58
+
59
+ First, build the parent package to generate the dist files:
60
+
61
+ ```bash
62
+ cd ../..
63
+ npm run build
64
+ ```
65
+
66
+ Then build this package:
67
+
68
+ ```bash
69
+ npm run build
70
+ ```
71
+
72
+ ## License
73
+
74
+ MIT
75
+
@@ -0,0 +1,28 @@
1
+ import type { CompareUrlsInput, CompareUrlsOutput } from "./types.js";
2
+ /**
3
+ * Compare two URLs visually and return analysis results.
4
+ *
5
+ * This function performs a complete visual comparison workflow:
6
+ * - Creates a temporary directory for images
7
+ * - Initializes and manages Stagehand browser automation
8
+ * - Takes screenshots of both URLs
9
+ * - Generates diff images
10
+ * - Analyzes sections structure
11
+ * - Performs AI-powered visual analysis
12
+ * - Captures section screenshots
13
+ *
14
+ * @param input - Comparison input parameters
15
+ * @returns Complete analysis results with image paths
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const result = await compareUrls({
20
+ * baseUrl: "https://example.com",
21
+ * previewUrl: "https://preview.example.com",
22
+ * page: "/contact"
23
+ * });
24
+ * console.log(result.status); // "pass" | "fail" | "warning" | "none"
25
+ * ```
26
+ */
27
+ export declare function compareUrls(input: CompareUrlsInput): Promise<CompareUrlsOutput>;
28
+ //# sourceMappingURL=compare-urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-urls.d.ts","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKtE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CA4D5B"}
@@ -0,0 +1,82 @@
1
+ import { Stagehand } from "@browserbasehq/stagehand";
2
+ import { performComparison } from "../../../dist/comparison/core.js";
3
+ import { join } from "path";
4
+ import { mkdirSync, existsSync } from "fs";
5
+ import { tmpdir } from "os";
6
+ /**
7
+ * Compare two URLs visually and return analysis results.
8
+ *
9
+ * This function performs a complete visual comparison workflow:
10
+ * - Creates a temporary directory for images
11
+ * - Initializes and manages Stagehand browser automation
12
+ * - Takes screenshots of both URLs
13
+ * - Generates diff images
14
+ * - Analyzes sections structure
15
+ * - Performs AI-powered visual analysis
16
+ * - Captures section screenshots
17
+ *
18
+ * @param input - Comparison input parameters
19
+ * @returns Complete analysis results with image paths
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const result = await compareUrls({
24
+ * baseUrl: "https://example.com",
25
+ * previewUrl: "https://preview.example.com",
26
+ * page: "/contact"
27
+ * });
28
+ * console.log(result.status); // "pass" | "fail" | "warning" | "none"
29
+ * ```
30
+ */
31
+ export async function compareUrls(input) {
32
+ const { baseUrl, previewUrl, page = "/" } = input;
33
+ // Create temporary directory for images.
34
+ const imagesDir = join(tmpdir(), `bruniai-${Date.now()}`);
35
+ if (!existsSync(imagesDir)) {
36
+ mkdirSync(imagesDir, { recursive: true });
37
+ }
38
+ // Initialize Stagehand.
39
+ const stagehand = new Stagehand({
40
+ env: "LOCAL",
41
+ localBrowserLaunchOptions: {
42
+ headless: true,
43
+ },
44
+ });
45
+ try {
46
+ await stagehand.init();
47
+ // Perform the core comparison.
48
+ const result = await performComparison({
49
+ stagehand,
50
+ baseUrl,
51
+ previewUrl,
52
+ page,
53
+ imagesDir,
54
+ prNumber: input.prNumber,
55
+ repository: input.repository,
56
+ prTitle: input.prTitle,
57
+ prDescription: input.prDescription,
58
+ });
59
+ // Build output structure.
60
+ const output = {
61
+ status: result.visual_analysis.status,
62
+ visual_analysis: result.visual_analysis,
63
+ sections_analysis: result.sections_analysis,
64
+ images: {
65
+ base_screenshot: result.base_screenshot,
66
+ preview_screenshot: result.preview_screenshot,
67
+ diff_image: result.diff_image,
68
+ section_screenshots: Object.keys(result.section_screenshots).length > 0
69
+ ? Object.fromEntries(Object.entries(result.section_screenshots).map(([key, value]) => [
70
+ key,
71
+ { base: value.base, preview: value.preview },
72
+ ]))
73
+ : undefined,
74
+ },
75
+ };
76
+ return output;
77
+ }
78
+ finally {
79
+ await stagehand.close();
80
+ }
81
+ }
82
+ //# sourceMappingURL=compare-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-urls.js","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAuB;IAEvB,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;IAElD,yCAAyC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,wBAAwB;IACxB,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;QAC9B,GAAG,EAAE,OAAO;QACZ,yBAAyB,EAAE;YACzB,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,+BAA+B;QAC/B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;YACrC,SAAS;YACT,OAAO;YACP,UAAU;YACV,IAAI;YACJ,SAAS;YACT,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,aAAa,EAAE,KAAK,CAAC,aAAa;SACnC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,MAAM,MAAM,GAAsB;YAChC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,MAAM;YACrC,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,MAAM,EAAE;gBACN,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;gBAC7C,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,mBAAmB,EACjB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC;oBAChD,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAC5C,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;wBAChB,GAAG;wBACH,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;qBAC7C,CACF,CACF;oBACH,CAAC,CAAC,SAAS;aAChB;SACF,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * BruniAI - AI-powered visual regression testing tool.
3
+ *
4
+ * Core comparison library for visual regression testing.
5
+ * Provides a simple API to compare two URLs and analyze visual differences.
6
+ */
7
+ export { compareUrls } from "./compare-urls.js";
8
+ export type { CompareUrlsInput, CompareUrlsOutput, ComparisonImages, } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * BruniAI - AI-powered visual regression testing tool.
3
+ *
4
+ * Core comparison library for visual regression testing.
5
+ * Provides a simple API to compare two URLs and analyze visual differences.
6
+ */
7
+ export { compareUrls } from "./compare-urls.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { VisualAnalysisResult } from "../../../dist/vision/types.js";
2
+ /**
3
+ * Input parameters for compareUrls function.
4
+ */
5
+ export interface CompareUrlsInput {
6
+ /** Base/reference URL to compare against. */
7
+ baseUrl: string;
8
+ /** Preview/changed URL to analyze. */
9
+ previewUrl: string;
10
+ /** Page path to compare (e.g., "/" or "/about"). Defaults to "/". */
11
+ page?: string;
12
+ /** Optional PR number for metadata. */
13
+ prNumber?: string;
14
+ /** Optional repository name for metadata. */
15
+ repository?: string;
16
+ /** Optional PR title for context. */
17
+ prTitle?: string;
18
+ /** Optional PR description for context. */
19
+ prDescription?: string;
20
+ }
21
+ /**
22
+ * Image paths returned from comparison.
23
+ */
24
+ export interface ComparisonImages {
25
+ /** Path to base screenshot. */
26
+ base_screenshot: string;
27
+ /** Path to preview screenshot. */
28
+ preview_screenshot: string;
29
+ /** Path to diff image. */
30
+ diff_image: string;
31
+ /** Section screenshots keyed by section ID. */
32
+ section_screenshots?: Record<string, {
33
+ base: string;
34
+ preview: string;
35
+ }>;
36
+ }
37
+ /**
38
+ * Output structure for compareUrls function.
39
+ */
40
+ export interface CompareUrlsOutput {
41
+ /** Overall comparison status. */
42
+ status: "pass" | "fail" | "warning" | "none";
43
+ /** Visual analysis result from AI. */
44
+ visual_analysis: VisualAnalysisResult;
45
+ /** Formatted sections analysis text. */
46
+ sections_analysis: string;
47
+ /** Generated images from comparison. */
48
+ images: ComparisonImages;
49
+ }
50
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC7C,sCAAsC;IACtC,eAAe,EAAE,oBAAoB,CAAC;IACtC,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,MAAM,EAAE,gBAAgB,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "bruniai",
3
+ "version": "0.1.2",
4
+ "type": "module",
5
+ "description": "AI-powered visual regression testing tool - core comparison library",
6
+ "author": "Joao Garin",
7
+ "license": "MIT",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "dev": "tsx src/index.ts"
23
+ },
24
+ "dependencies": {
25
+ "@browserbasehq/stagehand": "^3.0.1",
26
+ "dotenv": "^16.0.0",
27
+ "pixelmatch": "^7.1.0",
28
+ "playwright": "^1.42.1",
29
+ "pngjs": "^7.0.0",
30
+ "sharp": "^0.34.5",
31
+ "uuid": "^10.0.0",
32
+ "zod": "^3.23.8"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^20.11.24",
36
+ "@types/pixelmatch": "^5.2.6",
37
+ "@types/pngjs": "^6.0.5",
38
+ "@types/uuid": "^10.0.0",
39
+ "tsx": "^4.7.0",
40
+ "typescript": "^5.5.4"
41
+ },
42
+ "peerDependencies": {
43
+ "@browserbasehq/stagehand": "^3.0.1"
44
+ }
45
+ }