@vizzly-testing/cli 0.29.6 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -6
- package/dist/api/client.js +6 -3
- package/dist/api/endpoints.js +59 -0
- package/dist/api/index.js +1 -1
- package/dist/auth/core.js +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/cli.js +206 -51
- package/dist/client/index.js +21 -29
- package/dist/commands/api.js +145 -90
- package/dist/commands/baselines.js +78 -47
- package/dist/commands/builds.js +9 -8
- package/dist/commands/comparisons.js +7 -8
- package/dist/commands/config-cmd.js +15 -7
- package/dist/commands/context.js +870 -0
- package/dist/commands/doctor.js +116 -81
- package/dist/commands/init.js +202 -201
- package/dist/commands/login.js +134 -65
- package/dist/commands/logout.js +18 -7
- package/dist/commands/preview.js +29 -57
- package/dist/commands/project.js +120 -0
- package/dist/commands/projects.js +9 -2
- package/dist/commands/review.js +236 -202
- package/dist/commands/run.js +75 -72
- package/dist/commands/status.js +228 -150
- package/dist/commands/tdd-daemon-process.js +98 -0
- package/dist/commands/tdd-daemon.js +318 -212
- package/dist/commands/tdd.js +23 -8
- package/dist/commands/upload.js +10 -9
- package/dist/commands/whoami.js +64 -26
- package/dist/config/core.js +37 -36
- package/dist/context/local-workspace-provider.js +532 -0
- package/dist/context/provider-resolver.js +36 -0
- package/dist/index.js +5 -4
- package/dist/plugin-loader.js +55 -49
- package/dist/project/core.js +2 -2
- package/dist/project/operations.js +6 -3
- package/dist/reporter/reporter-bundle.css +2 -1
- package/dist/reporter/reporter-bundle.iife.js +119 -119
- package/dist/reporter-ssr/ssr-entry.js +605 -509
- package/dist/sdk/index.js +162 -107
- package/dist/server/handlers/tdd-handler.js +30 -54
- package/dist/server/routers/assets.js +4 -0
- package/dist/server/routers/baseline.js +195 -178
- package/dist/server/routers/events.js +226 -148
- package/dist/server/routers/projects.js +14 -5
- package/dist/server/routers/screenshot.js +1 -31
- package/dist/services/build-manager.js +19 -97
- package/dist/services/config-service.js +26 -34
- package/dist/services/index.js +2 -4
- package/dist/services/static-report-generator.js +11 -12
- package/dist/services/test-runner.js +21 -27
- package/dist/tdd/core/hotspot-coverage.js +1 -1
- package/dist/tdd/index.js +1 -1
- package/dist/tdd/metadata/region-metadata.js +0 -37
- package/dist/tdd/runtime-context.js +78 -0
- package/dist/tdd/server-registry.js +38 -17
- package/dist/tdd/services/baseline-manager.js +23 -0
- package/dist/tdd/services/hotspot-service.js +1 -14
- package/dist/tdd/tdd-service.js +82 -113
- package/dist/types/client.d.ts +36 -1
- package/dist/types/index.d.ts +114 -22
- package/dist/types/sdk.d.ts +47 -7
- package/dist/uploader/core.js +5 -4
- package/dist/uploader/index.js +79 -2
- package/dist/uploader/operations.js +40 -5
- package/dist/utils/api-url.js +14 -0
- package/dist/utils/async-utils.js +26 -0
- package/dist/utils/ci-env.js +19 -12
- package/dist/utils/colors.js +46 -44
- package/dist/utils/config-loader.js +39 -65
- package/dist/utils/config-schema.js +19 -55
- package/dist/utils/fetch-utils.js +12 -5
- package/dist/utils/git.js +35 -72
- package/dist/utils/global-config.js +22 -3
- package/dist/utils/output.js +19 -7
- package/dist/utils/patterns.js +14 -0
- package/dist/utils/project-link-store.js +105 -0
- package/dist/utils/report-data.js +31 -0
- package/dist/utils/screenshot-options.js +28 -0
- package/dist/utils/secret-store.js +65 -0
- package/dist/utils/security.js +3 -2
- package/package.json +14 -11
- package/dist/services/screenshot-server.js +0 -65
- package/dist/services/server-manager.js +0 -81
- package/dist/services/uploader.js +0 -100
- package/dist/tdd/services/region-service.js +0 -75
- package/dist/utils/build-history.js +0 -103
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# Vizzly CLI
|
|
2
2
|
|
|
3
|
-
> Visual
|
|
3
|
+
> Visual review for agents and teams
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@vizzly-testing/cli)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Vizzly keeps the visual truth behind your UI: approved baselines, meaningful diffs, review state, comments, and preview links in one place. That makes it useful for humans reviewing product changes and for LLM agents that need to understand what the UI is supposed to look like before they edit it.
|
|
9
9
|
|
|
10
|
-
Unlike tools that re-render components in isolation, Vizzly captures screenshots directly from your functional tests
|
|
10
|
+
Unlike tools that re-render components in isolation, Vizzly captures screenshots directly from your functional tests: the real thing. Whether you're validating AI-generated code or testing manual changes, you get reviewed visual evidence before anything hits production.
|
|
11
11
|
|
|
12
12
|
## Why Vizzly?
|
|
13
13
|
|
|
14
|
-
**Local TDD workflow.** See changes as you type, not after CI. The `vizzly tdd` command runs a local dashboard that compares screenshots instantly
|
|
14
|
+
**Local TDD workflow.** See changes as you type, not after CI. The `vizzly tdd` command runs a local dashboard that compares screenshots instantly and exposes the current workspace as local context.
|
|
15
15
|
|
|
16
|
-
**
|
|
16
|
+
**Meaningful diff metadata.** Vizzly stores rich diff evidence: changed regions, cluster metadata, fingerprints, hotspots, confirmed regions, and image URLs. Agents can inspect what changed instead of guessing from a pass/fail label.
|
|
17
17
|
|
|
18
18
|
**Any screenshot source.** Playwright, Cypress, Puppeteer, Selenium, native mobile apps, or even design mockups. If you can capture it, Vizzly can compare it.
|
|
19
19
|
|
|
20
|
-
**
|
|
20
|
+
**Approved baselines as truth.** Cloud context carries human review state. Local context carries the downloaded or generated baseline metadata. That is the bridge between TDD locally and collaborative review in Vizzly.
|
|
21
21
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
@@ -58,6 +58,33 @@ export VIZZLY_TOKEN=your-project-token
|
|
|
58
58
|
vizzly run "npm test" --wait
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
### Visual Context For Agents
|
|
62
|
+
|
|
63
|
+
Use `vizzly context` when you want Vizzly to act like a visual context store, not just a test runner.
|
|
64
|
+
|
|
65
|
+
This is especially useful for LLM agents, automation, and quick debugging loops. Instead of
|
|
66
|
+
making a bunch of narrow API calls, you can ask for one build, comparison, screenshot, or review
|
|
67
|
+
queue bundle and get the evidence in one place.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Cloud context for a build or comparison
|
|
71
|
+
vizzly context build abc123
|
|
72
|
+
vizzly context comparison def456 --json
|
|
73
|
+
|
|
74
|
+
# Local workspace context from .vizzly/
|
|
75
|
+
vizzly context build current --source local
|
|
76
|
+
vizzly context build current --source local --agent
|
|
77
|
+
vizzly context screenshot build-detail-screenshots --source local --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`--json` is the durable automation path. `--agent` gives a compact handoff for prompt assembly and local dogfooding. Add `--full` when an agent really needs the complete build context payload, or `--include screenshots,diffs,comments` when the compact JSON needs selected detail.
|
|
81
|
+
|
|
82
|
+
Local context is read-only and file-backed. It reads your existing `.vizzly` workspace state from
|
|
83
|
+
TDD runs, including screenshots, diffs, and any saved hotspot or region metadata.
|
|
84
|
+
|
|
85
|
+
Cloud context is also read-only right now. That is intentional. It keeps the trust model simple:
|
|
86
|
+
Vizzly helps you see and inspect visual changes, while people still decide what gets approved.
|
|
87
|
+
|
|
61
88
|
## Capture Screenshots
|
|
62
89
|
|
|
63
90
|
Add screenshots to your existing tests:
|
|
@@ -116,6 +143,7 @@ export default {
|
|
|
116
143
|
| `vizzly tdd start` | Start local TDD server with dashboard |
|
|
117
144
|
| `vizzly tdd run "cmd"` | Run tests once, generate static report |
|
|
118
145
|
| `vizzly run "cmd"` | Run tests with cloud integration |
|
|
146
|
+
| `vizzly context ...` | Fetch visual context bundles for builds, comparisons, and screenshots |
|
|
119
147
|
| `vizzly upload <dir>` | Upload existing screenshots |
|
|
120
148
|
| `vizzly login` | Authenticate via browser |
|
|
121
149
|
| `vizzly doctor` | Validate local setup |
|
package/dist/api/client.js
CHANGED
|
@@ -14,6 +14,9 @@ import { buildApiUrl, buildRequestHeaders, buildUserAgent, extractErrorBody, isA
|
|
|
14
14
|
* Default API URL
|
|
15
15
|
*/
|
|
16
16
|
export const DEFAULT_API_URL = 'https://app.vizzly.dev';
|
|
17
|
+
function isProjectToken(token) {
|
|
18
|
+
return typeof token === 'string' && token.startsWith('vzt_');
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* Create an API client with the given configuration
|
|
@@ -63,7 +66,7 @@ export function createApiClient(options = {}) {
|
|
|
63
66
|
let errorBody = await extractErrorBody(response);
|
|
64
67
|
|
|
65
68
|
// Handle 401 with token refresh
|
|
66
|
-
if (shouldRetryWithRefresh(response.status, isRetry, await hasRefreshToken())) {
|
|
69
|
+
if (shouldRetryWithRefresh(response.status, isRetry, !isProjectToken(token) && (await hasRefreshToken()))) {
|
|
67
70
|
let refreshed = await attemptTokenRefresh();
|
|
68
71
|
if (refreshed) {
|
|
69
72
|
token = refreshed;
|
|
@@ -73,7 +76,7 @@ export function createApiClient(options = {}) {
|
|
|
73
76
|
|
|
74
77
|
// Auth error
|
|
75
78
|
if (isAuthError(response.status)) {
|
|
76
|
-
throw new AuthError('Invalid or expired API token.
|
|
79
|
+
throw new AuthError('Invalid or expired API token. Run "vizzly project link <org>/<project>" or set VIZZLY_TOKEN.');
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
// Other errors
|
|
@@ -119,7 +122,7 @@ export function createApiClient(options = {}) {
|
|
|
119
122
|
await saveAuthTokens({
|
|
120
123
|
accessToken: data.accessToken,
|
|
121
124
|
refreshToken: data.refreshToken,
|
|
122
|
-
expiresAt: data.expiresAt,
|
|
125
|
+
expiresAt: data.expiresAt || new Date(Date.now() + data.expiresIn * 1000).toISOString(),
|
|
123
126
|
user: auth.user
|
|
124
127
|
});
|
|
125
128
|
return data.accessToken;
|
package/dist/api/endpoints.js
CHANGED
|
@@ -210,6 +210,65 @@ export async function getComparison(client, comparisonId) {
|
|
|
210
210
|
return response.comparison;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Get build context bundle for agent and reviewer workflows
|
|
215
|
+
* @param {Object} client - API client
|
|
216
|
+
* @param {string} buildId - Build ID
|
|
217
|
+
* @returns {Promise<Object>} Build context bundle
|
|
218
|
+
*/
|
|
219
|
+
export async function getBuildContext(client, buildId) {
|
|
220
|
+
return client.request(`/api/sdk/context/builds/${buildId}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get comparison context bundle with similarity and history
|
|
225
|
+
* @param {Object} client - API client
|
|
226
|
+
* @param {string} comparisonId - Comparison ID
|
|
227
|
+
* @param {Object} options - Optional query params
|
|
228
|
+
* @returns {Promise<Object>} Comparison context bundle
|
|
229
|
+
*/
|
|
230
|
+
export async function getComparisonContext(client, comparisonId, options = {}) {
|
|
231
|
+
let endpoint = buildEndpointWithParams(`/api/sdk/context/comparisons/${comparisonId}`, options);
|
|
232
|
+
return client.request(endpoint);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get screenshot context bundle for a screenshot name
|
|
237
|
+
* @param {Object} client - API client
|
|
238
|
+
* @param {string} screenshotName - Screenshot name
|
|
239
|
+
* @param {Object} options - Optional query params
|
|
240
|
+
* @returns {Promise<Object>} Screenshot context bundle
|
|
241
|
+
*/
|
|
242
|
+
export async function getScreenshotContext(client, screenshotName, options = {}) {
|
|
243
|
+
let encodedName = encodeURIComponent(screenshotName);
|
|
244
|
+
let endpoint = buildEndpointWithParams(`/api/sdk/context/screenshots/${encodedName}`, options);
|
|
245
|
+
return client.request(endpoint);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get project-scoped similar comparisons for a fingerprint hash
|
|
250
|
+
* @param {Object} client - API client
|
|
251
|
+
* @param {string} fingerprintHash - Honeydiff fingerprint hash
|
|
252
|
+
* @param {Object} options - Optional query params
|
|
253
|
+
* @returns {Promise<Object>} Fingerprint context bundle
|
|
254
|
+
*/
|
|
255
|
+
export async function getSimilarFingerprintContext(client, fingerprintHash, options = {}) {
|
|
256
|
+
let encodedFingerprint = encodeURIComponent(fingerprintHash);
|
|
257
|
+
let endpoint = buildEndpointWithParams(`/api/sdk/context/fingerprints/${encodedFingerprint}/similar`, options);
|
|
258
|
+
return client.request(endpoint);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get pending review queue context for a project
|
|
263
|
+
* @param {Object} client - API client
|
|
264
|
+
* @param {Object} options - Optional query params
|
|
265
|
+
* @returns {Promise<Object>} Review queue context bundle
|
|
266
|
+
*/
|
|
267
|
+
export async function getReviewQueueContext(client, options = {}) {
|
|
268
|
+
let endpoint = buildEndpointWithParams('/api/sdk/context/review-queue', options);
|
|
269
|
+
return client.request(endpoint);
|
|
270
|
+
}
|
|
271
|
+
|
|
213
272
|
/**
|
|
214
273
|
* Search for comparisons by name
|
|
215
274
|
* @param {Object} client - API client
|
package/dist/api/index.js
CHANGED
|
@@ -16,4 +16,4 @@ export { createApiClient, DEFAULT_API_URL } from './client.js';
|
|
|
16
16
|
export { buildApiUrl, buildAuthHeader, buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildRequestHeaders, buildScreenshotCheckObject, buildScreenshotPayload, buildShaCheckPayload, buildUserAgent, computeSha256, extractErrorBody, findScreenshotBySha, isAuthError, isRateLimited, parseApiError, partitionByShaExistence, shaExists, shouldRetryWithRefresh } from './core.js';
|
|
17
17
|
|
|
18
18
|
// Endpoint functions
|
|
19
|
-
export { checkShas, createBuild, finalizeBuild, finalizeParallelBuild, getBatchHotspots, getBuild, getBuilds, getComparison, getPreviewInfo, getScreenshotHotspots, getTddBaselines, getTokenContext, searchComparisons, updateBuildStatus, uploadPreviewZip, uploadScreenshot } from './endpoints.js';
|
|
19
|
+
export { checkShas, createBuild, finalizeBuild, finalizeParallelBuild, getBatchHotspots, getBuild, getBuildContext, getBuilds, getComparison, getComparisonContext, getPreviewInfo, getReviewQueueContext, getScreenshotContext, getScreenshotHotspots, getSimilarFingerprintContext, getTddBaselines, getTokenContext, searchComparisons, updateBuildStatus, uploadPreviewZip, uploadScreenshot } from './endpoints.js';
|
package/dist/auth/core.js
CHANGED
|
@@ -162,7 +162,7 @@ export function buildTokenData(response, existingUser = null) {
|
|
|
162
162
|
* @returns {{ valid: boolean, error: Error|null }}
|
|
163
163
|
*/
|
|
164
164
|
export function validateTokens(auth, requiredField = 'accessToken') {
|
|
165
|
-
if (!auth
|
|
165
|
+
if (!auth?.[requiredField]) {
|
|
166
166
|
let message = requiredField === 'refreshToken' ? 'No refresh token found. Please run "vizzly login" first.' : 'No authentication token found. Please run "vizzly login" first.';
|
|
167
167
|
return {
|
|
168
168
|
valid: false,
|
package/dist/auth/index.js
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
// Re-export token store utilities for convenience
|
|
11
11
|
import { clearAuthTokens, getAuthTokens, saveAuthTokens } from '../utils/global-config.js';
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
// HTTP client factory
|
|
14
14
|
export { createAuthClient } from './client.js';
|
|
15
15
|
// Core pure functions
|
|
16
16
|
export { buildAuthHeader, buildAuthUserAgent, buildDevicePollPayload, buildLogoutPayload, buildRefreshPayload, buildRequestHeaders, buildTokenData, parseAuthError, parseAuthenticatedError, validateTokens } from './core.js';
|
|
17
17
|
// Auth operations (take dependencies as parameters)
|
|
18
18
|
export { completeDeviceFlow, initiateDeviceFlow, isAuthenticated, logout, pollDeviceAuthorization, refresh, whoami } from './operations.js';
|
|
19
|
+
export { clearAuthTokens, getAuthTokens, saveAuthTokens };
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Create a token store adapter from global-config functions
|