@vizzly-testing/cli 0.35.3-beta.0 → 0.35.3-beta.1
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 +7 -4
- package/dist/api/client.js +20 -5
- package/dist/api/core.js +17 -3
- package/dist/cli.js +11 -51
- package/dist/commands/baselines.js +0 -7
- package/dist/commands/config-cmd.js +0 -7
- package/dist/commands/context.js +248 -306
- package/dist/commands/doctor.js +0 -8
- package/dist/commands/init.js +7 -12
- package/dist/commands/login.js +0 -13
- package/dist/commands/logout.js +0 -12
- package/dist/commands/orgs.js +0 -9
- package/dist/commands/whoami.js +0 -12
- package/dist/context/local-workspace-provider.js +276 -30
- package/dist/plugin-loader.js +1 -1
- package/dist/reporter/reporter-bundle.css +1 -1
- package/dist/reporter/reporter-bundle.iife.js +17 -17
- package/dist/server/routers/events.js +4 -4
- package/dist/utils/visual-context-normalizers.js +12 -3
- package/package.json +11 -10
- package/skills/vizzly/references/cli-context.md +5 -1
- package/dist/config/index.js +0 -13
- package/dist/project/index.js +0 -13
- package/dist/tdd/index.js +0 -19
- package/dist/tdd/services/baseline-downloader.js +0 -151
- package/dist/tdd/services/hotspot-service.js +0 -58
- package/dist/utils/environment.js +0 -109
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ evidence in one place.
|
|
|
101
101
|
```bash
|
|
102
102
|
# Cloud context for a build or comparison
|
|
103
103
|
vizzly context build abc123 --source cloud
|
|
104
|
-
vizzly context comparison def456 --source cloud --json
|
|
104
|
+
vizzly context comparison def456 --source cloud --agent --json
|
|
105
105
|
|
|
106
106
|
# Local workspace context from .vizzly/
|
|
107
107
|
vizzly context build current --source local
|
|
@@ -110,9 +110,12 @@ vizzly context screenshot build-detail-screenshots --source local --json
|
|
|
110
110
|
vizzly context review-queue --source local --json
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
`--json` is the durable automation path. `--agent` gives
|
|
114
|
-
prompt assembly.
|
|
115
|
-
|
|
113
|
+
`--json` is the durable automation path. `--agent` gives you the compact API
|
|
114
|
+
handoff for prompt assembly. Build handoffs contain up to 10 records; use the
|
|
115
|
+
exact next-page command returned in `suggested_commands` to continue safely.
|
|
116
|
+
That command carries the API's opaque `--cursor`. Add
|
|
117
|
+
`--include diffs` for raw diff diagnostics, or `--full` when you need the whole
|
|
118
|
+
payload.
|
|
116
119
|
|
|
117
120
|
Local context is read-only and file-backed. It reads your existing `.vizzly`
|
|
118
121
|
workspace state from TDD runs, including screenshots, diffs, and saved hotspot
|
package/dist/api/client.js
CHANGED
|
@@ -18,6 +18,11 @@ function isProjectToken(token) {
|
|
|
18
18
|
return typeof token === 'string' && token.startsWith('vzt_');
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/** Prefer the transport cause because Node's top-level fetch message is generic. */
|
|
22
|
+
function getNetworkFailureReason(error) {
|
|
23
|
+
return error?.cause?.code || error?.cause?.message || error?.message || 'request failed';
|
|
24
|
+
}
|
|
25
|
+
|
|
21
26
|
/**
|
|
22
27
|
* Create an API client with the given configuration
|
|
23
28
|
*
|
|
@@ -58,10 +63,19 @@ export function createApiClient(options = {}) {
|
|
|
58
63
|
contentType: fetchOptions.headers?.['Content-Type'],
|
|
59
64
|
extra: fetchOptions.headers || {}
|
|
60
65
|
});
|
|
61
|
-
let response
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
response = await fetch(url, {
|
|
69
|
+
...fetchOptions,
|
|
70
|
+
headers
|
|
71
|
+
});
|
|
72
|
+
} catch (error) {
|
|
73
|
+
let apiOrigin = new URL(url).origin;
|
|
74
|
+
let reason = getNetworkFailureReason(error);
|
|
75
|
+
throw new VizzlyError(`Unable to reach Vizzly at ${apiOrigin}: ${reason}`, 'NETWORK_ERROR', {
|
|
76
|
+
apiOrigin
|
|
77
|
+
});
|
|
78
|
+
}
|
|
65
79
|
if (!response.ok) {
|
|
66
80
|
let errorBody = await extractErrorBody(response);
|
|
67
81
|
|
|
@@ -82,7 +96,8 @@ export function createApiClient(options = {}) {
|
|
|
82
96
|
// Other errors
|
|
83
97
|
let error = parseApiError(response.status, errorBody, url);
|
|
84
98
|
throw new VizzlyError(error.message, error.code, {
|
|
85
|
-
status: error.status
|
|
99
|
+
status: error.status,
|
|
100
|
+
details: error.details
|
|
86
101
|
});
|
|
87
102
|
}
|
|
88
103
|
return response.json();
|
package/dist/api/core.js
CHANGED
|
@@ -232,8 +232,21 @@ export function shouldRetryWithRefresh(status, isRetry, hasRefreshToken) {
|
|
|
232
232
|
*/
|
|
233
233
|
export function parseApiError(status, body, url) {
|
|
234
234
|
let message = `API request failed: ${status}`;
|
|
235
|
+
let responseDetails = null;
|
|
236
|
+
let responseCode = null;
|
|
237
|
+
let responseMessage = body;
|
|
235
238
|
if (body) {
|
|
236
|
-
|
|
239
|
+
try {
|
|
240
|
+
let parsedBody = JSON.parse(body);
|
|
241
|
+
responseDetails = parsedBody.details ?? null;
|
|
242
|
+
responseCode = parsedBody.code ?? parsedBody.details?.code ?? null;
|
|
243
|
+
responseMessage = parsedBody.error ?? parsedBody.message ?? body;
|
|
244
|
+
} catch {
|
|
245
|
+
// Plain-text API errors remain valid and are surfaced unchanged.
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (responseMessage) {
|
|
249
|
+
message += ` - ${responseMessage}`;
|
|
237
250
|
}
|
|
238
251
|
message += ` (URL: ${url})`;
|
|
239
252
|
let code = 'API_ERROR';
|
|
@@ -244,8 +257,9 @@ export function parseApiError(status, body, url) {
|
|
|
244
257
|
if (status >= 500) code = 'SERVER_ERROR';
|
|
245
258
|
return {
|
|
246
259
|
message,
|
|
247
|
-
code,
|
|
248
|
-
status
|
|
260
|
+
code: responseCode || code,
|
|
261
|
+
status,
|
|
262
|
+
details: responseDetails
|
|
249
263
|
};
|
|
250
264
|
}
|
|
251
265
|
|
package/dist/cli.js
CHANGED
|
@@ -3,17 +3,17 @@ import 'dotenv/config';
|
|
|
3
3
|
import { existsSync, statSync } from 'node:fs';
|
|
4
4
|
import { Option, program } from 'commander';
|
|
5
5
|
import { apiCommand, validateApiOptions } from './commands/api.js';
|
|
6
|
-
import { baselinesCommand
|
|
6
|
+
import { baselinesCommand } from './commands/baselines.js';
|
|
7
7
|
import { buildsCommand, validateBuildsOptions } from './commands/builds.js';
|
|
8
8
|
import { comparisonsCommand, validateComparisonsOptions } from './commands/comparisons.js';
|
|
9
|
-
import { configCommand
|
|
9
|
+
import { configCommand } from './commands/config-cmd.js';
|
|
10
10
|
import { contextBuildCommand, contextComparisonCommand, contextReviewQueueCommand, contextScreenshotCommand, contextSimilarCommand, validateContextBuildOptions, validateContextComparisonOptions, validateContextReviewQueueOptions, validateContextScreenshotOptions, validateContextSimilarOptions } from './commands/context.js';
|
|
11
|
-
import { doctorCommand
|
|
11
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
12
12
|
import { finalizeCommand, validateFinalizeOptions } from './commands/finalize.js';
|
|
13
13
|
import { init } from './commands/init.js';
|
|
14
|
-
import { loginCommand
|
|
15
|
-
import { logoutCommand
|
|
16
|
-
import { orgsCommand
|
|
14
|
+
import { loginCommand } from './commands/login.js';
|
|
15
|
+
import { logoutCommand } from './commands/logout.js';
|
|
16
|
+
import { orgsCommand } from './commands/orgs.js';
|
|
17
17
|
import { previewCommand, validatePreviewOptions } from './commands/preview.js';
|
|
18
18
|
import { projectLinkCommand, validateProjectLinkOptions } from './commands/project.js';
|
|
19
19
|
import { projectsCommand, validateProjectsOptions } from './commands/projects.js';
|
|
@@ -23,7 +23,7 @@ import { statusCommand, validateStatusOptions } from './commands/status.js';
|
|
|
23
23
|
import { tddCommand, validateTddOptions } from './commands/tdd.js';
|
|
24
24
|
import { runDaemonChild, tddListCommand, tddStartCommand, tddStatusCommand, tddStopCommand, validateTddStartOptions } from './commands/tdd-daemon.js';
|
|
25
25
|
import { uploadCommand, validateUploadOptions } from './commands/upload.js';
|
|
26
|
-
import {
|
|
26
|
+
import { whoamiCommand } from './commands/whoami.js';
|
|
27
27
|
import { createPluginServices } from './plugin-api.js';
|
|
28
28
|
import { loadPlugins } from './plugin-loader.js';
|
|
29
29
|
import { createServices } from './services/index.js';
|
|
@@ -651,13 +651,13 @@ Examples:
|
|
|
651
651
|
await comparisonsCommand(options, globalOptions);
|
|
652
652
|
});
|
|
653
653
|
let contextCmd = program.command('context').description('Fetch build and diff context').showHelpAfterError('(Run vizzly context --help for available commands)').showSuggestionAfterError();
|
|
654
|
-
contextCmd.command('build').description('Fetch build context').argument('<build-id>', 'Build ID to fetch context for').option('--source <source>', 'Context source: auto, cloud, or local', 'auto').option('--agent', 'Output compact context for LLM agents').option('--full', 'Return the full build context
|
|
654
|
+
contextCmd.command('build').description('Fetch build context').argument('<build-id>', 'Build ID to fetch context for').option('--source <source>', 'Context source: auto, cloud, or local', 'auto').option('--agent', 'Output compact context for LLM agents').option('--full', 'Return the full build context instead of compact context').option('--cursor <cursor>', 'Continue compact evidence from an opaque API cursor').option('--include <items>', 'Add raw diff diagnostics to compact context: diffs').addHelpText('after', `
|
|
655
655
|
Examples:
|
|
656
656
|
$ vizzly context build abc123 --source cloud
|
|
657
657
|
$ vizzly context build current --source local
|
|
658
658
|
$ vizzly context build current --source local --agent
|
|
659
659
|
$ vizzly context build abc123 --source cloud --agent --json
|
|
660
|
-
$ vizzly context build abc123 --source cloud --agent --json --include diffs
|
|
660
|
+
$ vizzly context build abc123 --source cloud --agent --json --include diffs
|
|
661
661
|
$ vizzly context build abc123 --source cloud --agent --json --full
|
|
662
662
|
`).action(async (buildId, options) => {
|
|
663
663
|
let globalOptions = getGlobalOptions();
|
|
@@ -667,12 +667,12 @@ Examples:
|
|
|
667
667
|
}
|
|
668
668
|
await contextBuildCommand(buildId, options, globalOptions);
|
|
669
669
|
});
|
|
670
|
-
contextCmd.command('comparison').description('Fetch a comparison context bundle').argument('<comparison-id>', 'Comparison ID to fetch context for').option('--source <source>', 'Context source: auto, cloud, or local', 'auto').option('--
|
|
670
|
+
contextCmd.command('comparison').description('Fetch a comparison context bundle').argument('<comparison-id>', 'Comparison ID to fetch context for').option('--source <source>', 'Context source: auto, cloud, or local', 'auto').option('--agent', 'Output compact context for LLM agents').option('--full', 'Return the full comparison context instead of compact context').option('--cursor <cursor>', 'Continue compact history from an opaque API cursor').option('--include <items>', 'Add detail to compact context: diffs').addHelpText('after', `
|
|
671
671
|
Examples:
|
|
672
672
|
$ vizzly context comparison def456 --source cloud
|
|
673
673
|
$ vizzly context comparison def456 --source local
|
|
674
|
-
$ vizzly context comparison def456 --source cloud --similar-limit 5 --recent-limit 5
|
|
675
674
|
$ vizzly context comparison def456 --source cloud --json
|
|
675
|
+
$ vizzly context comparison def456 --source cloud --agent --json
|
|
676
676
|
`).action(async (comparisonId, options) => {
|
|
677
677
|
let globalOptions = getGlobalOptions();
|
|
678
678
|
const validationErrors = validateContextComparisonOptions(options);
|
|
@@ -724,12 +724,6 @@ Examples:
|
|
|
724
724
|
});
|
|
725
725
|
program.command('config').description('Display current configuration').argument('[key]', 'Specific config key to get (dot notation, e.g., comparison.threshold)').action(async (key, options) => {
|
|
726
726
|
let globalOptions = getGlobalOptions();
|
|
727
|
-
|
|
728
|
-
// Validate options
|
|
729
|
-
const validationErrors = validateConfigOptions(options);
|
|
730
|
-
if (validationErrors.length > 0) {
|
|
731
|
-
reportValidationErrors(validationErrors);
|
|
732
|
-
}
|
|
733
727
|
await configCommand(key, options, globalOptions);
|
|
734
728
|
});
|
|
735
729
|
program.command('baselines').description('List and query local TDD baselines').option('--name <pattern>', 'Filter baselines by name (supports wildcards)').option('--info <name>', 'Get detailed info for a specific baseline').addHelpText('after', `
|
|
@@ -742,12 +736,6 @@ Examples:
|
|
|
742
736
|
Note: Baselines are stored locally in .vizzly/baselines/ during TDD mode.
|
|
743
737
|
`).action(async options => {
|
|
744
738
|
let globalOptions = getGlobalOptions();
|
|
745
|
-
|
|
746
|
-
// Validate options
|
|
747
|
-
const validationErrors = validateBaselinesOptions(options);
|
|
748
|
-
if (validationErrors.length > 0) {
|
|
749
|
-
reportValidationErrors(validationErrors);
|
|
750
|
-
}
|
|
751
739
|
await baselinesCommand(options, globalOptions);
|
|
752
740
|
});
|
|
753
741
|
program.command('api').description('Make raw API requests (for power users)').argument('<endpoint>', 'API endpoint (e.g., /api/sdk/builds)').option('-X, --method <method>', 'HTTP method (GET or POST for approve/reject/comment)', 'GET').option('-d, --data <json>', 'Request body (JSON)').option('-H, --header <header>', 'Add header (key:value), can be repeated', (val, prev) => prev ? [...prev, val] : [val]).option('-q, --query <param>', 'Add query param (key=value), can be repeated', (val, prev) => prev ? [...prev, val] : [val]).addHelpText('after', `
|
|
@@ -833,10 +821,6 @@ Note: Shows organizations from your user account (via vizzly login)
|
|
|
833
821
|
or the single organization for a project token.
|
|
834
822
|
`).action(async options => {
|
|
835
823
|
let globalOptions = getGlobalOptions();
|
|
836
|
-
const validationErrors = validateOrgsOptions(options);
|
|
837
|
-
if (validationErrors.length > 0) {
|
|
838
|
-
reportValidationErrors(validationErrors);
|
|
839
|
-
}
|
|
840
824
|
await orgsCommand(options, globalOptions);
|
|
841
825
|
});
|
|
842
826
|
program.command('projects').description('List projects you have access to').option('--org <slug>', 'Filter by organization slug').option('--limit <n>', 'Maximum results to return (1-250)', Number, 50).option('--offset <n>', 'Skip first N results', Number, 0).addHelpText('after', `
|
|
@@ -910,42 +894,18 @@ program.command('preview').description('Upload static files as a preview for a b
|
|
|
910
894
|
});
|
|
911
895
|
program.command('doctor').description('Run diagnostics to check your environment and configuration').option('--api', 'Include API connectivity checks').action(async options => {
|
|
912
896
|
let globalOptions = getGlobalOptions();
|
|
913
|
-
|
|
914
|
-
// Validate options
|
|
915
|
-
const validationErrors = validateDoctorOptions(options);
|
|
916
|
-
if (validationErrors.length > 0) {
|
|
917
|
-
reportValidationErrors(validationErrors);
|
|
918
|
-
}
|
|
919
897
|
await doctorCommand(options, globalOptions);
|
|
920
898
|
});
|
|
921
899
|
program.command('login').description('Authenticate with your Vizzly account').option('--api-url <url>', 'API URL override').action(async options => {
|
|
922
900
|
let globalOptions = getGlobalOptions();
|
|
923
|
-
|
|
924
|
-
// Validate options
|
|
925
|
-
const validationErrors = validateLoginOptions(options);
|
|
926
|
-
if (validationErrors.length > 0) {
|
|
927
|
-
reportValidationErrors(validationErrors);
|
|
928
|
-
}
|
|
929
901
|
await loginCommand(options, globalOptions);
|
|
930
902
|
});
|
|
931
903
|
program.command('logout').description('Clear stored authentication tokens').option('--api-url <url>', 'API URL override').action(async options => {
|
|
932
904
|
let globalOptions = getGlobalOptions();
|
|
933
|
-
|
|
934
|
-
// Validate options
|
|
935
|
-
const validationErrors = validateLogoutOptions(options);
|
|
936
|
-
if (validationErrors.length > 0) {
|
|
937
|
-
reportValidationErrors(validationErrors);
|
|
938
|
-
}
|
|
939
905
|
await logoutCommand(options, globalOptions);
|
|
940
906
|
});
|
|
941
907
|
program.command('whoami').description('Show current authentication status and user information').option('--api-url <url>', 'API URL override').action(async options => {
|
|
942
908
|
let globalOptions = getGlobalOptions();
|
|
943
|
-
|
|
944
|
-
// Validate options
|
|
945
|
-
const validationErrors = validateWhoamiOptions(options);
|
|
946
|
-
if (validationErrors.length > 0) {
|
|
947
|
-
reportValidationErrors(validationErrors);
|
|
948
|
-
}
|
|
949
909
|
await whoamiCommand(options, globalOptions);
|
|
950
910
|
});
|
|
951
911
|
|
|
@@ -286,11 +286,4 @@ export function formatBytes(bytes) {
|
|
|
286
286
|
if (bytes < 1024) return `${bytes} B`;
|
|
287
287
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
288
288
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Validate baselines command options
|
|
293
|
-
*/
|
|
294
|
-
export function validateBaselinesOptions() {
|
|
295
|
-
return [];
|
|
296
289
|
}
|