@vizzly-testing/cli 0.10.3 → 0.11.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 +168 -8
- package/claude-plugin/.claude-plugin/.mcp.json +8 -0
- package/claude-plugin/.claude-plugin/README.md +114 -0
- package/claude-plugin/.claude-plugin/marketplace.json +28 -0
- package/claude-plugin/.claude-plugin/plugin.json +14 -0
- package/claude-plugin/commands/debug-diff.md +153 -0
- package/claude-plugin/commands/setup.md +137 -0
- package/claude-plugin/commands/suggest-screenshots.md +111 -0
- package/claude-plugin/commands/tdd-status.md +43 -0
- package/claude-plugin/mcp/vizzly-server/cloud-api-provider.js +354 -0
- package/claude-plugin/mcp/vizzly-server/index.js +861 -0
- package/claude-plugin/mcp/vizzly-server/local-tdd-provider.js +422 -0
- package/claude-plugin/mcp/vizzly-server/token-resolver.js +185 -0
- package/dist/cli.js +64 -0
- package/dist/client/index.js +13 -3
- package/dist/commands/login.js +195 -0
- package/dist/commands/logout.js +71 -0
- package/dist/commands/project.js +351 -0
- package/dist/commands/run.js +30 -0
- package/dist/commands/whoami.js +162 -0
- package/dist/plugin-loader.js +9 -15
- package/dist/sdk/index.js +16 -4
- package/dist/services/api-service.js +50 -7
- package/dist/services/auth-service.js +226 -0
- package/dist/types/client/index.d.ts +9 -3
- package/dist/types/commands/login.d.ts +11 -0
- package/dist/types/commands/logout.d.ts +11 -0
- package/dist/types/commands/project.d.ts +28 -0
- package/dist/types/commands/whoami.d.ts +11 -0
- package/dist/types/sdk/index.d.ts +9 -4
- package/dist/types/services/api-service.d.ts +2 -1
- package/dist/types/services/auth-service.d.ts +59 -0
- package/dist/types/utils/browser.d.ts +6 -0
- package/dist/types/utils/config-loader.d.ts +1 -1
- package/dist/types/utils/config-schema.d.ts +8 -174
- package/dist/types/utils/file-helpers.d.ts +18 -0
- package/dist/types/utils/global-config.d.ts +84 -0
- package/dist/utils/browser.js +44 -0
- package/dist/utils/config-loader.js +69 -3
- package/dist/utils/file-helpers.js +64 -0
- package/dist/utils/global-config.js +259 -0
- package/docs/api-reference.md +177 -6
- package/docs/authentication.md +334 -0
- package/docs/getting-started.md +21 -2
- package/docs/plugins.md +27 -0
- package/docs/test-integration.md +60 -10
- package/package.json +5 -3
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logout command implementation
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function logoutCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Validate logout options
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function validateLogoutOptions(): any[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project select command - configure project for current directory
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function projectSelectCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Project list command - show all configured projects
|
|
9
|
+
* @param {Object} _options - Command options (unused)
|
|
10
|
+
* @param {Object} globalOptions - Global CLI options
|
|
11
|
+
*/
|
|
12
|
+
export function projectListCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Project token command - show/regenerate token for current directory
|
|
15
|
+
* @param {Object} _options - Command options (unused)
|
|
16
|
+
* @param {Object} globalOptions - Global CLI options
|
|
17
|
+
*/
|
|
18
|
+
export function projectTokenCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Project remove command - remove project configuration for current directory
|
|
21
|
+
* @param {Object} _options - Command options (unused)
|
|
22
|
+
* @param {Object} globalOptions - Global CLI options
|
|
23
|
+
*/
|
|
24
|
+
export function projectRemoveCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Validate project command options
|
|
27
|
+
*/
|
|
28
|
+
export function validateProjectOptions(): any[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whoami command implementation
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function whoamiCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Validate whoami options
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function validateWhoamiOptions(): any[];
|
|
@@ -81,11 +81,14 @@ export class VizzlySDK {
|
|
|
81
81
|
/**
|
|
82
82
|
* Capture a screenshot
|
|
83
83
|
* @param {string} name - Screenshot name
|
|
84
|
-
* @param {Buffer} imageBuffer - Image data
|
|
84
|
+
* @param {Buffer|string} imageBuffer - Image data as a Buffer, or a file path to an image
|
|
85
85
|
* @param {import('../types').ScreenshotOptions} [options] - Options
|
|
86
86
|
* @returns {Promise<void>}
|
|
87
|
+
* @throws {VizzlyError} When server is not running
|
|
88
|
+
* @throws {VizzlyError} When file path is provided but file doesn't exist
|
|
89
|
+
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
87
90
|
*/
|
|
88
|
-
screenshot(name: string, imageBuffer: Buffer, options?: any): Promise<void>;
|
|
91
|
+
screenshot(name: string, imageBuffer: Buffer | string, options?: any): Promise<void>;
|
|
89
92
|
/**
|
|
90
93
|
* Upload all captured screenshots
|
|
91
94
|
* @param {import('../types').UploadOptions} [options] - Upload options
|
|
@@ -95,10 +98,12 @@ export class VizzlySDK {
|
|
|
95
98
|
/**
|
|
96
99
|
* Run local comparison in TDD mode
|
|
97
100
|
* @param {string} name - Screenshot name
|
|
98
|
-
* @param {Buffer} imageBuffer - Current image
|
|
101
|
+
* @param {Buffer|string} imageBuffer - Current image as a Buffer, or a file path to an image
|
|
99
102
|
* @returns {Promise<import('../types').ComparisonResult>} Comparison result
|
|
103
|
+
* @throws {VizzlyError} When file path is provided but file doesn't exist
|
|
104
|
+
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
100
105
|
*/
|
|
101
|
-
compare(name: string, imageBuffer: Buffer): Promise<any>;
|
|
106
|
+
compare(name: string, imageBuffer: Buffer | string): Promise<any>;
|
|
102
107
|
}
|
|
103
108
|
export { loadConfig } from "../utils/config-loader.js";
|
|
104
109
|
export { createLogger } from "../utils/logger.js";
|
|
@@ -11,9 +11,10 @@ export class ApiService {
|
|
|
11
11
|
* Make an API request
|
|
12
12
|
* @param {string} endpoint - API endpoint
|
|
13
13
|
* @param {Object} options - Fetch options
|
|
14
|
+
* @param {boolean} isRetry - Internal flag to prevent infinite retry loops
|
|
14
15
|
* @returns {Promise<Object>} Response data
|
|
15
16
|
*/
|
|
16
|
-
request(endpoint: string, options?: any): Promise<any>;
|
|
17
|
+
request(endpoint: string, options?: any, isRetry?: boolean): Promise<any>;
|
|
17
18
|
/**
|
|
18
19
|
* Get build information
|
|
19
20
|
* @param {string} buildId - Build ID
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthService class for CLI authentication
|
|
3
|
+
*/
|
|
4
|
+
export class AuthService {
|
|
5
|
+
constructor(options?: {});
|
|
6
|
+
baseUrl: any;
|
|
7
|
+
userAgent: string;
|
|
8
|
+
/**
|
|
9
|
+
* Make an unauthenticated API request
|
|
10
|
+
* @param {string} endpoint - API endpoint
|
|
11
|
+
* @param {Object} options - Fetch options
|
|
12
|
+
* @returns {Promise<Object>} Response data
|
|
13
|
+
*/
|
|
14
|
+
request(endpoint: string, options?: any): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Make an authenticated API request
|
|
17
|
+
* @param {string} endpoint - API endpoint
|
|
18
|
+
* @param {Object} options - Fetch options
|
|
19
|
+
* @returns {Promise<Object>} Response data
|
|
20
|
+
*/
|
|
21
|
+
authenticatedRequest(endpoint: string, options?: any): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Initiate OAuth device flow
|
|
24
|
+
* @returns {Promise<Object>} Device code, user code, verification URL
|
|
25
|
+
*/
|
|
26
|
+
initiateDeviceFlow(): Promise<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Poll for device authorization
|
|
29
|
+
* @param {string} deviceCode - Device code from initiate
|
|
30
|
+
* @returns {Promise<Object>} Token data or pending status
|
|
31
|
+
*/
|
|
32
|
+
pollDeviceAuthorization(deviceCode: string): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Complete device flow and save tokens
|
|
35
|
+
* @param {Object} tokenData - Token response from poll
|
|
36
|
+
* @returns {Promise<Object>} Token data with user info
|
|
37
|
+
*/
|
|
38
|
+
completeDeviceFlow(tokenData: any): Promise<any>;
|
|
39
|
+
/**
|
|
40
|
+
* Refresh access token using refresh token
|
|
41
|
+
* @returns {Promise<Object>} New tokens
|
|
42
|
+
*/
|
|
43
|
+
refresh(): Promise<any>;
|
|
44
|
+
/**
|
|
45
|
+
* Logout and revoke tokens
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
logout(): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Get current user information
|
|
51
|
+
* @returns {Promise<Object>} User and organization data
|
|
52
|
+
*/
|
|
53
|
+
whoami(): Promise<any>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if user is authenticated
|
|
56
|
+
* @returns {Promise<boolean>} True if authenticated
|
|
57
|
+
*/
|
|
58
|
+
isAuthenticated(): Promise<boolean>;
|
|
59
|
+
}
|
|
@@ -21,197 +21,31 @@ export let vizzlyConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
|
21
21
|
server: z.ZodDefault<z.ZodObject<{
|
|
22
22
|
port: z.ZodDefault<z.ZodNumber>;
|
|
23
23
|
timeout: z.ZodDefault<z.ZodNumber>;
|
|
24
|
-
},
|
|
25
|
-
port?: number;
|
|
26
|
-
timeout?: number;
|
|
27
|
-
}, {
|
|
28
|
-
port?: number;
|
|
29
|
-
timeout?: number;
|
|
30
|
-
}>>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
31
25
|
build: z.ZodDefault<z.ZodObject<{
|
|
32
26
|
name: z.ZodDefault<z.ZodString>;
|
|
33
27
|
environment: z.ZodDefault<z.ZodString>;
|
|
34
28
|
branch: z.ZodOptional<z.ZodString>;
|
|
35
29
|
commit: z.ZodOptional<z.ZodString>;
|
|
36
30
|
message: z.ZodOptional<z.ZodString>;
|
|
37
|
-
},
|
|
38
|
-
name?: string;
|
|
39
|
-
message?: string;
|
|
40
|
-
environment?: string;
|
|
41
|
-
branch?: string;
|
|
42
|
-
commit?: string;
|
|
43
|
-
}, {
|
|
44
|
-
name?: string;
|
|
45
|
-
message?: string;
|
|
46
|
-
environment?: string;
|
|
47
|
-
branch?: string;
|
|
48
|
-
commit?: string;
|
|
49
|
-
}>>;
|
|
31
|
+
}, z.core.$strip>>;
|
|
50
32
|
upload: z.ZodDefault<z.ZodObject<{
|
|
51
|
-
screenshotsDir: z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString
|
|
33
|
+
screenshotsDir: z.ZodDefault<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
52
34
|
batchSize: z.ZodDefault<z.ZodNumber>;
|
|
53
35
|
timeout: z.ZodDefault<z.ZodNumber>;
|
|
54
|
-
},
|
|
55
|
-
timeout?: number;
|
|
56
|
-
screenshotsDir?: string | string[];
|
|
57
|
-
batchSize?: number;
|
|
58
|
-
}, {
|
|
59
|
-
timeout?: number;
|
|
60
|
-
screenshotsDir?: string | string[];
|
|
61
|
-
batchSize?: number;
|
|
62
|
-
}>>;
|
|
36
|
+
}, z.core.$strip>>;
|
|
63
37
|
comparison: z.ZodDefault<z.ZodObject<{
|
|
64
38
|
threshold: z.ZodDefault<z.ZodNumber>;
|
|
65
|
-
},
|
|
66
|
-
threshold?: number;
|
|
67
|
-
}, {
|
|
68
|
-
threshold?: number;
|
|
69
|
-
}>>;
|
|
39
|
+
}, z.core.$strip>>;
|
|
70
40
|
tdd: z.ZodDefault<z.ZodObject<{
|
|
71
41
|
openReport: z.ZodDefault<z.ZodBoolean>;
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
}, {
|
|
75
|
-
openReport?: boolean;
|
|
76
|
-
}>>;
|
|
77
|
-
plugins: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
42
|
+
}, z.core.$strip>>;
|
|
43
|
+
plugins: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
78
44
|
parallelId: z.ZodOptional<z.ZodString>;
|
|
79
45
|
baselineBuildId: z.ZodOptional<z.ZodString>;
|
|
80
46
|
baselineComparisonId: z.ZodOptional<z.ZodString>;
|
|
81
47
|
eager: z.ZodOptional<z.ZodBoolean>;
|
|
82
48
|
wait: z.ZodOptional<z.ZodBoolean>;
|
|
83
49
|
allowNoToken: z.ZodOptional<z.ZodBoolean>;
|
|
84
|
-
},
|
|
85
|
-
apiKey: z.ZodOptional<z.ZodString>;
|
|
86
|
-
apiUrl: z.ZodOptional<z.ZodString>;
|
|
87
|
-
server: z.ZodDefault<z.ZodObject<{
|
|
88
|
-
port: z.ZodDefault<z.ZodNumber>;
|
|
89
|
-
timeout: z.ZodDefault<z.ZodNumber>;
|
|
90
|
-
}, "strip", z.ZodTypeAny, {
|
|
91
|
-
port?: number;
|
|
92
|
-
timeout?: number;
|
|
93
|
-
}, {
|
|
94
|
-
port?: number;
|
|
95
|
-
timeout?: number;
|
|
96
|
-
}>>;
|
|
97
|
-
build: z.ZodDefault<z.ZodObject<{
|
|
98
|
-
name: z.ZodDefault<z.ZodString>;
|
|
99
|
-
environment: z.ZodDefault<z.ZodString>;
|
|
100
|
-
branch: z.ZodOptional<z.ZodString>;
|
|
101
|
-
commit: z.ZodOptional<z.ZodString>;
|
|
102
|
-
message: z.ZodOptional<z.ZodString>;
|
|
103
|
-
}, "strip", z.ZodTypeAny, {
|
|
104
|
-
name?: string;
|
|
105
|
-
message?: string;
|
|
106
|
-
environment?: string;
|
|
107
|
-
branch?: string;
|
|
108
|
-
commit?: string;
|
|
109
|
-
}, {
|
|
110
|
-
name?: string;
|
|
111
|
-
message?: string;
|
|
112
|
-
environment?: string;
|
|
113
|
-
branch?: string;
|
|
114
|
-
commit?: string;
|
|
115
|
-
}>>;
|
|
116
|
-
upload: z.ZodDefault<z.ZodObject<{
|
|
117
|
-
screenshotsDir: z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
118
|
-
batchSize: z.ZodDefault<z.ZodNumber>;
|
|
119
|
-
timeout: z.ZodDefault<z.ZodNumber>;
|
|
120
|
-
}, "strip", z.ZodTypeAny, {
|
|
121
|
-
timeout?: number;
|
|
122
|
-
screenshotsDir?: string | string[];
|
|
123
|
-
batchSize?: number;
|
|
124
|
-
}, {
|
|
125
|
-
timeout?: number;
|
|
126
|
-
screenshotsDir?: string | string[];
|
|
127
|
-
batchSize?: number;
|
|
128
|
-
}>>;
|
|
129
|
-
comparison: z.ZodDefault<z.ZodObject<{
|
|
130
|
-
threshold: z.ZodDefault<z.ZodNumber>;
|
|
131
|
-
}, "strip", z.ZodTypeAny, {
|
|
132
|
-
threshold?: number;
|
|
133
|
-
}, {
|
|
134
|
-
threshold?: number;
|
|
135
|
-
}>>;
|
|
136
|
-
tdd: z.ZodDefault<z.ZodObject<{
|
|
137
|
-
openReport: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
-
}, "strip", z.ZodTypeAny, {
|
|
139
|
-
openReport?: boolean;
|
|
140
|
-
}, {
|
|
141
|
-
openReport?: boolean;
|
|
142
|
-
}>>;
|
|
143
|
-
plugins: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
144
|
-
parallelId: z.ZodOptional<z.ZodString>;
|
|
145
|
-
baselineBuildId: z.ZodOptional<z.ZodString>;
|
|
146
|
-
baselineComparisonId: z.ZodOptional<z.ZodString>;
|
|
147
|
-
eager: z.ZodOptional<z.ZodBoolean>;
|
|
148
|
-
wait: z.ZodOptional<z.ZodBoolean>;
|
|
149
|
-
allowNoToken: z.ZodOptional<z.ZodBoolean>;
|
|
150
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
151
|
-
apiKey: z.ZodOptional<z.ZodString>;
|
|
152
|
-
apiUrl: z.ZodOptional<z.ZodString>;
|
|
153
|
-
server: z.ZodDefault<z.ZodObject<{
|
|
154
|
-
port: z.ZodDefault<z.ZodNumber>;
|
|
155
|
-
timeout: z.ZodDefault<z.ZodNumber>;
|
|
156
|
-
}, "strip", z.ZodTypeAny, {
|
|
157
|
-
port?: number;
|
|
158
|
-
timeout?: number;
|
|
159
|
-
}, {
|
|
160
|
-
port?: number;
|
|
161
|
-
timeout?: number;
|
|
162
|
-
}>>;
|
|
163
|
-
build: z.ZodDefault<z.ZodObject<{
|
|
164
|
-
name: z.ZodDefault<z.ZodString>;
|
|
165
|
-
environment: z.ZodDefault<z.ZodString>;
|
|
166
|
-
branch: z.ZodOptional<z.ZodString>;
|
|
167
|
-
commit: z.ZodOptional<z.ZodString>;
|
|
168
|
-
message: z.ZodOptional<z.ZodString>;
|
|
169
|
-
}, "strip", z.ZodTypeAny, {
|
|
170
|
-
name?: string;
|
|
171
|
-
message?: string;
|
|
172
|
-
environment?: string;
|
|
173
|
-
branch?: string;
|
|
174
|
-
commit?: string;
|
|
175
|
-
}, {
|
|
176
|
-
name?: string;
|
|
177
|
-
message?: string;
|
|
178
|
-
environment?: string;
|
|
179
|
-
branch?: string;
|
|
180
|
-
commit?: string;
|
|
181
|
-
}>>;
|
|
182
|
-
upload: z.ZodDefault<z.ZodObject<{
|
|
183
|
-
screenshotsDir: z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
184
|
-
batchSize: z.ZodDefault<z.ZodNumber>;
|
|
185
|
-
timeout: z.ZodDefault<z.ZodNumber>;
|
|
186
|
-
}, "strip", z.ZodTypeAny, {
|
|
187
|
-
timeout?: number;
|
|
188
|
-
screenshotsDir?: string | string[];
|
|
189
|
-
batchSize?: number;
|
|
190
|
-
}, {
|
|
191
|
-
timeout?: number;
|
|
192
|
-
screenshotsDir?: string | string[];
|
|
193
|
-
batchSize?: number;
|
|
194
|
-
}>>;
|
|
195
|
-
comparison: z.ZodDefault<z.ZodObject<{
|
|
196
|
-
threshold: z.ZodDefault<z.ZodNumber>;
|
|
197
|
-
}, "strip", z.ZodTypeAny, {
|
|
198
|
-
threshold?: number;
|
|
199
|
-
}, {
|
|
200
|
-
threshold?: number;
|
|
201
|
-
}>>;
|
|
202
|
-
tdd: z.ZodDefault<z.ZodObject<{
|
|
203
|
-
openReport: z.ZodDefault<z.ZodBoolean>;
|
|
204
|
-
}, "strip", z.ZodTypeAny, {
|
|
205
|
-
openReport?: boolean;
|
|
206
|
-
}, {
|
|
207
|
-
openReport?: boolean;
|
|
208
|
-
}>>;
|
|
209
|
-
plugins: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
210
|
-
parallelId: z.ZodOptional<z.ZodString>;
|
|
211
|
-
baselineBuildId: z.ZodOptional<z.ZodString>;
|
|
212
|
-
baselineComparisonId: z.ZodOptional<z.ZodString>;
|
|
213
|
-
eager: z.ZodOptional<z.ZodBoolean>;
|
|
214
|
-
wait: z.ZodOptional<z.ZodBoolean>;
|
|
215
|
-
allowNoToken: z.ZodOptional<z.ZodBoolean>;
|
|
216
|
-
}, z.ZodTypeAny, "passthrough">>>;
|
|
50
|
+
}, z.core.$loose>>;
|
|
217
51
|
import { z } from 'zod';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve image buffer from file path or return buffer as-is
|
|
3
|
+
* Handles both Buffer inputs and file path strings, with proper validation and error handling
|
|
4
|
+
*
|
|
5
|
+
* @param {Buffer|string} imageBufferOrPath - Image data as Buffer or file path
|
|
6
|
+
* @param {string} contextName - Context for error messages (e.g., 'screenshot', 'compare')
|
|
7
|
+
* @returns {Buffer} The image buffer
|
|
8
|
+
* @throws {VizzlyError} When file not found, unreadable, or invalid input type
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // With Buffer
|
|
12
|
+
* const buffer = resolveImageBuffer(myBuffer, 'screenshot');
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // With file path
|
|
16
|
+
* const buffer = resolveImageBuffer('./my-image.png', 'screenshot');
|
|
17
|
+
*/
|
|
18
|
+
export function resolveImageBuffer(imageBufferOrPath: Buffer | string, contextName: string): Buffer;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the path to the global Vizzly directory
|
|
3
|
+
* @returns {string} Path to ~/.vizzly
|
|
4
|
+
*/
|
|
5
|
+
export function getGlobalConfigDir(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get the path to the global config file
|
|
8
|
+
* @returns {string} Path to ~/.vizzly/config.json
|
|
9
|
+
*/
|
|
10
|
+
export function getGlobalConfigPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Load the global configuration
|
|
13
|
+
* @returns {Promise<Object>} Global config object
|
|
14
|
+
*/
|
|
15
|
+
export function loadGlobalConfig(): Promise<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Save the global configuration
|
|
18
|
+
* @param {Object} config - Configuration object to save
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
export function saveGlobalConfig(config: any): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Clear all global configuration
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*/
|
|
26
|
+
export function clearGlobalConfig(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get authentication tokens from global config
|
|
29
|
+
* @returns {Promise<Object|null>} Token object with accessToken, refreshToken, expiresAt, user, or null if not found
|
|
30
|
+
*/
|
|
31
|
+
export function getAuthTokens(): Promise<any | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Save authentication tokens to global config
|
|
34
|
+
* @param {Object} auth - Auth object with accessToken, refreshToken, expiresAt, user
|
|
35
|
+
* @returns {Promise<void>}
|
|
36
|
+
*/
|
|
37
|
+
export function saveAuthTokens(auth: any): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Clear authentication tokens from global config
|
|
40
|
+
* @returns {Promise<void>}
|
|
41
|
+
*/
|
|
42
|
+
export function clearAuthTokens(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if authentication tokens exist and are not expired
|
|
45
|
+
* @returns {Promise<boolean>} True if valid tokens exist
|
|
46
|
+
*/
|
|
47
|
+
export function hasValidTokens(): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the access token from global config if available
|
|
50
|
+
* @returns {Promise<string|null>} Access token or null
|
|
51
|
+
*/
|
|
52
|
+
export function getAccessToken(): Promise<string | null>;
|
|
53
|
+
/**
|
|
54
|
+
* Get project mapping for a directory
|
|
55
|
+
* Walks up the directory tree to find the closest mapping
|
|
56
|
+
* @param {string} directoryPath - Absolute path to project directory
|
|
57
|
+
* @returns {Promise<Object|null>} Project data or null
|
|
58
|
+
*/
|
|
59
|
+
export function getProjectMapping(directoryPath: string): Promise<any | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Save project mapping for a directory
|
|
62
|
+
* @param {string} directoryPath - Absolute path to project directory
|
|
63
|
+
* @param {Object} projectData - Project configuration
|
|
64
|
+
* @param {string} projectData.token - Project API token (vzt_...)
|
|
65
|
+
* @param {string} projectData.projectSlug - Project slug
|
|
66
|
+
* @param {string} projectData.organizationSlug - Organization slug
|
|
67
|
+
* @param {string} projectData.projectName - Project name
|
|
68
|
+
*/
|
|
69
|
+
export function saveProjectMapping(directoryPath: string, projectData: {
|
|
70
|
+
token: string;
|
|
71
|
+
projectSlug: string;
|
|
72
|
+
organizationSlug: string;
|
|
73
|
+
projectName: string;
|
|
74
|
+
}): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Get all project mappings
|
|
77
|
+
* @returns {Promise<Object>} Map of directory paths to project data
|
|
78
|
+
*/
|
|
79
|
+
export function getProjectMappings(): Promise<any>;
|
|
80
|
+
/**
|
|
81
|
+
* Delete project mapping for a directory
|
|
82
|
+
* @param {string} directoryPath - Absolute path to project directory
|
|
83
|
+
*/
|
|
84
|
+
export function deleteProjectMapping(directoryPath: string): Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser utilities for opening URLs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
|
+
import { platform } from 'os';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Open a URL in the default browser
|
|
10
|
+
* @param {string} url - URL to open
|
|
11
|
+
* @returns {Promise<boolean>} True if successful
|
|
12
|
+
*/
|
|
13
|
+
export async function openBrowser(url) {
|
|
14
|
+
return new Promise(resolve => {
|
|
15
|
+
let command;
|
|
16
|
+
let args;
|
|
17
|
+
let os = platform();
|
|
18
|
+
switch (os) {
|
|
19
|
+
case 'darwin':
|
|
20
|
+
// macOS
|
|
21
|
+
command = 'open';
|
|
22
|
+
args = [url];
|
|
23
|
+
break;
|
|
24
|
+
case 'win32':
|
|
25
|
+
// Windows
|
|
26
|
+
command = 'cmd.exe';
|
|
27
|
+
args = ['/c', 'start', '""', url];
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
// Linux and others
|
|
31
|
+
command = 'xdg-open';
|
|
32
|
+
args = [url];
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
execFile(command, args, error => {
|
|
36
|
+
if (error) {
|
|
37
|
+
// Browser opening failed, but don't throw - user can manually open
|
|
38
|
+
resolve(false);
|
|
39
|
+
} else {
|
|
40
|
+
resolve(true);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -2,9 +2,11 @@ import { cosmiconfigSync } from 'cosmiconfig';
|
|
|
2
2
|
import { resolve } from 'path';
|
|
3
3
|
import { getApiToken, getApiUrl, getParallelId } from './environment-config.js';
|
|
4
4
|
import { validateVizzlyConfigWithDefaults } from './config-schema.js';
|
|
5
|
+
import { getAccessToken, getProjectMapping } from './global-config.js';
|
|
5
6
|
const DEFAULT_CONFIG = {
|
|
6
7
|
// API Configuration
|
|
7
|
-
apiKey:
|
|
8
|
+
apiKey: undefined,
|
|
9
|
+
// Will be set from env, global config, or CLI overrides
|
|
8
10
|
apiUrl: getApiUrl(),
|
|
9
11
|
// Server Configuration (for run command)
|
|
10
12
|
server: {
|
|
@@ -70,16 +72,80 @@ export async function loadConfig(configPath = null, cliOverrides = {}) {
|
|
|
70
72
|
// Merge validated file config
|
|
71
73
|
mergeConfig(config, validatedFileConfig);
|
|
72
74
|
|
|
73
|
-
// 3.
|
|
75
|
+
// 3. Check project mapping for current directory (if no CLI flag)
|
|
76
|
+
if (!cliOverrides.token) {
|
|
77
|
+
const currentDir = process.cwd();
|
|
78
|
+
if (process.env.DEBUG_CONFIG) {
|
|
79
|
+
console.log('[CONFIG] Looking up project mapping for:', currentDir);
|
|
80
|
+
}
|
|
81
|
+
const projectMapping = await getProjectMapping(currentDir);
|
|
82
|
+
if (projectMapping && projectMapping.token) {
|
|
83
|
+
// Handle both string tokens and token objects (backward compatibility)
|
|
84
|
+
let token;
|
|
85
|
+
if (typeof projectMapping.token === 'string') {
|
|
86
|
+
token = projectMapping.token;
|
|
87
|
+
} else if (typeof projectMapping.token === 'object' && projectMapping.token.token) {
|
|
88
|
+
// Handle nested token object from old API responses
|
|
89
|
+
token = projectMapping.token.token;
|
|
90
|
+
} else {
|
|
91
|
+
token = String(projectMapping.token);
|
|
92
|
+
}
|
|
93
|
+
config.apiKey = token;
|
|
94
|
+
config.projectSlug = projectMapping.projectSlug;
|
|
95
|
+
config.organizationSlug = projectMapping.organizationSlug;
|
|
96
|
+
|
|
97
|
+
// Debug logging
|
|
98
|
+
if (process.env.DEBUG_CONFIG) {
|
|
99
|
+
console.log('[CONFIG] Found project mapping:', {
|
|
100
|
+
dir: currentDir,
|
|
101
|
+
projectSlug: projectMapping.projectSlug,
|
|
102
|
+
hasToken: !!projectMapping.token,
|
|
103
|
+
tokenType: typeof projectMapping.token,
|
|
104
|
+
tokenPrefix: token ? token.substring(0, 8) + '***' : 'none'
|
|
105
|
+
});
|
|
106
|
+
console.log('[CONFIG] Set config.apiKey to:', config.apiKey ? config.apiKey.substring(0, 8) + '***' : 'NONE');
|
|
107
|
+
}
|
|
108
|
+
} else if (process.env.DEBUG_CONFIG) {
|
|
109
|
+
console.log('[CONFIG] No project mapping found for:', currentDir);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 3.5. Check global config for user access token (if no CLI flag)
|
|
114
|
+
if (!config.apiKey && !cliOverrides.token) {
|
|
115
|
+
const globalToken = await getAccessToken();
|
|
116
|
+
if (globalToken) {
|
|
117
|
+
config.apiKey = globalToken;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 4. Override with environment variables (higher priority than fallbacks)
|
|
74
122
|
const envApiKey = getApiToken();
|
|
75
123
|
const envApiUrl = getApiUrl();
|
|
76
124
|
const envParallelId = getParallelId();
|
|
125
|
+
if (process.env.DEBUG_CONFIG) {
|
|
126
|
+
console.log('[CONFIG] Step 4 - env vars:', JSON.stringify({
|
|
127
|
+
hasEnvApiKey: !!envApiKey,
|
|
128
|
+
envApiKeyPrefix: envApiKey ? envApiKey.substring(0, 8) + '***' : 'none',
|
|
129
|
+
configApiKeyBefore: config.apiKey ? config.apiKey.substring(0, 8) + '***' : 'NONE'
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
77
132
|
if (envApiKey) config.apiKey = envApiKey;
|
|
78
133
|
if (envApiUrl !== 'https://app.vizzly.dev') config.apiUrl = envApiUrl;
|
|
79
134
|
if (envParallelId) config.parallelId = envParallelId;
|
|
80
135
|
|
|
81
|
-
//
|
|
136
|
+
// 5. Apply CLI overrides (highest priority)
|
|
137
|
+
if (process.env.DEBUG_CONFIG) {
|
|
138
|
+
console.log('[CONFIG] Step 5 - before CLI overrides:', {
|
|
139
|
+
configApiKey: config.apiKey ? config.apiKey.substring(0, 8) + '***' : 'NONE',
|
|
140
|
+
cliToken: cliOverrides.token ? cliOverrides.token.substring(0, 8) + '***' : 'none'
|
|
141
|
+
});
|
|
142
|
+
}
|
|
82
143
|
applyCLIOverrides(config, cliOverrides);
|
|
144
|
+
if (process.env.DEBUG_CONFIG) {
|
|
145
|
+
console.log('[CONFIG] Step 6 - after CLI overrides:', {
|
|
146
|
+
configApiKey: config.apiKey ? config.apiKey.substring(0, 8) + '***' : 'NONE'
|
|
147
|
+
});
|
|
148
|
+
}
|
|
83
149
|
return config;
|
|
84
150
|
}
|
|
85
151
|
|