@testivai/witness-playwright 1.9.0 → 2.0.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/dist/types.d.ts CHANGED
@@ -1,10 +1,5 @@
1
1
  /**
2
- * Types for Testivai Witness Playwright SDK
3
- *
4
- * Defines the data shapes for evidence collection:
5
- * - SnapshotPayload: DOM + Layout data for a single snapshot
6
- * - BatchPayload: Git + Browser info + collection of snapshots
7
- * - TestivAIConfig: Configuration for visual analysis behavior
2
+ * Types for the TestivAI Playwright adapter
8
3
  */
9
4
  /**
10
5
  * How an ignored selector is neutralized before capture:
@@ -24,219 +19,28 @@ export type IgnoreSelectorInput = string | {
24
19
  mode?: IgnoreMode;
25
20
  };
26
21
  /**
27
- * Layout configuration for visual analysis
28
- */
29
- export interface LayoutConfig {
30
- /** Sensitivity level: 0-4 scale (0=strict/precise, 4=very lenient) */
31
- sensitivity: number;
32
- /** Base pixel tolerance for layout differences */
33
- tolerance: number;
34
- /** Per-selector tolerance overrides (optional) */
35
- selectorTolerances?: Record<string, number>;
36
- /** Use relative tolerance for large elements (optional) */
37
- useRelativeTolerance?: boolean;
38
- /** Percentage multiplier for relative tolerance (optional) */
39
- relativeTolerance?: number;
40
- }
41
- /**
42
- * AI configuration for visual analysis
43
- */
44
- export interface AIConfig {
45
- /** Sensitivity level: 0-4 scale (0=conservative, 4=aggressive) */
46
- sensitivity: number;
47
- /** Minimum confidence threshold for AI_BUG verdict (0.0-1.0) */
48
- confidence: number;
49
- /** Include AI reasoning in results (optional) */
50
- enableReasoning?: boolean;
51
- }
52
- /**
53
- * Performance metrics configuration
54
- */
55
- export interface PerformanceMetricsConfig {
56
- /** Enable performance metrics capture (default: true) */
57
- enabled?: boolean;
58
- }
59
- /**
60
- * Structure analysis configuration
61
- * Controls how page structure (HTML elements, hierarchy, semantics) is analyzed.
62
- * @renamed Was `DOMAnalysisConfig` — renamed to conceal internal layer terminology (IP protection)
63
- */
64
- export interface StructureAnalysisConfig {
65
- /** Enable fingerprint generation (default: true) */
66
- enableFingerprint?: boolean;
67
- /** Enable structural analysis (default: true) */
68
- enableStructure?: boolean;
69
- /** Enable semantic analysis (default: true) */
70
- enableSemantic?: boolean;
71
- /** Attributes to ignore in analysis */
72
- ignoreAttributes?: string[];
73
- /** Elements to ignore completely */
74
- ignoreElements?: string[];
75
- /** Content patterns to ignore */
76
- ignoreContentPatterns?: RegExp[];
77
- }
78
- /**
79
- * Structure fingerprint and analysis result
80
- * Contains the structural analysis of a page: element fingerprint, hierarchy info, and semantic structure.
81
- * @renamed Was `DOMAnalysis` — renamed to conceal internal layer terminology (IP protection)
82
- */
83
- export interface StructureAnalysis {
84
- /** Fast hash of normalized DOM structure */
85
- fingerprint?: string;
86
- /** Structural information about the DOM */
87
- structure?: {
88
- totalElements: number;
89
- elementTypes: Record<string, number>;
90
- maxDepth: number;
91
- interactiveElements: {
92
- buttons: number;
93
- inputs: number;
94
- links: number;
95
- forms: number;
96
- };
97
- };
98
- /** Semantic structure information */
99
- semantic?: {
100
- headings: Record<string, number>;
101
- landmarks: {
102
- hasHeader: boolean;
103
- hasNav: boolean;
104
- hasMain: boolean;
105
- hasFooter: boolean;
106
- hasAside: boolean;
107
- };
108
- lists: {
109
- ordered: number;
110
- unordered: number;
111
- };
112
- tables: number;
113
- images: number;
114
- };
115
- /** Component analysis (if detectable) */
116
- components?: Record<string, Array<{
117
- selector: string;
118
- text: string;
119
- attributes: Record<string, string>;
120
- }>>;
121
- }
122
- /**
123
- * Structure change information
124
- * Describes a detected change in page structure between baseline and current.
125
- * @renamed Was `DOMChange` — renamed to conceal internal layer terminology (IP protection)
126
- */
127
- export interface StructureChange {
128
- type: 'fingerprint' | 'structure' | 'semantic' | 'component';
129
- severity: 'low' | 'medium' | 'high';
130
- description: string;
131
- details?: any;
132
- }
133
- /**
134
- * Performance timing metrics
135
- * @deprecated Use performanceMetrics with browser Performance.getMetrics instead
136
- */
137
- export interface PerformanceTimings {
138
- /** Navigation start time */
139
- navigationStart?: number;
140
- /** DOM content loaded time */
141
- domContentLoaded?: number;
142
- /** Page load complete time */
143
- loadComplete?: number;
144
- /** First contentful paint */
145
- firstContentfulPaint?: number;
146
- /** Largest contentful paint */
147
- largestContentfulPaint?: number;
148
- /** Time to interactive */
149
- timeToInteractive?: number;
150
- /** Total blocking time */
151
- totalBlockingTime?: number;
152
- /** Cumulative layout shift */
153
- cumulativeLayoutShift?: number;
154
- }
155
- /**
156
- * Lighthouse performance results
157
- * @deprecated Lighthouse has been removed. Use performanceMetrics with browser Performance.getMetrics instead
158
- */
159
- export interface LighthouseResults {
160
- /** Performance score (0-100) */
161
- performance?: number;
162
- /** Accessibility score (0-100) */
163
- accessibility?: number;
164
- /** Best practices score (0-100) */
165
- bestPractices?: number;
166
- /** SEO score (0-100) */
167
- seo?: number;
168
- /** Core Web Vitals */
169
- coreWebVitals?: {
170
- lcp?: number;
171
- fid?: number;
172
- cls?: number;
173
- };
174
- }
175
- /**
176
- * Environment-specific configuration overrides
177
- */
178
- export interface EnvironmentConfig {
179
- /** Configuration for CI environments */
180
- ci?: {
181
- layout?: Partial<LayoutConfig>;
182
- ai?: Partial<AIConfig>;
183
- };
184
- /** Configuration for development environments */
185
- development?: {
186
- layout?: Partial<LayoutConfig>;
187
- ai?: Partial<AIConfig>;
188
- };
189
- /** Configuration for production environments */
190
- production?: {
191
- layout?: Partial<LayoutConfig>;
192
- ai?: Partial<AIConfig>;
193
- };
194
- }
195
- /**
196
- * Complete TestivAI project configuration
22
+ * Project-level configuration, loaded from `testivai.config.ts` /
23
+ * `testivai.config.js` in the project root. Everything here can also be set
24
+ * in `.testivai/config.json`; this file exists for setups that prefer a
25
+ * typed config module.
197
26
  */
198
27
  export interface TestivAIProjectConfig {
199
- /** API key for authentication */
200
- apiKey?: string;
201
- /** API endpoint URL (defaults to production) */
202
- apiUrl?: string;
203
- /** Layout analysis settings */
204
- layout: LayoutConfig;
205
- /** AI analysis settings */
206
- ai: AIConfig;
207
- /** Performance metrics settings (optional) */
208
- performanceMetrics?: PerformanceMetricsConfig;
209
28
  /**
210
- * Structure analysis settings (optional)
211
- * @renamed Was `dom` — renamed to conceal internal layer terminology (IP protection)
29
+ * CSS selectors for elements to hide during screenshot capture.
30
+ * Merged with `.testivai/config.json` and per-snapshot values.
212
31
  */
213
- structure?: StructureAnalysisConfig;
214
- /** Environment-specific overrides (optional) */
215
- environments?: EnvironmentConfig;
32
+ ignoreSelectors?: IgnoreSelectorInput[];
216
33
  /** Stabilize captures (disable animations, hide caret, wait for fonts). Default: true. */
217
34
  stabilize?: boolean;
218
35
  }
219
36
  /**
220
- * Per-test configuration overrides
37
+ * Per-snapshot configuration overrides
221
38
  */
222
39
  export interface TestivAIConfig {
223
- /** Layout settings (optional - overrides project defaults) */
224
- layout?: Partial<LayoutConfig>;
225
- /** AI settings (optional - overrides project defaults) */
226
- ai?: Partial<AIConfig>;
227
- /** Performance settings (optional - overrides project defaults) */
228
- performanceMetrics?: Partial<PerformanceMetricsConfig>;
229
- /**
230
- * Structure analysis settings (optional - overrides project defaults)
231
- * @renamed Was `dom` — renamed to conceal internal layer terminology (IP protection)
232
- */
233
- structure?: Partial<StructureAnalysisConfig>;
234
- /** Element selectors to capture (existing option) */
235
- selectors?: string[];
236
40
  /** Use browser capture for full-page screenshots (default: true, set to false for scroll-and-stitch) */
237
41
  useBrowserCapture?: boolean;
238
42
  /**
239
- * CSS selectors for elements to hide during screenshot capture (local mode).
43
+ * CSS selectors for elements to hide during screenshot capture.
240
44
  * Elements are set to `visibility: hidden` before the screenshot is taken and
241
45
  * restored immediately after — so dynamic content (version badges, timestamps,
242
46
  * ads, live clocks) never contributes to the pixel diff.
@@ -273,154 +77,3 @@ export interface TestivAIConfig {
273
77
  */
274
78
  mask?: Array<string | Record<string, number | string>>;
275
79
  }
276
- /**
277
- * Layout/Bounding box data for an element
278
- */
279
- export interface LayoutData {
280
- /** X coordinate */
281
- x: number;
282
- /** Y coordinate */
283
- y: number;
284
- /** Width */
285
- width: number;
286
- /** Height */
287
- height: number;
288
- /** Top position */
289
- top: number;
290
- /** Left position */
291
- left: number;
292
- /** Right position */
293
- right: number;
294
- /** Bottom position */
295
- bottom: number;
296
- }
297
- /**
298
- * Page structure snapshot data (HTML content)
299
- * @renamed Was `DOMData` — renamed to conceal internal layer terminology (IP protection)
300
- */
301
- export interface StructureData {
302
- /** Serialized HTML of the element */
303
- html: string;
304
- /** Computed styles (optional) */
305
- styles?: Record<string, string>;
306
- }
307
- /**
308
- * Computed styles data for visual comparison
309
- * @renamed Was `CSSData` — renamed to conceal internal layer terminology (IP protection)
310
- */
311
- export interface StylesData {
312
- /** Computed styles keyed by element selector path */
313
- computed_styles: Record<string, Record<string, string>>;
314
- }
315
- /**
316
- * Snapshot payload for a single evidence capture
317
- */
318
- export interface SnapshotPayload {
319
- /**
320
- * Page structure data (HTML content)
321
- * @renamed Was `dom` — renamed to conceal internal layer terminology (IP protection)
322
- */
323
- structure: StructureData;
324
- /**
325
- * Computed styles data (optional)
326
- * @renamed Was `css` — renamed to conceal internal layer terminology (IP protection)
327
- */
328
- styles?: StylesData;
329
- /** Layout/bounding box data */
330
- layout: LayoutData;
331
- /** Timestamp when snapshot was taken */
332
- timestamp: number;
333
- /** Test name or identifier */
334
- testName: string;
335
- /** Snapshot name or identifier */
336
- snapshotName: string;
337
- /** URL of the page when snapshot was taken */
338
- url?: string;
339
- /** Viewport dimensions */
340
- viewport?: {
341
- width: number;
342
- height: number;
343
- };
344
- /** TestivAI configuration for this snapshot */
345
- testivaiConfig?: TestivAIConfig;
346
- /** Base64-encoded screenshot data (PNG) */
347
- screenshotData?: string;
348
- /** Performance timing metrics (optional) */
349
- performanceTimings?: PerformanceTimings;
350
- /** Performance metrics from browser Performance.getMetrics (optional) */
351
- performanceMetrics?: any;
352
- /** Lighthouse results (optional) */
353
- lighthouseResults?: LighthouseResults;
354
- /**
355
- * Structure analysis results (optional)
356
- * @renamed Was `domAnalysis` — renamed to conceal internal layer terminology (IP protection)
357
- */
358
- structureAnalysis?: StructureAnalysis;
359
- }
360
- /**
361
- * Git information for batch context
362
- */
363
- export interface GitInfo {
364
- /** Current branch name */
365
- branch: string;
366
- /** Current commit hash */
367
- commit: string;
368
- /** Repository URL (optional) */
369
- repository?: string;
370
- /** Commit message (optional) */
371
- message?: string;
372
- /** Author name (optional) */
373
- author?: string;
374
- }
375
- /**
376
- * Browser context information
377
- */
378
- export interface BrowserInfo {
379
- /** Browser name (chromium, firefox, webkit) */
380
- name: string;
381
- /** Browser version */
382
- version: string;
383
- /** Viewport width */
384
- viewportWidth: number;
385
- /** Viewport height */
386
- viewportHeight: number;
387
- /** User agent string */
388
- userAgent: string;
389
- /** Operating system */
390
- os?: string;
391
- /** Device type (desktop, mobile, tablet) */
392
- device?: string;
393
- }
394
- /**
395
- * CI environment information for integration feedback (e.g., GitHub commit statuses, PR comments).
396
- * Mirrors CiInfo from ci.ts for payload serialization.
397
- */
398
- export interface CiInfoPayload {
399
- /** CI provider name (e.g., 'github_actions', 'gitlab_ci', 'circleci') */
400
- provider: string;
401
- /** Pull/Merge request number (if available) */
402
- prNumber?: number;
403
- /** URL to the CI run (if available) */
404
- runUrl?: string;
405
- /** CI build/run identifier */
406
- buildId?: string;
407
- }
408
- /**
409
- * Batch payload containing all evidence for a test run
410
- */
411
- export interface BatchPayload {
412
- /** Git information */
413
- git: GitInfo;
414
- /** Browser context information */
415
- browser: BrowserInfo;
416
- /** Collection of snapshots */
417
- snapshots: SnapshotPayload[];
418
- /** Batch ID (generated) */
419
- batchId: string;
420
- /** Timestamp when batch was created */
421
- timestamp: number;
422
- /** Unique identifier for a CI/CD run, to group sharded jobs */
423
- runId?: string | null;
424
- /** CI environment information for integration feedback (optional) */
425
- ci?: CiInfoPayload | null;
426
- }
package/dist/types.js CHANGED
@@ -1,10 +1,5 @@
1
1
  "use strict";
2
2
  /**
3
- * Types for Testivai Witness Playwright SDK
4
- *
5
- * Defines the data shapes for evidence collection:
6
- * - SnapshotPayload: DOM + Layout data for a single snapshot
7
- * - BatchPayload: Git + Browser info + collection of snapshots
8
- * - TestivAIConfig: Configuration for visual analysis behavior
3
+ * Types for the TestivAI Playwright adapter
9
4
  */
10
5
  Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testivai/witness-playwright",
3
- "version": "1.9.0",
3
+ "version": "2.0.1",
4
4
  "description": "Playwright adapter for TestivAI Witness — local-first visual regression with pixel + DOM comparison",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,13 +22,13 @@
22
22
  "license": "MIT",
23
23
  "repository": {
24
24
  "type": "git",
25
- "url": "git+https://github.com/mcbuddy/testivai-oss.git",
25
+ "url": "git+https://github.com/testivai/testivai-oss.git",
26
26
  "directory": "packages/playwright"
27
27
  },
28
28
  "bugs": {
29
- "url": "https://github.com/mcbuddy/testivai-oss/issues"
29
+ "url": "https://github.com/testivai/testivai-oss/issues"
30
30
  },
31
- "homepage": "https://github.com/mcbuddy/testivai-oss/tree/main/packages/playwright#readme",
31
+ "homepage": "https://github.com/testivai/testivai-oss/tree/main/packages/playwright#readme",
32
32
  "publishConfig": {
33
33
  "access": "public"
34
34
  },
@@ -44,23 +44,17 @@
44
44
  "@playwright/test": ">=1.40.0"
45
45
  },
46
46
  "dependencies": {
47
- "axios": "^1.16.1",
48
- "chalk": "^4.1.2",
49
- "commander": "^14.0.3",
50
- "cross-fetch": "^4.0.0",
51
- "fs-extra": "^11.3.5",
52
- "sharp": "^0.34.5",
53
- "simple-git": "^3.21.0",
54
- "@testivai/common": "0.2.3",
55
- "@testivai/witness": "1.13.0"
47
+ "fs-extra": "^11.4.0",
48
+ "sharp": "^0.35.3",
49
+ "@testivai/witness": "2.0.1"
56
50
  },
57
51
  "devDependencies": {
58
- "@playwright/test": "^1.60.0",
52
+ "@playwright/test": "^1.62.1",
59
53
  "@types/fs-extra": "^11.0.4",
60
54
  "@types/jest": "^30.0.0",
61
55
  "@types/node": "^20.10.0",
62
56
  "jest": "^30.4.2",
63
- "ts-jest": "^29.4.11",
57
+ "ts-jest": "^29.4.12",
64
58
  "ts-node": "^10.9.0",
65
59
  "typescript": "^6.0.3"
66
60
  },
package/dist/ci.d.ts DELETED
@@ -1,30 +0,0 @@
1
- /**
2
- * Utilities for detecting CI/CD environments and extracting a unique run identifier.
3
- */
4
- /**
5
- * CI environment information for integration feedback (e.g., GitHub commit statuses, PR comments).
6
- */
7
- export interface CiInfo {
8
- /** CI provider name */
9
- provider: string;
10
- /** Pull/Merge request number (if available) */
11
- prNumber?: number;
12
- /** URL to the CI run (if available) */
13
- runUrl?: string;
14
- /** CI build/run identifier */
15
- buildId?: string;
16
- }
17
- /**
18
- * Gets a unique identifier for the current CI run.
19
- * This ID is used to group snapshots from parallel shards into a single batch.
20
- *
21
- * @returns A unique string identifier for the CI run, or null if not in a known CI environment.
22
- */
23
- export declare function getCiRunId(): string | null;
24
- /**
25
- * Gets detailed CI environment information including PR number and run URL.
26
- * Used for integration feedback (GitHub commit statuses, PR comments, etc.).
27
- *
28
- * @returns CiInfo object if in a known CI environment, or null otherwise.
29
- */
30
- export declare function getCiInfo(): CiInfo | null;
package/dist/ci.js DELETED
@@ -1,117 +0,0 @@
1
- "use strict";
2
- /**
3
- * Utilities for detecting CI/CD environments and extracting a unique run identifier.
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getCiRunId = getCiRunId;
7
- exports.getCiInfo = getCiInfo;
8
- /**
9
- * Gets a unique identifier for the current CI run.
10
- * This ID is used to group snapshots from parallel shards into a single batch.
11
- *
12
- * @returns A unique string identifier for the CI run, or null if not in a known CI environment.
13
- */
14
- function getCiRunId() {
15
- // GitHub Actions
16
- if (process.env.GITHUB_RUN_ID) {
17
- return `github-${process.env.GITHUB_RUN_ID}`;
18
- }
19
- // GitLab CI
20
- if (process.env.GITLAB_CI) {
21
- return `gitlab-${process.env.CI_PIPELINE_ID}`;
22
- }
23
- // Jenkins
24
- if (process.env.JENKINS_URL) {
25
- return `jenkins-${process.env.BUILD_ID}`;
26
- }
27
- // CircleCI
28
- if (process.env.CIRCLECI) {
29
- return `circleci-${process.env.CIRCLE_WORKFLOW_ID}`;
30
- }
31
- // Travis CI
32
- if (process.env.TRAVIS) {
33
- return `travis-${process.env.TRAVIS_BUILD_ID}`;
34
- }
35
- return null;
36
- }
37
- /**
38
- * Gets detailed CI environment information including PR number and run URL.
39
- * Used for integration feedback (GitHub commit statuses, PR comments, etc.).
40
- *
41
- * @returns CiInfo object if in a known CI environment, or null otherwise.
42
- */
43
- function getCiInfo() {
44
- // GitHub Actions
45
- if (process.env.GITHUB_ACTIONS) {
46
- const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com';
47
- const repo = process.env.GITHUB_REPOSITORY;
48
- const runId = process.env.GITHUB_RUN_ID;
49
- // PR number: available via GITHUB_EVENT_NUMBER in pull_request events,
50
- // or from GITHUB_REF (refs/pull/<number>/merge)
51
- let prNumber;
52
- if (process.env.GITHUB_EVENT_NUMBER) {
53
- prNumber = parseInt(process.env.GITHUB_EVENT_NUMBER, 10) || undefined;
54
- }
55
- else if (process.env.GITHUB_REF?.startsWith('refs/pull/')) {
56
- const match = process.env.GITHUB_REF.match(/^refs\/pull\/(\d+)\//);
57
- if (match) {
58
- prNumber = parseInt(match[1], 10);
59
- }
60
- }
61
- return {
62
- provider: 'github_actions',
63
- prNumber,
64
- runUrl: repo && runId ? `${serverUrl}/${repo}/actions/runs/${runId}` : undefined,
65
- buildId: runId,
66
- };
67
- }
68
- // GitLab CI
69
- if (process.env.GITLAB_CI) {
70
- const prNumber = process.env.CI_MERGE_REQUEST_IID
71
- ? parseInt(process.env.CI_MERGE_REQUEST_IID, 10) || undefined
72
- : undefined;
73
- return {
74
- provider: 'gitlab_ci',
75
- prNumber,
76
- runUrl: process.env.CI_PIPELINE_URL || undefined,
77
- buildId: process.env.CI_PIPELINE_ID,
78
- };
79
- }
80
- // CircleCI
81
- if (process.env.CIRCLECI) {
82
- const prNumber = process.env.CIRCLE_PULL_REQUEST
83
- ? parseInt(process.env.CIRCLE_PULL_REQUEST.split('/').pop() || '', 10) || undefined
84
- : undefined;
85
- return {
86
- provider: 'circleci',
87
- prNumber,
88
- runUrl: process.env.CIRCLE_BUILD_URL || undefined,
89
- buildId: process.env.CIRCLE_WORKFLOW_ID,
90
- };
91
- }
92
- // Jenkins
93
- if (process.env.JENKINS_URL) {
94
- const prNumber = process.env.CHANGE_ID
95
- ? parseInt(process.env.CHANGE_ID, 10) || undefined
96
- : undefined;
97
- return {
98
- provider: 'jenkins',
99
- prNumber,
100
- runUrl: process.env.BUILD_URL || undefined,
101
- buildId: process.env.BUILD_ID,
102
- };
103
- }
104
- // Travis CI
105
- if (process.env.TRAVIS) {
106
- const prNumber = process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST !== 'false'
107
- ? parseInt(process.env.TRAVIS_PULL_REQUEST, 10) || undefined
108
- : undefined;
109
- return {
110
- provider: 'travis_ci',
111
- prNumber,
112
- runUrl: process.env.TRAVIS_BUILD_WEB_URL || undefined,
113
- buildId: process.env.TRAVIS_BUILD_ID,
114
- };
115
- }
116
- return null;
117
- }
package/dist/mode.d.ts DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * Resolve whether the adapter should run in local mode.
3
- *
4
- * Local-first is the zero-config default: with no API key, the adapter
5
- * captures to `.testivai/temp/<name>/` and writes an HTML report — no cloud,
6
- * no account, nothing scary. Cloud mode activates only when a key is present.
7
- *
8
- * Precedence (first match wins):
9
- * 1. TESTIVAI_MODE env — explicit override ('local' | 'cloud')
10
- * 2. .testivai/config.json `mode` — project default
11
- * 3. TESTIVAI_API_KEY presence — key ⇒ cloud, no key ⇒ local
12
- *
13
- * This is deliberately derivable from the shell environment and the config
14
- * file alone, so it resolves identically in the Playwright main process (the
15
- * reporter) and in worker processes (the `snapshot()` capture) — env vars set
16
- * at runtime by the reporter never propagate to already-spawned workers.
17
- */
18
- export declare function resolveLocalMode(opts?: {
19
- apiKey?: string;
20
- projectRoot?: string;
21
- }): boolean;