@vizzly-testing/cli 0.35.3-beta.1 → 0.35.3-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +8 -3
  2. package/dist/api/endpoints.js +1 -46
  3. package/dist/api/index.js +1 -1
  4. package/dist/cli.js +5 -5
  5. package/dist/commands/api.js +3 -3
  6. package/dist/commands/builds.js +12 -15
  7. package/dist/commands/comparisons.js +7 -9
  8. package/dist/commands/context.js +10 -20
  9. package/dist/commands/init.js +62 -13
  10. package/dist/commands/review.js +122 -35
  11. package/dist/commands/run.js +1 -3
  12. package/dist/commands/status.js +35 -79
  13. package/dist/commands/upload.js +1 -1
  14. package/dist/context/local-workspace-provider.js +36 -126
  15. package/dist/reporter/reporter-bundle.iife.js +49 -81
  16. package/dist/server/handlers/tdd-handler.js +2 -7
  17. package/dist/server/routers/dashboard.js +5 -1
  18. package/dist/tdd/runtime-context.js +0 -2
  19. package/dist/tdd/services/comparison-service.js +36 -76
  20. package/dist/tdd/tdd-service.js +7 -205
  21. package/dist/types/index.d.ts +1 -1
  22. package/dist/uploader/core.js +7 -8
  23. package/dist/utils/visual-context-normalizers.js +86 -139
  24. package/package.json +4 -4
  25. package/skills/vizzly/SKILL.md +42 -52
  26. package/skills/vizzly/references/cli-context.md +49 -52
  27. package/skills/vizzly/references/dynamic-content.md +18 -29
  28. package/skills/vizzly/references/sdks.md +20 -28
  29. package/skills/vizzly/references/setup-ci.md +18 -42
  30. package/dist/tdd/core/hotspot-coverage.js +0 -112
  31. package/dist/tdd/core/region-coverage.js +0 -203
  32. package/dist/tdd/metadata/hotspot-metadata.js +0 -93
  33. package/dist/tdd/metadata/region-metadata.js +0 -56
  34. package/skills/vizzly/agents/openai.yaml +0 -4
@@ -1,16 +1,25 @@
1
- # CLI And Context
1
+ # CLI Context
2
2
 
3
- Use the repository's existing CLI invocation. The examples use `vizzly` for
4
- brevity; substitute the repository's package script or package-manager command
5
- when needed.
3
+ Use the repository's established CLI invocation and existing authentication.
4
+ If cloud authentication is unavailable, report the blocker. Do not start an
5
+ interactive login unless setup is in scope.
6
6
 
7
- Use existing authentication and project configuration. If cloud authentication
8
- is missing, report the blocker. Do not start an interactive login or change
9
- credentials unless the task includes setup.
7
+ ## Choose The Evidence
10
8
 
11
- ## Inspect Existing Local Evidence
9
+ Use an ID supplied by the task. If no cloud build is supplied, list recent
10
+ builds and select the one matching the branch, commit, or pull request:
12
11
 
13
- Request structured local evidence with both `--agent` and `--json`:
12
+ ```bash
13
+ vizzly builds --branch <branch> --limit 5 --json
14
+ vizzly status <build-id> --json
15
+ vizzly context build <build-id> --source cloud --agent --json
16
+ ```
17
+
18
+ Use status for lifecycle facts and build context for visual evidence. Do not
19
+ assume the first returned comparison is the most important; preserve API order
20
+ and inspect the records relevant to the task.
21
+
22
+ For saved local evidence:
14
23
 
15
24
  ```bash
16
25
  vizzly context build current --source local --agent --json
@@ -18,83 +27,71 @@ vizzly context screenshot "<screenshot-name>" --source local --json
18
27
  vizzly context review-queue --source local --json
19
28
  ```
20
29
 
21
- Pin hand-written local drill-downs with `--source local`. Without it, automatic
22
- source resolution may fall back to cloud data when a local item is unavailable.
23
-
24
- Local context reads persisted `.vizzly` artifacts. Confirm that their build,
25
- branch, timestamp, and baseline match the task before treating them as current.
30
+ Confirm the stored build, branch, timestamp, and baseline are current enough
31
+ for the task.
26
32
 
27
- ## Generate Fresh Local Evidence
33
+ ## Generate Fresh Evidence
28
34
 
29
- For a one-off run, let Vizzly own the complete local session:
35
+ For one run, let Vizzly own the local session:
30
36
 
31
37
  ```bash
32
38
  vizzly tdd run "<existing visual test command>" --no-open
33
- vizzly context build current --source local --agent --json
34
39
  ```
35
40
 
36
- For repeated test runs, start the detached daemon once:
41
+ For repeated runs, start the detached daemon once:
37
42
 
38
43
  ```bash
39
44
  vizzly tdd start --json
40
45
  vizzly tdd status --json
41
46
  <existing visual test command>
42
- vizzly context build current --source local --agent --json
43
47
  vizzly tdd stop --json
44
48
  ```
45
49
 
46
- Treat `tdd run` and `tdd start` as alternatives. Do not shell-background
47
- `tdd start`; it already launches a detached daemon. Stop only a server started
48
- for the current task, and reuse the printed port for status or stop commands
49
- when Vizzly selects a non-default port.
50
+ `tdd run` and `tdd start` are alternatives. Stop only a daemon started for the
51
+ current task.
50
52
 
51
- ## Inspect Cloud Evidence
52
-
53
- When the task already has a build ID:
53
+ When a cloud build is in scope:
54
54
 
55
55
  ```bash
56
- vizzly status <build-id> --json
56
+ vizzly run "<existing visual test command>" --wait --json
57
57
  vizzly context build <build-id> --source cloud --agent --json
58
58
  ```
59
59
 
60
- Use status for server-owned lifecycle, processing, comparison, and review
61
- facts. Use build context for visual debugging.
60
+ ## Inspect A Comparison
62
61
 
63
- When creating a cloud build is in scope, wrap the repository's existing test
64
- command:
62
+ Follow the build response's `suggested_commands`. The direct form is:
65
63
 
66
64
  ```bash
67
- vizzly run "<existing visual test command>" --wait --json
68
- vizzly context build <build-id> --source cloud --agent --json
65
+ vizzly context comparison <comparison-id> --source <local-or-cloud> --agent --json
66
+ vizzly context comparison <comparison-id> --source <local-or-cloud> --agent --include diffs --json
69
67
  ```
70
68
 
71
- ## Read And Drill Into Evidence
69
+ Open all three images together. Prefer `original_url` and fall back to `url`:
72
70
 
73
- For each evidence record:
71
+ - Current: `comparison.screenshot.original_url` or
72
+ `comparison.screenshot.url`
73
+ - Baseline: `comparison.baseline.original_url` or `comparison.baseline.url`
74
+ - Diff: `comparison.analysis.diff_image_url`
74
75
 
75
- 1. Inspect the current, baseline, and diff images with an available harness
76
- capability. State the limitation if an image cannot be accessed.
77
- 2. Read render metadata, review state, and compact Honeydiff diagnostics next
78
- to the images.
79
- 3. Run the returned `suggested_commands` instead of reconstructing identifiers
80
- or URLs.
81
- 4. Add `--include diffs` only when raw Honeydiff region geometry is needed.
82
- Request comments only when human review context matters.
76
+ Then compare the visible change with diff regions, fingerprint, and the
77
+ separate `similar_by_fingerprint` and `recent_by_name` history streams.
78
+ Previous review decisions help explain recurring evidence but do not decide the
79
+ current review.
83
80
 
84
- Useful manual drill-downs are:
81
+ Useful supporting commands:
85
82
 
86
83
  ```bash
87
- vizzly context comparison <comparison-id> --source <local-or-cloud> --agent --json
88
84
  vizzly context screenshot "<screenshot-name>" --source <local-or-cloud> --json
89
85
  vizzly context similar <fingerprint-hash> --source cloud --json
90
86
  vizzly context review-queue --source <local-or-cloud> --json
91
87
  ```
92
88
 
93
- Use the source from the evidence you are inspecting in place of
94
- `<local-or-cloud>`. `context similar` is cloud-only. Keep missing values
95
- unknown, and do not turn metadata into a visual conclusion when the underlying
96
- images are unavailable.
89
+ Use `--include diffs` only when compact diagnostics are insufficient. Request
90
+ comments only when human review context matters.
91
+
92
+ ## Continue Without Guessing
97
93
 
98
- When a build has more than 10 actionable records, run its returned next-page
99
- command. The command uses `--offset` to preserve API order without pulling the
100
- full build context into the agent handoff.
94
+ Run returned `suggested_commands` rather than reconstructing IDs, sources, or
95
+ pagination. When more evidence exists, the next-page command carries the API's
96
+ opaque `--cursor`; do not edit or interpret it. Keep follow-up commands pinned
97
+ to the source that produced the evidence.
@@ -1,39 +1,28 @@
1
1
  # Dynamic Content
2
2
 
3
- Treat dates, timers, randomized data, API-backed content, generated images, and
4
- responsive text as possible causes of change, not automatic explanations.
3
+ Dates, timers, random data, API content, generated images, and responsive text
4
+ can cause a diff. They are possible explanations, not conclusions.
5
5
 
6
6
  ## Diagnose Before Tuning
7
7
 
8
- 1. Inspect screenshot history and the actual image evidence:
8
+ 1. Inspect the actual images and screenshot history:
9
9
 
10
10
  ```bash
11
11
  vizzly context screenshot "<screenshot-name>" --source <local-or-cloud> --json
12
12
  ```
13
13
 
14
- 2. Replace `<local-or-cloud>` with the source of the evidence being diagnosed.
15
- Record the observed region, recurrence, render metadata, and whether the
16
- same change appears across builds or variants.
17
- 3. Check whether deterministic fixtures can remove irrelevant variation.
18
- 4. Treat hotspots and confirmed regions as server- or user-owned evidence.
19
- They can affect comparison results, but this CLI exposes them for inspection
20
- rather than authoring.
21
- 5. Preserve existing per-screenshot `threshold` and `minClusterSize` values
22
- unless the task and repeated evidence justify a change. Do not invent new
23
- tolerance values from one diff.
24
-
25
- ## Avoid
26
-
27
- - Raising a global threshold for one unstable area.
28
- - Masking a whole page when only a small region changes.
29
- - Assuming a recurring change is harmless without inspecting it.
30
- - Ignoring structural movement because a region contains dynamic content.
31
- - Claiming a cause when only metadata, rather than images or history, is
32
- available.
33
-
34
- ## Report Findings
35
-
36
- State the observed change first. Then distinguish a likely explanation—such as
37
- fixture drift, content disappearance, layout shift, capture timing, or baseline
38
- mismatch—from unresolved alternatives. Include the screenshot identity and the
39
- context command or link used.
14
+ 2. Record the visible region, recurrence, render metadata, and whether the same
15
+ change appears across builds or variants.
16
+ 3. Prefer deterministic fixtures when they can remove irrelevant variation.
17
+ 4. Use diff regions only to locate changed pixels; they do not approve a
18
+ comparison or explain why it changed.
19
+ 5. Preserve `threshold` and `minClusterSize` unless repeated evidence
20
+ justifies a change.
21
+
22
+ Avoid broad masks, global threshold changes for one region, and claims based on
23
+ metadata alone. A recurring change can still be a bug, especially when content
24
+ movement affects nearby layout.
25
+
26
+ Report the observed change first. Label fixture drift, layout shift, capture
27
+ timing, or baseline mismatch as a possible cause until the evidence establishes
28
+ it.
@@ -1,9 +1,10 @@
1
- # SDK Capture Patterns
1
+ # SDK Capture
2
2
 
3
- Prefer the repository's existing Vizzly integration and user journey. Add a new
4
- capture path only when the task requires it.
3
+ Use the repository's existing Vizzly integration and user journey. The
4
+ JavaScript example applies only when no framework-specific capture path already
5
+ owns the workflow.
5
6
 
6
- ## JavaScript Client
7
+ ## JavaScript
7
8
 
8
9
  ```javascript
9
10
  import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
@@ -13,37 +14,28 @@ await vizzlyScreenshot('settings-profile-edit-mode', screenshot);
13
14
  ```
14
15
 
15
16
  `vizzlyScreenshot(name, image, options)` accepts PNG bytes or a file path.
16
- Available options include:
17
+ Options include `properties`, `threshold`, `minClusterSize`, and
18
+ `fullPage`. Preserve existing tuning unless visual evidence justifies changing
19
+ it.
17
20
 
18
- - `properties`: metadata attached to the screenshot.
19
- - `threshold`: per-screenshot CIEDE2000 Delta E tolerance.
20
- - `minClusterSize`: minimum changed-pixel cluster size.
21
- - `fullPage`: whether the screenshot represents a full-page capture.
21
+ ## Keep Identity Stable
22
22
 
23
- Do not add arbitrary tuning values. Preserve the repository's existing values
24
- unless visual evidence justifies changing them.
23
+ Use a descriptive name. Identity always includes the name, viewport width, and
24
+ browser. Configured `signatureProperties` add custom identity fields; other
25
+ properties are metadata.
25
26
 
26
- ## Screenshot Identity
27
+ Do not assume theme, locale, or state creates a separate baseline unless the
28
+ configuration says so. Avoid generic names such as `screenshot1` and names
29
+ with slashes.
27
30
 
28
- Use a stable, descriptive name. Vizzly's signature always includes the name,
29
- viewport width, and browser. Only properties named in the project's
30
- `signatureProperties` configuration participate in baseline identity.
31
+ ## Follow Existing Integrations
31
32
 
32
- Treat other `properties` as metadata. Do not assume values such as theme,
33
- locale, or state create separate baselines unless the configuration says so.
34
-
35
- ## Existing Integrations
36
-
37
- - Use the Vizzly Vitest matcher when the project already configures the plugin:
33
+ - Keep the Vizzly Vitest matcher when it is already configured:
38
34
 
39
35
  ```javascript
40
36
  await expect(page).toMatchScreenshot('hero-section.png');
41
37
  ```
42
38
 
43
- - Prefer existing Storybook, static-site, or Ember capture flows over adding a
44
- parallel Playwright path.
45
- - For Swift/XCTest, inspect the repository's Vizzly Swift package documentation
46
- and existing `VizzlyXCTest` usage before changing capture code.
47
-
48
- Use properties for searchable metadata and configured variants. Avoid generic
49
- names such as `screenshot1` or `test`, and avoid names with slashes.
39
+ - Prefer existing Storybook, static-site, Ember, or Swift capture flows over a
40
+ parallel test path.
41
+ - Inspect the repository's integration setup before changing capture code.
@@ -1,10 +1,10 @@
1
1
  # Setup And CI
2
2
 
3
- Use this reference only when the user asks to initialize Vizzly, change CI, or
4
- troubleshoot configuration. These workflows mutate project files or external
5
- build state.
3
+ Use this reference only when the task includes initialization, CI changes, or
4
+ configuration troubleshooting. These workflows mutate files or external build
5
+ state.
6
6
 
7
- ## Local Setup
7
+ ## Initialize
8
8
 
9
9
  Initialize only with authorization:
10
10
 
@@ -12,57 +12,33 @@ Initialize only with authorization:
12
12
  vizzly init
13
13
  ```
14
14
 
15
- After setup, choose one local execution mode:
16
-
17
- ```bash
18
- vizzly tdd run "<existing visual test command>" --no-open
19
- ```
20
-
21
- or:
22
-
23
- ```bash
24
- vizzly tdd start --json
25
- <existing visual test command>
26
- vizzly tdd stop --json
27
- ```
28
-
29
- Do not run `tdd start` before `tdd run`; both own a local TDD server lifecycle.
15
+ Use [CLI context](cli-context.md) for local evidence and TDD lifecycle commands.
30
16
 
31
17
  ## Cloud CI
32
18
 
33
- Use a project-scoped token supplied by the user's existing secret-management
34
- system. Never print it, write it into the repository, or replace working
35
- credentials while debugging.
36
-
37
- Wrap the CI job's existing visual test command:
19
+ Use a project-scoped token from the repository's existing secret system. Never
20
+ print it or write it into the repository.
38
21
 
39
22
  ```bash
40
23
  vizzly run "<existing visual test command>" --wait --json
41
24
  ```
42
25
 
43
- ## Parallel CI
44
-
45
- Give every shard in one build the same parallel ID, unique to that workflow
46
- attempt. Run all shards without `--wait`, then finalize that shared ID once
47
- after every shard finishes:
26
+ For parallel CI, give every shard the same workflow-specific parallel ID. Run
27
+ shards without `--wait`, then finalize once after all shards finish:
48
28
 
49
29
  ```bash
50
30
  vizzly run "<shard test command>" --parallel-id "<shared-ci-run-id>" --json
51
31
  vizzly finalize "<shared-ci-run-id>" --json
52
32
  ```
53
33
 
54
- Do not create a different parallel ID per shard, and do not wait for a parallel
55
- build to complete before it has been finalized. Use one finalizer rather than
56
- having every shard race to finalize the build.
57
-
58
34
  ## Troubleshoot
59
35
 
60
- - Run `vizzly doctor` for local configuration checks.
61
- - Run `vizzly tdd status --json` for a local daemon started by the task.
62
- - Run `vizzly status <build-id> --json` for cloud lifecycle facts.
63
- - Run `vizzly context build <build-id> --source cloud --agent --json` for visual
64
- evidence.
65
- - If screenshots are absent, verify the existing SDK or integration, the test
66
- path that should capture them, and the active local or cloud session.
67
- - If authentication is absent, report it rather than initiating login unless
68
- setup is explicitly in scope.
36
+ - `vizzly doctor`: local configuration
37
+ - `vizzly tdd status --json`: a local daemon started by the task
38
+ - `vizzly status <build-id> --json`: cloud lifecycle
39
+ - `vizzly context build <build-id> --source cloud --agent --json`: visual
40
+ evidence
41
+
42
+ If screenshots are absent, verify the existing integration, the test path that
43
+ should capture them, and the active session. If authentication is absent,
44
+ report it rather than logging in unless setup is in scope.
@@ -1,112 +0,0 @@
1
- /**
2
- * Hotspot Coverage Calculation
3
- *
4
- * Pure functions for calculating how much of a visual diff falls within
5
- * "hotspot" regions - areas of the UI that frequently change due to dynamic
6
- * content (timestamps, animations, etc.).
7
- *
8
- * Uses 1D Y-coordinate matching (same algorithm as cloud).
9
- */
10
-
11
- /**
12
- * Calculate what percentage of diff falls within hotspot regions
13
- *
14
- * @param {Array} diffClusters - Array of diff clusters from honeydiff
15
- * @param {Object} hotspotAnalysis - Hotspot data with regions array
16
- * @returns {{ coverage: number, linesInHotspots: number, totalLines: number }}
17
- */
18
- export function calculateHotspotCoverage(diffClusters, hotspotAnalysis) {
19
- if (!diffClusters || diffClusters.length === 0) {
20
- return {
21
- coverage: 0,
22
- linesInHotspots: 0,
23
- totalLines: 0
24
- };
25
- }
26
- if (!hotspotAnalysis?.regions || hotspotAnalysis.regions.length === 0) {
27
- return {
28
- coverage: 0,
29
- linesInHotspots: 0,
30
- totalLines: 0
31
- };
32
- }
33
-
34
- // Extract Y-coordinates (diff lines) from clusters
35
- // Each cluster has a boundingBox with y and height
36
- let diffLines = [];
37
- for (let cluster of diffClusters) {
38
- if (cluster.boundingBox) {
39
- let {
40
- y,
41
- height
42
- } = cluster.boundingBox;
43
- // Add all Y lines covered by this cluster
44
- for (let line = y; line < y + height; line++) {
45
- diffLines.push(line);
46
- }
47
- }
48
- }
49
- if (diffLines.length === 0) {
50
- return {
51
- coverage: 0,
52
- linesInHotspots: 0,
53
- totalLines: 0
54
- };
55
- }
56
-
57
- // Remove duplicates and sort
58
- diffLines = [...new Set(diffLines)].sort((a, b) => a - b);
59
-
60
- // Check how many diff lines fall within hotspot regions
61
- let linesInHotspots = 0;
62
- for (let line of diffLines) {
63
- let inHotspot = hotspotAnalysis.regions.some(region => line >= region.y1 && line <= region.y2);
64
- if (inHotspot) {
65
- linesInHotspots++;
66
- }
67
- }
68
- let coverage = linesInHotspots / diffLines.length;
69
- return {
70
- coverage,
71
- linesInHotspots,
72
- totalLines: diffLines.length
73
- };
74
- }
75
-
76
- /**
77
- * Determine if a comparison should be filtered as "passed" based on hotspot coverage
78
- *
79
- * A diff is filtered when:
80
- * 1. Coverage is >= 80% (most diff in hotspot regions)
81
- * 2. Confidence is "high" or confidence score > 0.7
82
- *
83
- * @param {Object} hotspotAnalysis - Hotspot data with confidence info
84
- * @param {{ coverage: number }} coverageResult - Result from calculateHotspotCoverage
85
- * @returns {boolean} True if diff should be filtered as hotspot noise
86
- */
87
- export function shouldFilterAsHotspot(hotspotAnalysis, coverageResult) {
88
- if (!hotspotAnalysis || !coverageResult) {
89
- return false;
90
- }
91
- let {
92
- coverage
93
- } = coverageResult;
94
-
95
- // Need at least 80% of diff in hotspot regions
96
- if (coverage < 0.8) {
97
- return false;
98
- }
99
-
100
- // Need high confidence in the hotspot analysis
101
- let {
102
- confidence,
103
- confidenceScore
104
- } = hotspotAnalysis;
105
- if (confidence === 'high') {
106
- return true;
107
- }
108
- if (confidenceScore !== undefined && confidenceScore > 0.7) {
109
- return true;
110
- }
111
- return false;
112
- }