@seybel/breakhound 0.0.0-stage → 1.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.
@@ -0,0 +1,530 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "$schema": {
6
+ "type": "string",
7
+ "description": "The JSON Schema this file follows."
8
+ },
9
+ "baseUrl": {
10
+ "type": "string",
11
+ "description": "Where your app is running, e.g. http://localhost:3000."
12
+ },
13
+ "routes": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "string"
17
+ },
18
+ "description": "Pages to scan: paths (joined to baseUrl) or full URLs. Leave it out to find every route automatically."
19
+ },
20
+ "include": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "string"
24
+ },
25
+ "description": "Only scan routes matching these globs, e.g. ['/blog/**']. `*` is one segment, `**` any number."
26
+ },
27
+ "exclude": {
28
+ "type": "array",
29
+ "items": {
30
+ "type": "string"
31
+ },
32
+ "description": "Skip routes matching these globs, e.g. ['/admin/**']."
33
+ },
34
+ "samples": {
35
+ "type": "object",
36
+ "additionalProperties": {
37
+ "type": "string"
38
+ },
39
+ "description": "A real URL for each dynamic route, e.g. { '/products/[id]': '/products/42' }."
40
+ },
41
+ "maxRoutes": {
42
+ "type": "number",
43
+ "description": "Most routes to scan in one run (default 100)."
44
+ },
45
+ "server": {
46
+ "type": "object",
47
+ "properties": {
48
+ "command": {
49
+ "type": "string",
50
+ "description": "Command that starts the app, e.g. \"npm run dev -- --port 4000\"."
51
+ },
52
+ "port": {
53
+ "type": "number",
54
+ "description": "Port to wait on, when the command doesn't print its URL."
55
+ },
56
+ "timeout": {
57
+ "type": "number",
58
+ "description": "Seconds to wait for the server to answer (default 120)."
59
+ }
60
+ },
61
+ "additionalProperties": false,
62
+ "description": "How to start the app when it isn't running, if not with its \"dev\" script."
63
+ },
64
+ "widths": {
65
+ "type": "object",
66
+ "properties": {
67
+ "min": {
68
+ "type": "number",
69
+ "description": "Narrowest width (default 320)."
70
+ },
71
+ "max": {
72
+ "type": "number",
73
+ "description": "Widest width (default 1920)."
74
+ },
75
+ "step": {
76
+ "type": "number",
77
+ "description": "Step of the first, coarse sweep before narrowing down (default 16)."
78
+ }
79
+ },
80
+ "additionalProperties": false,
81
+ "description": "Viewport widths to sweep, in CSS pixels."
82
+ },
83
+ "detectors": {
84
+ "type": "object",
85
+ "properties": {
86
+ "page-overflow": {
87
+ "anyOf": [
88
+ {
89
+ "type": "boolean"
90
+ },
91
+ {
92
+ "type": "string",
93
+ "const": "error"
94
+ },
95
+ {
96
+ "type": "string",
97
+ "const": "warning"
98
+ },
99
+ {
100
+ "type": "string",
101
+ "const": "info"
102
+ }
103
+ ]
104
+ },
105
+ "content-overflow": {
106
+ "anyOf": [
107
+ {
108
+ "type": "boolean"
109
+ },
110
+ {
111
+ "type": "string",
112
+ "const": "error"
113
+ },
114
+ {
115
+ "type": "string",
116
+ "const": "warning"
117
+ },
118
+ {
119
+ "type": "string",
120
+ "const": "info"
121
+ }
122
+ ]
123
+ },
124
+ "media-overflow": {
125
+ "anyOf": [
126
+ {
127
+ "type": "boolean"
128
+ },
129
+ {
130
+ "type": "string",
131
+ "const": "error"
132
+ },
133
+ {
134
+ "type": "string",
135
+ "const": "warning"
136
+ },
137
+ {
138
+ "type": "string",
139
+ "const": "info"
140
+ }
141
+ ]
142
+ },
143
+ "overlap": {
144
+ "anyOf": [
145
+ {
146
+ "type": "boolean"
147
+ },
148
+ {
149
+ "type": "string",
150
+ "const": "error"
151
+ },
152
+ {
153
+ "type": "string",
154
+ "const": "warning"
155
+ },
156
+ {
157
+ "type": "string",
158
+ "const": "info"
159
+ }
160
+ ]
161
+ },
162
+ "unexpected-wrap": {
163
+ "anyOf": [
164
+ {
165
+ "type": "boolean"
166
+ },
167
+ {
168
+ "type": "string",
169
+ "const": "error"
170
+ },
171
+ {
172
+ "type": "string",
173
+ "const": "warning"
174
+ },
175
+ {
176
+ "type": "string",
177
+ "const": "info"
178
+ }
179
+ ]
180
+ },
181
+ "clipped-text": {
182
+ "anyOf": [
183
+ {
184
+ "type": "boolean"
185
+ },
186
+ {
187
+ "type": "string",
188
+ "const": "error"
189
+ },
190
+ {
191
+ "type": "string",
192
+ "const": "warning"
193
+ },
194
+ {
195
+ "type": "string",
196
+ "const": "info"
197
+ }
198
+ ]
199
+ },
200
+ "squished-text": {
201
+ "anyOf": [
202
+ {
203
+ "type": "boolean"
204
+ },
205
+ {
206
+ "type": "string",
207
+ "const": "error"
208
+ },
209
+ {
210
+ "type": "string",
211
+ "const": "warning"
212
+ },
213
+ {
214
+ "type": "string",
215
+ "const": "info"
216
+ }
217
+ ]
218
+ },
219
+ "distorted-media": {
220
+ "anyOf": [
221
+ {
222
+ "type": "boolean"
223
+ },
224
+ {
225
+ "type": "string",
226
+ "const": "error"
227
+ },
228
+ {
229
+ "type": "string",
230
+ "const": "warning"
231
+ },
232
+ {
233
+ "type": "string",
234
+ "const": "info"
235
+ }
236
+ ]
237
+ },
238
+ "small-tap-target": {
239
+ "anyOf": [
240
+ {
241
+ "type": "boolean"
242
+ },
243
+ {
244
+ "type": "string",
245
+ "const": "error"
246
+ },
247
+ {
248
+ "type": "string",
249
+ "const": "warning"
250
+ },
251
+ {
252
+ "type": "string",
253
+ "const": "info"
254
+ }
255
+ ]
256
+ },
257
+ "tiny-text": {
258
+ "anyOf": [
259
+ {
260
+ "type": "boolean"
261
+ },
262
+ {
263
+ "type": "string",
264
+ "const": "error"
265
+ },
266
+ {
267
+ "type": "string",
268
+ "const": "warning"
269
+ },
270
+ {
271
+ "type": "string",
272
+ "const": "info"
273
+ }
274
+ ]
275
+ },
276
+ "oversized-text": {
277
+ "anyOf": [
278
+ {
279
+ "type": "boolean"
280
+ },
281
+ {
282
+ "type": "string",
283
+ "const": "error"
284
+ },
285
+ {
286
+ "type": "string",
287
+ "const": "warning"
288
+ },
289
+ {
290
+ "type": "string",
291
+ "const": "info"
292
+ }
293
+ ]
294
+ },
295
+ "edge-gutter": {
296
+ "anyOf": [
297
+ {
298
+ "type": "boolean"
299
+ },
300
+ {
301
+ "type": "string",
302
+ "const": "error"
303
+ },
304
+ {
305
+ "type": "string",
306
+ "const": "warning"
307
+ },
308
+ {
309
+ "type": "string",
310
+ "const": "info"
311
+ }
312
+ ]
313
+ },
314
+ "viewport-meta": {
315
+ "anyOf": [
316
+ {
317
+ "type": "boolean"
318
+ },
319
+ {
320
+ "type": "string",
321
+ "const": "error"
322
+ },
323
+ {
324
+ "type": "string",
325
+ "const": "warning"
326
+ },
327
+ {
328
+ "type": "string",
329
+ "const": "info"
330
+ }
331
+ ]
332
+ },
333
+ "vision": {
334
+ "anyOf": [
335
+ {
336
+ "type": "boolean"
337
+ },
338
+ {
339
+ "type": "string",
340
+ "const": "error"
341
+ },
342
+ {
343
+ "type": "string",
344
+ "const": "warning"
345
+ },
346
+ {
347
+ "type": "string",
348
+ "const": "info"
349
+ }
350
+ ]
351
+ }
352
+ },
353
+ "additionalProperties": false,
354
+ "description": "Turn a check off with `false`, or change how serious it is."
355
+ },
356
+ "ignore": {
357
+ "type": "array",
358
+ "items": {
359
+ "anyOf": [
360
+ {
361
+ "type": "string"
362
+ },
363
+ {
364
+ "type": "object",
365
+ "properties": {
366
+ "selector": {
367
+ "type": "string",
368
+ "description": "CSS selector; matching elements and everything inside them are ignored."
369
+ },
370
+ "detectors": {
371
+ "type": "array",
372
+ "items": {
373
+ "type": "string",
374
+ "enum": [
375
+ "page-overflow",
376
+ "content-overflow",
377
+ "media-overflow",
378
+ "overlap",
379
+ "unexpected-wrap",
380
+ "clipped-text",
381
+ "squished-text",
382
+ "distorted-media",
383
+ "small-tap-target",
384
+ "tiny-text",
385
+ "oversized-text",
386
+ "edge-gutter",
387
+ "viewport-meta",
388
+ "vision"
389
+ ]
390
+ },
391
+ "description": "Limit the rule to these detectors. Omit to ignore every detector."
392
+ }
393
+ },
394
+ "required": [
395
+ "selector"
396
+ ],
397
+ "additionalProperties": false
398
+ }
399
+ ]
400
+ },
401
+ "description": "Elements to leave out: a CSS selector, or a selector limited to some checks."
402
+ },
403
+ "failOn": {
404
+ "type": "string",
405
+ "enum": [
406
+ "error",
407
+ "warning",
408
+ "info",
409
+ "none"
410
+ ],
411
+ "description": "Exit with code 1 when an issue at this level (or worse) is found."
412
+ },
413
+ "outDir": {
414
+ "type": "string",
415
+ "description": "Where reports are written."
416
+ },
417
+ "screenshots": {
418
+ "type": "boolean",
419
+ "description": "Take a screenshot of every issue."
420
+ },
421
+ "states": {
422
+ "type": [
423
+ "boolean",
424
+ "number"
425
+ ],
426
+ "description": "Also open menus, dialogs and expandable sections (the mobile menu, a modal, an FAQ) and scan them open. A number sets the most to open on one page (default 5); false turns it off."
427
+ },
428
+ "pdf": {
429
+ "type": "boolean",
430
+ "description": "Also write report.pdf."
431
+ },
432
+ "browsers": {
433
+ "type": "array",
434
+ "items": {
435
+ "type": "string",
436
+ "enum": [
437
+ "chromium",
438
+ "webkit",
439
+ "firefox"
440
+ ]
441
+ },
442
+ "description": "Browser engines to scan in: chromium, webkit (Safari's engine) and firefox. The first finds the routes; the others check the same pages after it, one at a time. Default [\"chromium\"]."
443
+ },
444
+ "vision": {
445
+ "anyOf": [
446
+ {
447
+ "type": "boolean"
448
+ },
449
+ {
450
+ "type": "object",
451
+ "properties": {
452
+ "provider": {
453
+ "type": "string",
454
+ "enum": [
455
+ "anthropic",
456
+ "openai",
457
+ "ollama"
458
+ ]
459
+ },
460
+ "model": {
461
+ "type": "string"
462
+ },
463
+ "widths": {
464
+ "type": "array",
465
+ "items": {
466
+ "type": "number"
467
+ }
468
+ }
469
+ },
470
+ "additionalProperties": false
471
+ }
472
+ ],
473
+ "description": "Also show screenshots of each page at 375, 768 and 1280px to your own vision model (the one `fix` uses, or set one here) and report what it says looks off, as info. Off by default."
474
+ },
475
+ "fix": {
476
+ "type": "object",
477
+ "properties": {
478
+ "provider": {
479
+ "type": "string",
480
+ "enum": [
481
+ "anthropic",
482
+ "openai",
483
+ "ollama"
484
+ ],
485
+ "description": "anthropic, openai (or any compatible API) or ollama. Picked from your environment when left out."
486
+ },
487
+ "model": {
488
+ "type": "string"
489
+ }
490
+ },
491
+ "additionalProperties": false,
492
+ "description": "The model `breakhound fix` uses; flags and environment variables work too."
493
+ },
494
+ "concurrency": {
495
+ "type": "number",
496
+ "description": "Browser tabs to use at once (default: half your CPU cores, up to 4)."
497
+ },
498
+ "memoryLimit": {
499
+ "anyOf": [
500
+ {
501
+ "type": "string"
502
+ },
503
+ {
504
+ "type": "boolean",
505
+ "const": false
506
+ }
507
+ ],
508
+ "description": "Most memory the dev server and browser breakhound starts may use together before it shuts them down, so a big app can't freeze your computer: a size like \"6GB\", a share like \"50%\", or \"off\". Default 60% of your memory, leaving at least 2 GB free."
509
+ },
510
+ "settle": {
511
+ "type": "object",
512
+ "properties": {
513
+ "networkIdleMs": {
514
+ "type": "number",
515
+ "description": "Most milliseconds to wait for the network to go quiet after load (default 5000)."
516
+ },
517
+ "maxSettleMs": {
518
+ "type": "number",
519
+ "description": "Most milliseconds to wait for the layout to stop moving after a resize (default 1000)."
520
+ }
521
+ },
522
+ "additionalProperties": false,
523
+ "description": "How long to wait for the page to settle."
524
+ }
525
+ },
526
+ "additionalProperties": false,
527
+ "description": "The config file's shape. Everything is optional: with no config at all, breakhound finds the app, its routes and its dev server by itself.",
528
+ "definitions": {},
529
+ "title": "breakhound config"
530
+ }